@koda-sl/baker-cli 0.410.0 → 0.412.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 +33 -0
- package/dist/{chunk-KTMFHBN6.js → chunk-4Q7EDLEC.js} +3 -3
- package/dist/{chunk-ISCXDKWB.js → chunk-ASON7WRD.js} +9 -1
- package/dist/{chunk-ISCXDKWB.js.map → chunk-ASON7WRD.js.map} +1 -1
- package/dist/{chunk-ISJOVAJP.js → chunk-EXFQDO6T.js} +2 -2
- package/dist/{chunk-S5BY45H7.js → chunk-FLERTMEW.js} +3 -3
- package/dist/{chunk-VKWHVMMD.js → chunk-G7YB37RQ.js} +3 -3
- package/dist/{chunk-ZIOW64BL.js → chunk-PLH5K6RI.js} +4 -4
- package/dist/cli.js +979 -551
- package/dist/cli.js.map +1 -1
- package/dist/{client-AY6TPFQ4.js → client-22ED7NUR.js} +4 -4
- package/dist/engine/index.js +3 -3
- package/dist/{env-CWEGTJF3.js → env-E565GJBV.js} +2 -2
- package/dist/{output-EPF3HHJ4.js → output-F6NKGZ6E.js} +5 -5
- package/dist/{shared-53G34I3U.js → shared-YSUGIUS4.js} +6 -6
- package/package.json +1 -1
- /package/dist/{chunk-KTMFHBN6.js.map → chunk-4Q7EDLEC.js.map} +0 -0
- /package/dist/{chunk-ISJOVAJP.js.map → chunk-EXFQDO6T.js.map} +0 -0
- /package/dist/{chunk-S5BY45H7.js.map → chunk-FLERTMEW.js.map} +0 -0
- /package/dist/{chunk-VKWHVMMD.js.map → chunk-G7YB37RQ.js.map} +0 -0
- /package/dist/{chunk-ZIOW64BL.js.map → chunk-PLH5K6RI.js.map} +0 -0
- /package/dist/{client-AY6TPFQ4.js.map → client-22ED7NUR.js.map} +0 -0
- /package/dist/{env-CWEGTJF3.js.map → env-E565GJBV.js.map} +0 -0
- /package/dist/{output-EPF3HHJ4.js.map → output-F6NKGZ6E.js.map} +0 -0
- /package/dist/{shared-53G34I3U.js.map → shared-YSUGIUS4.js.map} +0 -0
package/dist/cli.js
CHANGED
|
@@ -97,7 +97,7 @@ import {
|
|
|
97
97
|
withoutCastName,
|
|
98
98
|
wordCount,
|
|
99
99
|
ytDlpBlockSignal
|
|
100
|
-
} from "./chunk-
|
|
100
|
+
} from "./chunk-4Q7EDLEC.js";
|
|
101
101
|
import {
|
|
102
102
|
NAME_CONTAINS_ARG,
|
|
103
103
|
csvOrJson,
|
|
@@ -108,7 +108,7 @@ import {
|
|
|
108
108
|
resolveEffectiveStatus,
|
|
109
109
|
statusFilterHints,
|
|
110
110
|
todayIso
|
|
111
|
-
} from "./chunk-
|
|
111
|
+
} from "./chunk-PLH5K6RI.js";
|
|
112
112
|
import {
|
|
113
113
|
buildQueryCacheKey,
|
|
114
114
|
cacheGet,
|
|
@@ -124,19 +124,19 @@ import {
|
|
|
124
124
|
writeAdsJson,
|
|
125
125
|
writeAdsOutput,
|
|
126
126
|
writeJsonEnvelope
|
|
127
|
-
} from "./chunk-
|
|
127
|
+
} from "./chunk-G7YB37RQ.js";
|
|
128
128
|
import {
|
|
129
129
|
ApiError,
|
|
130
130
|
apiGet,
|
|
131
131
|
apiGetWithHeaders,
|
|
132
132
|
apiPost,
|
|
133
133
|
validateConvexId
|
|
134
|
-
} from "./chunk-
|
|
134
|
+
} from "./chunk-FLERTMEW.js";
|
|
135
135
|
import {
|
|
136
136
|
installExitRecord,
|
|
137
137
|
installStreamTaps,
|
|
138
138
|
logInvocation
|
|
139
|
-
} from "./chunk-
|
|
139
|
+
} from "./chunk-EXFQDO6T.js";
|
|
140
140
|
import {
|
|
141
141
|
__commonJS,
|
|
142
142
|
__esm,
|
|
@@ -171,7 +171,7 @@ import {
|
|
|
171
171
|
winningAdNormalizer,
|
|
172
172
|
writeJson,
|
|
173
173
|
writeOutput
|
|
174
|
-
} from "./chunk-
|
|
174
|
+
} from "./chunk-ASON7WRD.js";
|
|
175
175
|
|
|
176
176
|
// ../../node_modules/.pnpm/i18n-iso-countries@7.14.0/node_modules/i18n-iso-countries/langs/af.json
|
|
177
177
|
var require_af = __commonJS({
|
|
@@ -21715,7 +21715,7 @@ var require_entry_node = __commonJS({
|
|
|
21715
21715
|
});
|
|
21716
21716
|
|
|
21717
21717
|
// src/cli.ts
|
|
21718
|
-
import { defineCommand as
|
|
21718
|
+
import { defineCommand as defineCommand279, runMain } from "citty";
|
|
21719
21719
|
|
|
21720
21720
|
// src/cache-flag.ts
|
|
21721
21721
|
var NO_CACHE_ARG = {
|
|
@@ -23949,20 +23949,20 @@ var conversionUploadRowSchema = z4.strictObject({
|
|
|
23949
23949
|
value: z4.number().nonnegative().optional(),
|
|
23950
23950
|
currency: z4.string().regex(/^[A-Z]{3}$/, "expected a 3-letter currency code, e.g. EUR").optional()
|
|
23951
23951
|
}).refine(
|
|
23952
|
-
(
|
|
23952
|
+
(row2) => Boolean(row2.gclid ?? row2.gbraid ?? row2.wbraid ?? row2.email ?? row2.phone ?? row2.address),
|
|
23953
23953
|
"every conversion needs something to match on: a click id (gclid / gbraid / wbraid), or a customer's email, phone or name+address"
|
|
23954
23954
|
).refine(
|
|
23955
|
-
(
|
|
23955
|
+
(row2) => [row2.gclid, row2.gbraid, row2.wbraid].filter(Boolean).length <= 1,
|
|
23956
23956
|
"pass at most one click id per conversion \u2014 gclid, gbraid and wbraid are three ways of naming the same click"
|
|
23957
23957
|
).refine(
|
|
23958
|
-
(
|
|
23958
|
+
(row2) => row2.value === void 0 || row2.currency !== void 0,
|
|
23959
23959
|
"a conversion with a value needs its currency too"
|
|
23960
|
-
).refine((
|
|
23960
|
+
).refine((row2) => row2.currency === void 0 || row2.value !== void 0, "currency was given with no value");
|
|
23961
23961
|
var conversionUploadSchema = z4.strictObject({
|
|
23962
23962
|
conversionAction: conversionUploadActionSchema,
|
|
23963
23963
|
conversions: z4.array(conversionUploadRowSchema).min(1).max(CONVERSION_UPLOAD_MAX_ROWS)
|
|
23964
23964
|
}).refine((payload) => {
|
|
23965
|
-
const ids2 = payload.conversions.map((
|
|
23965
|
+
const ids2 = payload.conversions.map((row2) => row2.orderId);
|
|
23966
23966
|
return new Set(ids2).size === ids2.length;
|
|
23967
23967
|
}, "two conversions share an order id \u2014 each order id can appear once per upload");
|
|
23968
23968
|
var MS_PER_DAY = 24 * 60 * 60 * 1e3;
|
|
@@ -28952,7 +28952,8 @@ var researchFetchResponseSchema = z27.object({
|
|
|
28952
28952
|
contentChars: z27.number(),
|
|
28953
28953
|
/** The page was longer than one response may carry, so the tail is missing. */
|
|
28954
28954
|
truncated: z27.boolean(),
|
|
28955
|
-
|
|
28955
|
+
/** `reddit` when the URL was a Reddit thread, which Firecrawl refuses and our Reddit reader serves instead. */
|
|
28956
|
+
provider: z27.enum(["firecrawl", "reddit"])
|
|
28956
28957
|
});
|
|
28957
28958
|
var RESEARCH_KEYWORD_METRICS_MAX_KEYWORDS = 700;
|
|
28958
28959
|
var RESEARCH_KEYWORD_METRICS_MAX_KEYWORD_CHARS = 80;
|
|
@@ -28991,6 +28992,81 @@ var researchKeywordMetricsRowSchema = z27.object({
|
|
|
28991
28992
|
var researchKeywordMetricsResponseSchema = z27.object({
|
|
28992
28993
|
data: z27.array(researchKeywordMetricsRowSchema)
|
|
28993
28994
|
});
|
|
28995
|
+
var RESEARCH_REDDIT_SEARCH_MAX_LIMIT = 50;
|
|
28996
|
+
var RESEARCH_REDDIT_MAX_SUBREDDITS = 10;
|
|
28997
|
+
var RESEARCH_REDDIT_THREAD_MAX_COMMENTS = 200;
|
|
28998
|
+
var RESEARCH_REDDIT_THREAD_DEFAULT_COMMENTS = 40;
|
|
28999
|
+
var researchRedditSourceSchema = z27.enum(["reddit_api", "reddit_web", "archive"]);
|
|
29000
|
+
var researchRedditSubredditSchema = z27.string().trim().transform((name) => name.replace(/^\/?r\//i, "")).pipe(z27.string().regex(/^[A-Za-z0-9_]{2,21}$/, "Not a subreddit name"));
|
|
29001
|
+
var researchRedditSearchRequestSchema = z27.object({
|
|
29002
|
+
query: z27.string().trim().min(1).max(256),
|
|
29003
|
+
subreddits: z27.array(researchRedditSubredditSchema).max(RESEARCH_REDDIT_MAX_SUBREDDITS).default([]),
|
|
29004
|
+
/** `comments` searches what people replied, which is where most of the verbatim voice is. */
|
|
29005
|
+
kind: z27.enum(["posts", "comments"]).default("posts"),
|
|
29006
|
+
/** Only things written on or after this day, `YYYY-MM-DD`. */
|
|
29007
|
+
since: z27.string().regex(/^\d{4}-\d{2}-\d{2}$/, "Use YYYY-MM-DD").optional(),
|
|
29008
|
+
limit: z27.coerce.number().int().min(1).max(RESEARCH_REDDIT_SEARCH_MAX_LIMIT).default(25)
|
|
29009
|
+
});
|
|
29010
|
+
var researchRedditThreadRequestSchema = z27.object({
|
|
29011
|
+
/** A thread link in any form Reddit hands out — full, `old.`, `redd.it`, `/s/` share — or a bare post id. */
|
|
29012
|
+
target: z27.string().trim().min(1).max(2048),
|
|
29013
|
+
comments: z27.coerce.number().int().min(0).max(RESEARCH_REDDIT_THREAD_MAX_COMMENTS).default(RESEARCH_REDDIT_THREAD_DEFAULT_COMMENTS)
|
|
29014
|
+
});
|
|
29015
|
+
var researchRedditItemSchema = z27.object({
|
|
29016
|
+
kind: z27.enum(["post", "comment"]),
|
|
29017
|
+
id: z27.string(),
|
|
29018
|
+
postId: z27.string(),
|
|
29019
|
+
subreddit: z27.string(),
|
|
29020
|
+
/** `null` once the account is deleted. */
|
|
29021
|
+
author: z27.string().nullable(),
|
|
29022
|
+
/** The post's title; on a comment, the title of the post it sits under when known. */
|
|
29023
|
+
title: z27.string().nullable(),
|
|
29024
|
+
/** Verbatim: the post's own text (empty for a link post) or the comment's. */
|
|
29025
|
+
text: z27.string(),
|
|
29026
|
+
score: z27.number().nullable(),
|
|
29027
|
+
/** Posts only. */
|
|
29028
|
+
commentCount: z27.number().nullable(),
|
|
29029
|
+
createdAt: z27.string(),
|
|
29030
|
+
permalink: z27.string(),
|
|
29031
|
+
/** Comments inside a thread: 0 answers the post, 1 answers a comment, and so on. */
|
|
29032
|
+
depth: z27.number().nullable()
|
|
29033
|
+
});
|
|
29034
|
+
var researchRedditAttemptSchema = z27.object({
|
|
29035
|
+
source: researchRedditSourceSchema,
|
|
29036
|
+
outcome: z27.enum(["ok", "empty", "not_found", "not_configured", "unsupported", "blocked", "unavailable"])
|
|
29037
|
+
});
|
|
29038
|
+
var researchRedditSearchResponseSchema = z27.object({
|
|
29039
|
+
results: z27.array(researchRedditItemSchema),
|
|
29040
|
+
source: researchRedditSourceSchema,
|
|
29041
|
+
/** Every source asked, in order — an empty answer from one is not the same as none from all. */
|
|
29042
|
+
attempts: z27.array(researchRedditAttemptSchema)
|
|
29043
|
+
});
|
|
29044
|
+
var researchRedditThreadResponseSchema = z27.object({
|
|
29045
|
+
post: researchRedditItemSchema,
|
|
29046
|
+
/** Highest-scoring first, each followed by its best replies. Removed and deleted comments are left out. */
|
|
29047
|
+
comments: z27.array(researchRedditItemSchema),
|
|
29048
|
+
source: researchRedditSourceSchema,
|
|
29049
|
+
attempts: z27.array(researchRedditAttemptSchema)
|
|
29050
|
+
});
|
|
29051
|
+
var RESEARCH_REDDIT_SUBREDDITS_MAX_LIMIT = 25;
|
|
29052
|
+
var researchRedditSubredditsRequestSchema = z27.object({
|
|
29053
|
+
query: z27.string().trim().min(2).max(100),
|
|
29054
|
+
limit: z27.coerce.number().int().min(1).max(RESEARCH_REDDIT_SUBREDDITS_MAX_LIMIT).default(10)
|
|
29055
|
+
});
|
|
29056
|
+
var researchRedditSubredditSummarySchema = z27.object({
|
|
29057
|
+
name: z27.string(),
|
|
29058
|
+
/** Members; `null` when the source does not say. Size, not activity — a big subreddit can be quiet. */
|
|
29059
|
+
subscribers: z27.number().nullable(),
|
|
29060
|
+
/** `restricted`: anyone reads, only approved members post. `private`: nothing can be read. */
|
|
29061
|
+
access: z27.enum(["public", "restricted", "private", "other"]).nullable(),
|
|
29062
|
+
description: z27.string(),
|
|
29063
|
+
url: z27.string()
|
|
29064
|
+
});
|
|
29065
|
+
var researchRedditSubredditsResponseSchema = z27.object({
|
|
29066
|
+
results: z27.array(researchRedditSubredditSummarySchema),
|
|
29067
|
+
source: researchRedditSourceSchema,
|
|
29068
|
+
attempts: z27.array(researchRedditAttemptSchema)
|
|
29069
|
+
});
|
|
28994
29070
|
|
|
28995
29071
|
// ../api/src/scheduledAgentRules.ts
|
|
28996
29072
|
import { z as z28 } from "zod";
|
|
@@ -30313,7 +30389,11 @@ var videoAnalysisSchema = z35.object({
|
|
|
30313
30389
|
shotStyle: z35.string(),
|
|
30314
30390
|
audioStyle: z35.string(),
|
|
30315
30391
|
hook: z35.string(),
|
|
30316
|
-
usageNotes: z35.string()
|
|
30392
|
+
usageNotes: z35.string(),
|
|
30393
|
+
// Optional because rows analysed before analysis version 2 do not carry them.
|
|
30394
|
+
format: z35.string().optional(),
|
|
30395
|
+
tone: z35.string().optional(),
|
|
30396
|
+
productClaims: z35.array(z35.string()).optional()
|
|
30317
30397
|
});
|
|
30318
30398
|
var videoDocSchema = z35.object({
|
|
30319
30399
|
_id: z35.string(),
|
|
@@ -31564,9 +31644,9 @@ function toRow(entry) {
|
|
|
31564
31644
|
};
|
|
31565
31645
|
}
|
|
31566
31646
|
function renderEntry(entry, full) {
|
|
31567
|
-
const
|
|
31568
|
-
const suffix =
|
|
31569
|
-
const lines = [`- \`${
|
|
31647
|
+
const row2 = toRow(entry);
|
|
31648
|
+
const suffix = row2.status ? ` [${row2.status}]` : "";
|
|
31649
|
+
const lines = [`- \`${row2.id}\` ${row2.name}${suffix}`];
|
|
31570
31650
|
const nested = entry.action;
|
|
31571
31651
|
const doc = nested && typeof nested === "object" ? nested : entry;
|
|
31572
31652
|
const description = typeof doc.description === "string" ? doc.description : "";
|
|
@@ -31576,8 +31656,8 @@ function renderEntry(entry, full) {
|
|
|
31576
31656
|
...text2.trim().split("\n").map((line) => line ? ` ${line}` : "")
|
|
31577
31657
|
);
|
|
31578
31658
|
}
|
|
31579
|
-
if (
|
|
31580
|
-
lines.push(` ${
|
|
31659
|
+
if (row2.hint) {
|
|
31660
|
+
lines.push(` ${row2.hint}`);
|
|
31581
31661
|
}
|
|
31582
31662
|
return lines;
|
|
31583
31663
|
}
|
|
@@ -35288,10 +35368,10 @@ function membersFromFile(content) {
|
|
|
35288
35368
|
const emailColumn = header.findIndex((cell3) => EMAIL_HEADER.test(cell3));
|
|
35289
35369
|
const phoneColumn = header.findIndex((cell3) => !EMAIL_HEADER.test(cell3) && PHONE_HEADER.test(cell3));
|
|
35290
35370
|
if (emailColumn >= 0 || phoneColumn >= 0) {
|
|
35291
|
-
const cells = (column) => column < 0 ? [] : rows.slice(1).flatMap((
|
|
35371
|
+
const cells = (column) => column < 0 ? [] : rows.slice(1).flatMap((row2) => row2[column] ? [row2[column]] : []);
|
|
35292
35372
|
return { emails: cells(emailColumn), phones: cells(phoneColumn) };
|
|
35293
35373
|
}
|
|
35294
|
-
const values = rows.flatMap((
|
|
35374
|
+
const values = rows.flatMap((row2) => row2[0] ? [row2[0]] : []);
|
|
35295
35375
|
return values.some((value2) => value2.includes("@")) ? { emails: values, phones: [] } : { emails: [], phones: values };
|
|
35296
35376
|
}
|
|
35297
35377
|
|
|
@@ -35820,7 +35900,7 @@ function conversionReportRequestFromArgs(args8) {
|
|
|
35820
35900
|
};
|
|
35821
35901
|
}
|
|
35822
35902
|
function reportHints(report) {
|
|
35823
|
-
const nothing = report.rows.every((
|
|
35903
|
+
const nothing = report.rows.every((row2) => row2.conversions === 0 && (row2.events ?? []).length === 0);
|
|
35824
35904
|
return nothing ? [
|
|
35825
35905
|
"No attributed conversions in this window. Before concluding the ads do not convert: `conversions events` shows whether the site's events arrive at all, and `campaigns` whether anything served."
|
|
35826
35906
|
] : [
|
|
@@ -39331,9 +39411,9 @@ function warnDefaults(ctx) {
|
|
|
39331
39411
|
var PLANNER_SOURCE = "keyword_planner_estimate";
|
|
39332
39412
|
var IDENTITY_FIELDS = /* @__PURE__ */ new Set(["keyword"]);
|
|
39333
39413
|
function stampPlannerRows(rows) {
|
|
39334
|
-
return rows.map((
|
|
39414
|
+
return rows.map((row2) => {
|
|
39335
39415
|
const stamped = { source: PLANNER_SOURCE };
|
|
39336
|
-
for (const [key, value2] of Object.entries(
|
|
39416
|
+
for (const [key, value2] of Object.entries(row2)) {
|
|
39337
39417
|
stamped[IDENTITY_FIELDS.has(key) || key.startsWith("planner_") ? key : `planner_${key}`] = value2;
|
|
39338
39418
|
}
|
|
39339
39419
|
return stamped;
|
|
@@ -40262,33 +40342,33 @@ function toMicros2(value2) {
|
|
|
40262
40342
|
function formatMoney(micros) {
|
|
40263
40343
|
return (micros / 1e6).toFixed(2);
|
|
40264
40344
|
}
|
|
40265
|
-
function keywordLabel(
|
|
40266
|
-
const text2 =
|
|
40267
|
-
const id =
|
|
40345
|
+
function keywordLabel(row2) {
|
|
40346
|
+
const text2 = row2["ad_group_criterion.keyword.text"];
|
|
40347
|
+
const id = row2["ad_group_criterion.criterion_id"];
|
|
40268
40348
|
const name = typeof text2 === "string" && text2 !== "" ? text2 : id == null ? "(unnamed keyword)" : `criterion ${id}`;
|
|
40269
|
-
const adGroup =
|
|
40349
|
+
const adGroup = row2["ad_group.name"];
|
|
40270
40350
|
return typeof adGroup === "string" && adGroup !== "" ? `${name} (ad group ${adGroup})` : name;
|
|
40271
40351
|
}
|
|
40272
|
-
function keywordKey(
|
|
40273
|
-
const adGroup =
|
|
40274
|
-
const criterion =
|
|
40275
|
-
return `${String(adGroup)}~${String(criterion)}` === "~" ? keywordLabel(
|
|
40352
|
+
function keywordKey(row2) {
|
|
40353
|
+
const adGroup = row2["ad_group.id"] ?? row2["ad_group.name"] ?? "";
|
|
40354
|
+
const criterion = row2["ad_group_criterion.criterion_id"] ?? row2["ad_group_criterion.keyword.text"] ?? "";
|
|
40355
|
+
return `${String(adGroup)}~${String(criterion)}` === "~" ? keywordLabel(row2) : `${adGroup}~${criterion}`;
|
|
40276
40356
|
}
|
|
40277
|
-
function reasonsOn(
|
|
40278
|
-
const raw =
|
|
40357
|
+
function reasonsOn(row2) {
|
|
40358
|
+
const raw = row2["ad_group_criterion.primary_status_reasons"];
|
|
40279
40359
|
if (!Array.isArray(raw)) return null;
|
|
40280
40360
|
return raw.filter((r) => typeof r === "string");
|
|
40281
40361
|
}
|
|
40282
|
-
function bidShortfall(
|
|
40283
|
-
const bid = toMicros2(
|
|
40284
|
-
const firstPage = toMicros2(
|
|
40362
|
+
function bidShortfall(row2) {
|
|
40363
|
+
const bid = toMicros2(row2["ad_group_criterion.effective_cpc_bid_micros"] ?? row2["ad_group_criterion.cpc_bid_micros"]);
|
|
40364
|
+
const firstPage = toMicros2(row2["ad_group_criterion.position_estimates.first_page_cpc_micros"]);
|
|
40285
40365
|
if (bid == null || firstPage == null || bid >= firstPage) return null;
|
|
40286
40366
|
return `bids ${formatMoney(bid)} against a ${formatMoney(firstPage)} first-page estimate`;
|
|
40287
40367
|
}
|
|
40288
|
-
function limitsOn(
|
|
40289
|
-
const reasons = reasonsOn(
|
|
40290
|
-
const shortfall = bidShortfall(
|
|
40291
|
-
const label = keywordLabel(
|
|
40368
|
+
function limitsOn(row2, options) {
|
|
40369
|
+
const reasons = reasonsOn(row2);
|
|
40370
|
+
const shortfall = bidShortfall(row2);
|
|
40371
|
+
const label = keywordLabel(row2);
|
|
40292
40372
|
const applicable = reasons ? reasons.filter((reason) => reason in ACTIONABLE_REASONS) : options.statusReasonsSelected || shortfall === null ? [] : [BELOW_FIRST_PAGE_BID];
|
|
40293
40373
|
return applicable.map((reason) => ({
|
|
40294
40374
|
reason,
|
|
@@ -40302,10 +40382,10 @@ function describeLimit(reason, details) {
|
|
|
40302
40382
|
return `${label} \u2014 ${details.length}: ${named}${rest}. Fix: ${advice}.`;
|
|
40303
40383
|
}
|
|
40304
40384
|
function collectKeywordLimits(rows, options, acc = { detailsByReason: /* @__PURE__ */ new Map(), keywords: /* @__PURE__ */ new Set() }) {
|
|
40305
|
-
for (const
|
|
40306
|
-
const limits = limitsOn(
|
|
40385
|
+
for (const row2 of rows) {
|
|
40386
|
+
const limits = limitsOn(row2, options);
|
|
40307
40387
|
if (limits.length === 0) continue;
|
|
40308
|
-
acc.keywords.add(keywordKey(
|
|
40388
|
+
acc.keywords.add(keywordKey(row2));
|
|
40309
40389
|
for (const { reason, detail } of limits) {
|
|
40310
40390
|
const bucket = acc.detailsByReason.get(reason);
|
|
40311
40391
|
if (bucket) bucket.push(detail);
|
|
@@ -40415,11 +40495,11 @@ function writeRowsToFile(filePath, rows, fields, append) {
|
|
|
40415
40495
|
writeFileSync(filePath, `${toCsvRow(fields)}
|
|
40416
40496
|
`, "utf-8");
|
|
40417
40497
|
}
|
|
40418
|
-
const csvRows = rows.map((
|
|
40498
|
+
const csvRows = rows.map((row2) => toCsvRow(fields.map((f) => String(row2[f] ?? ""))));
|
|
40419
40499
|
appendFileSync(filePath, `${csvRows.join("\n")}
|
|
40420
40500
|
`, "utf-8");
|
|
40421
40501
|
} else if (filePath.split(".").pop()?.toLowerCase() === "jsonl") {
|
|
40422
|
-
const lines = rows.map((
|
|
40502
|
+
const lines = rows.map((row2) => JSON.stringify(row2));
|
|
40423
40503
|
if (append && existsSync2(filePath)) {
|
|
40424
40504
|
appendFileSync(filePath, `${lines.join("\n")}
|
|
40425
40505
|
`, "utf-8");
|
|
@@ -40504,26 +40584,26 @@ function writeLine(line) {
|
|
|
40504
40584
|
var writeCsvRows = (rows, fields, notices) => {
|
|
40505
40585
|
writeLine(toCsvRow(fields));
|
|
40506
40586
|
for (const line of notices) writeLine(line);
|
|
40507
|
-
for (const
|
|
40587
|
+
for (const row2 of rows) writeLine(toCsvRow(fields.map((f) => String(row2[f] ?? ""))));
|
|
40508
40588
|
};
|
|
40509
40589
|
var writeJsonlRows = (rows, _fields, notices) => {
|
|
40510
40590
|
for (const line of notices) writeLine(line);
|
|
40511
|
-
for (const
|
|
40591
|
+
for (const row2 of rows) writeLine(JSON.stringify(row2));
|
|
40512
40592
|
};
|
|
40513
40593
|
var OMITTED = "(omitted)";
|
|
40514
40594
|
var OMITTED_FALSE = `false ${OMITTED}`;
|
|
40515
40595
|
var OMITTED_LEGEND = `> ${OMITTED} = Google left this field off the row, which is how it sends false, 0 and "not set": the field WAS read. A field with no column here was not read.`;
|
|
40516
|
-
function mdCell(
|
|
40517
|
-
if (!(field in
|
|
40518
|
-
return String(
|
|
40596
|
+
function mdCell(row2, field, booleanColumns) {
|
|
40597
|
+
if (!(field in row2)) return booleanColumns.has(field) ? OMITTED_FALSE : OMITTED;
|
|
40598
|
+
return String(row2[field] ?? "").replace(/\|/g, "\\|");
|
|
40519
40599
|
}
|
|
40520
40600
|
var writeMdRows = (rows, fields, notices) => {
|
|
40521
|
-
const booleanColumns = new Set(fields.filter((f) => rows.some((
|
|
40601
|
+
const booleanColumns = new Set(fields.filter((f) => rows.some((row2) => typeof row2[f] === "boolean")));
|
|
40522
40602
|
for (const line of notices) writeLine(line);
|
|
40523
40603
|
writeLine(`| ${fields.join(" | ")} |`);
|
|
40524
40604
|
writeLine(`| ${fields.map(() => "---").join(" | ")} |`);
|
|
40525
|
-
for (const
|
|
40526
|
-
if (rows.some((
|
|
40605
|
+
for (const row2 of rows) writeLine(`| ${fields.map((f) => mdCell(row2, f, booleanColumns)).join(" | ")} |`);
|
|
40606
|
+
if (rows.some((row2) => fields.some((f) => !(f in row2)))) writeLine(OMITTED_LEGEND);
|
|
40527
40607
|
};
|
|
40528
40608
|
var ROW_WRITERS = { csv: writeCsvRows, jsonl: writeJsonlRows, md: writeMdRows };
|
|
40529
40609
|
function writeRows(format, rows, columns, notices) {
|
|
@@ -40647,8 +40727,8 @@ function parseSelectedFields(gaql) {
|
|
|
40647
40727
|
return list.split(",").map((field) => field.trim()).filter((field) => /^[A-Za-z_][A-Za-z0-9_]*(\.[A-Za-z0-9_]+)*$/.test(field));
|
|
40648
40728
|
}
|
|
40649
40729
|
function foldObservedFields(rows, observed) {
|
|
40650
|
-
for (const
|
|
40651
|
-
for (const key of Object.keys(
|
|
40730
|
+
for (const row2 of rows) {
|
|
40731
|
+
for (const key of Object.keys(row2)) observed.add(key);
|
|
40652
40732
|
}
|
|
40653
40733
|
}
|
|
40654
40734
|
function unobservedFields(gaql, observed) {
|
|
@@ -41483,11 +41563,11 @@ var PROPERTY_ROW_PREFIX = "properties.";
|
|
|
41483
41563
|
var PROPERTY_KEY_MAX = 64;
|
|
41484
41564
|
var PROPERTY_KEY = /^[A-Za-z0-9_][A-Za-z0-9_.-]*$/;
|
|
41485
41565
|
var RESERVED_PROPERTY_KEYS = ["baker_source", "hubspot_property", "hubspot_value"];
|
|
41486
|
-
function isPropertyRow(
|
|
41487
|
-
return
|
|
41566
|
+
function isPropertyRow(row2) {
|
|
41567
|
+
return row2.startsWith(PROPERTY_ROW_PREFIX);
|
|
41488
41568
|
}
|
|
41489
|
-
function propertyKeyOf(
|
|
41490
|
-
return isPropertyRow(
|
|
41569
|
+
function propertyKeyOf(row2) {
|
|
41570
|
+
return isPropertyRow(row2) ? row2.slice(PROPERTY_ROW_PREFIX.length) : null;
|
|
41491
41571
|
}
|
|
41492
41572
|
function propertyKeyProblem(key) {
|
|
41493
41573
|
const trimmed = key.trim();
|
|
@@ -41499,11 +41579,11 @@ function propertyKeyProblem(key) {
|
|
|
41499
41579
|
if (RESERVED_PROPERTY_KEYS.includes(trimmed)) return `"${trimmed}" is written by Baker itself; pick another name.`;
|
|
41500
41580
|
return null;
|
|
41501
41581
|
}
|
|
41502
|
-
function mappingRowProblem(
|
|
41503
|
-
if (isSourceField(
|
|
41504
|
-
const key = propertyKeyOf(
|
|
41582
|
+
function mappingRowProblem(row2) {
|
|
41583
|
+
if (isSourceField(row2)) return null;
|
|
41584
|
+
const key = propertyKeyOf(row2);
|
|
41505
41585
|
if (key === null) {
|
|
41506
|
-
return `"${
|
|
41586
|
+
return `"${row2}" is not a field an event can carry. A field is one of ${SOURCE_FIELD_NAMES.join(", ")}; an extra property is spelled properties.<name>.`;
|
|
41507
41587
|
}
|
|
41508
41588
|
return propertyKeyProblem(key);
|
|
41509
41589
|
}
|
|
@@ -42090,13 +42170,13 @@ var BOOKKEEPING_TYPES = /* @__PURE__ */ new Set([
|
|
|
42090
42170
|
"side_effect_settled"
|
|
42091
42171
|
]);
|
|
42092
42172
|
var SUBMIT_TRIGGERS = new Set(Object.values(STEP_SUBMIT_TRIGGERS));
|
|
42093
|
-
function isEmbedLifecycle(
|
|
42094
|
-
return
|
|
42173
|
+
function isEmbedLifecycle(row2) {
|
|
42174
|
+
return row2.eventType === "form_trigger" && triggerDescription2(row2.triggerId)?.lifecycle === true;
|
|
42095
42175
|
}
|
|
42096
|
-
function isBookkeepingRow(
|
|
42097
|
-
if (BOOKKEEPING_TYPES.has(
|
|
42098
|
-
if (isEmbedLifecycle(
|
|
42099
|
-
return
|
|
42176
|
+
function isBookkeepingRow(row2) {
|
|
42177
|
+
if (BOOKKEEPING_TYPES.has(row2.eventType)) return true;
|
|
42178
|
+
if (isEmbedLifecycle(row2)) return true;
|
|
42179
|
+
return row2.eventType === "form_trigger" && SUBMIT_TRIGGERS.has(row2.triggerId);
|
|
42100
42180
|
}
|
|
42101
42181
|
|
|
42102
42182
|
// ../api/src/analytics/identityLinks.ts
|
|
@@ -42325,13 +42405,13 @@ var CLICK_LABELS2 = {
|
|
|
42325
42405
|
sccid: "Snapchat click id",
|
|
42326
42406
|
oppref: "ChatGPT Ads click id"
|
|
42327
42407
|
};
|
|
42328
|
-
var PERSON_FIELDS = MATCH_FIELD_FORWARDING.map((
|
|
42329
|
-
name:
|
|
42330
|
-
label: PERSON_LABELS[
|
|
42408
|
+
var PERSON_FIELDS = MATCH_FIELD_FORWARDING.map((row2) => ({
|
|
42409
|
+
name: row2.field,
|
|
42410
|
+
label: PERSON_LABELS[row2.field] ?? row2.field,
|
|
42331
42411
|
group: "person",
|
|
42332
|
-
hashed:
|
|
42333
|
-
...
|
|
42334
|
-
...
|
|
42412
|
+
hashed: row2.hashed,
|
|
42413
|
+
...row2.meta ? { meta: row2.meta } : {},
|
|
42414
|
+
...row2.google ? { google: row2.google } : {}
|
|
42335
42415
|
}));
|
|
42336
42416
|
var CLICK_FIELDS = INGEST_CLICK_ID_PARAMS.map((param) => ({
|
|
42337
42417
|
name: param,
|
|
@@ -44707,18 +44787,18 @@ var ADDRESS_KEYS = [
|
|
|
44707
44787
|
"city",
|
|
44708
44788
|
"administrativeArea"
|
|
44709
44789
|
];
|
|
44710
|
-
function nestAddress(
|
|
44790
|
+
function nestAddress(row2) {
|
|
44711
44791
|
const address = {};
|
|
44712
44792
|
for (const key of ADDRESS_KEYS) {
|
|
44713
|
-
if (
|
|
44714
|
-
address[key] =
|
|
44715
|
-
delete
|
|
44793
|
+
if (row2[key] !== void 0) {
|
|
44794
|
+
address[key] = row2[key];
|
|
44795
|
+
delete row2[key];
|
|
44716
44796
|
}
|
|
44717
44797
|
}
|
|
44718
|
-
return Object.keys(address).length > 0 ? { ...
|
|
44798
|
+
return Object.keys(address).length > 0 ? { ...row2, address } : row2;
|
|
44719
44799
|
}
|
|
44720
44800
|
function toRow2(record) {
|
|
44721
|
-
const
|
|
44801
|
+
const row2 = {};
|
|
44722
44802
|
const ignored = [];
|
|
44723
44803
|
for (const [column, raw] of Object.entries(record)) {
|
|
44724
44804
|
const key = payloadKeyForColumn(column);
|
|
@@ -44730,10 +44810,10 @@ function toRow2(record) {
|
|
|
44730
44810
|
}
|
|
44731
44811
|
const value2 = cellValue(key, raw);
|
|
44732
44812
|
if (value2 !== void 0) {
|
|
44733
|
-
|
|
44813
|
+
row2[key] = value2;
|
|
44734
44814
|
}
|
|
44735
44815
|
}
|
|
44736
|
-
return { row: nestAddress(
|
|
44816
|
+
return { row: nestAddress(row2), ignored };
|
|
44737
44817
|
}
|
|
44738
44818
|
function cellValue(key, raw) {
|
|
44739
44819
|
const value2 = typeof raw === "string" ? raw.trim() : raw;
|
|
@@ -44922,42 +45002,42 @@ function rowFromFlags(args8) {
|
|
|
44922
45002
|
["regionCode", args8.country],
|
|
44923
45003
|
["postalCode", args8["postal-code"]]
|
|
44924
45004
|
];
|
|
44925
|
-
const
|
|
45005
|
+
const row2 = {};
|
|
44926
45006
|
for (const [key, value2] of entries) {
|
|
44927
45007
|
if (typeof value2 === "string" && value2.trim() !== "") {
|
|
44928
|
-
|
|
45008
|
+
row2[key] = value2.trim();
|
|
44929
45009
|
}
|
|
44930
45010
|
}
|
|
44931
|
-
nestAddressFlags(
|
|
44932
|
-
readNumericFlags(args8,
|
|
44933
|
-
return Object.keys(
|
|
45011
|
+
nestAddressFlags(row2);
|
|
45012
|
+
readNumericFlags(args8, row2);
|
|
45013
|
+
return Object.keys(row2).length > 0 ? row2 : void 0;
|
|
44934
45014
|
}
|
|
44935
|
-
function nestAddressFlags(
|
|
45015
|
+
function nestAddressFlags(row2) {
|
|
44936
45016
|
const address = {};
|
|
44937
45017
|
for (const key of ["givenName", "familyName", "regionCode", "postalCode"]) {
|
|
44938
|
-
if (
|
|
44939
|
-
address[key] =
|
|
44940
|
-
delete
|
|
45018
|
+
if (row2[key] !== void 0) {
|
|
45019
|
+
address[key] = row2[key];
|
|
45020
|
+
delete row2[key];
|
|
44941
45021
|
}
|
|
44942
45022
|
}
|
|
44943
45023
|
if (Object.keys(address).length > 0) {
|
|
44944
|
-
|
|
45024
|
+
row2.address = address;
|
|
44945
45025
|
}
|
|
44946
45026
|
}
|
|
44947
|
-
function readNumericFlags(args8,
|
|
45027
|
+
function readNumericFlags(args8, row2) {
|
|
44948
45028
|
if (args8["conversion-count"] !== void 0 && args8["conversion-count"] !== "") {
|
|
44949
45029
|
const count2 = Number(args8["conversion-count"]);
|
|
44950
45030
|
if (!Number.isInteger(count2) || count2 < 1) {
|
|
44951
45031
|
failWriteValidation2("--conversion-count must be a whole number of conversions, e.g. 3");
|
|
44952
45032
|
}
|
|
44953
|
-
|
|
45033
|
+
row2.conversionCount = count2;
|
|
44954
45034
|
}
|
|
44955
45035
|
if (args8.value !== void 0 && args8.value !== "") {
|
|
44956
45036
|
const numeric = Number(args8.value);
|
|
44957
45037
|
if (!Number.isFinite(numeric)) {
|
|
44958
45038
|
failWriteValidation2("--value must be a number in major currency units, e.g. 49.90");
|
|
44959
45039
|
}
|
|
44960
|
-
|
|
45040
|
+
row2.value = numeric;
|
|
44961
45041
|
}
|
|
44962
45042
|
}
|
|
44963
45043
|
var conversionsUploadCommand = defineCommand50({
|
|
@@ -46956,16 +47036,16 @@ function parseListFileArg(path58, maxRows) {
|
|
|
46956
47036
|
const rows = [];
|
|
46957
47037
|
for (const line of lines.slice(1)) {
|
|
46958
47038
|
const cells = parseCsvLine(line);
|
|
46959
|
-
const
|
|
47039
|
+
const row2 = {};
|
|
46960
47040
|
columns.forEach((column, index) => {
|
|
46961
47041
|
const value2 = cells[index] ?? "";
|
|
46962
47042
|
if (!value2) {
|
|
46963
47043
|
return;
|
|
46964
47044
|
}
|
|
46965
|
-
|
|
47045
|
+
row2[column] = column.toLowerCase() === "email" ? sha256Lower(value2) : value2;
|
|
46966
47046
|
});
|
|
46967
|
-
if (Object.keys(
|
|
46968
|
-
rows.push(
|
|
47047
|
+
if (Object.keys(row2).length > 0) {
|
|
47048
|
+
rows.push(row2);
|
|
46969
47049
|
}
|
|
46970
47050
|
}
|
|
46971
47051
|
if (rows.length > maxRows) {
|
|
@@ -49830,8 +49910,8 @@ import { defineCommand as defineCommand64 } from "citty";
|
|
|
49830
49910
|
function asRecord(value2) {
|
|
49831
49911
|
return typeof value2 === "object" && value2 !== null && !Array.isArray(value2) ? value2 : void 0;
|
|
49832
49912
|
}
|
|
49833
|
-
function readPath2(
|
|
49834
|
-
let current =
|
|
49913
|
+
function readPath2(row2, path58) {
|
|
49914
|
+
let current = row2;
|
|
49835
49915
|
for (const segment of path58.split(".")) {
|
|
49836
49916
|
const record = asRecord(current);
|
|
49837
49917
|
if (!record) return void 0;
|
|
@@ -49840,10 +49920,10 @@ function readPath2(row, path58) {
|
|
|
49840
49920
|
return current;
|
|
49841
49921
|
}
|
|
49842
49922
|
function projectFields(rows, paths) {
|
|
49843
|
-
return rows.map((
|
|
49923
|
+
return rows.map((row2) => {
|
|
49844
49924
|
const projected = {};
|
|
49845
49925
|
for (const path58 of paths) {
|
|
49846
|
-
const value2 = readPath2(
|
|
49926
|
+
const value2 = readPath2(row2, path58);
|
|
49847
49927
|
if (value2 !== void 0) {
|
|
49848
49928
|
projected[path58] = value2;
|
|
49849
49929
|
}
|
|
@@ -49857,19 +49937,19 @@ function shapeListRows(rows, args8, compact5) {
|
|
|
49857
49937
|
if (fields) {
|
|
49858
49938
|
const paths = fields.split(",").map((field) => field.trim()).filter((field) => field.length > 0);
|
|
49859
49939
|
if (paths.length > 0) {
|
|
49860
|
-
const projected = projectFields(raw, paths).map((
|
|
49861
|
-
const missing = paths.filter((path58) =>
|
|
49940
|
+
const projected = projectFields(raw, paths).map((row2, i) => {
|
|
49941
|
+
const missing = paths.filter((path58) => row2[path58] === void 0);
|
|
49862
49942
|
const source = rows[i];
|
|
49863
|
-
if (missing.length === 0 || source === void 0) return
|
|
49943
|
+
if (missing.length === 0 || source === void 0) return row2;
|
|
49864
49944
|
const compactRow3 = compact5.row(source);
|
|
49865
49945
|
for (const path58 of missing) {
|
|
49866
|
-
if (compactRow3[path58] !== void 0)
|
|
49946
|
+
if (compactRow3[path58] !== void 0) row2[path58] = compactRow3[path58];
|
|
49867
49947
|
}
|
|
49868
|
-
return
|
|
49948
|
+
return row2;
|
|
49869
49949
|
});
|
|
49870
|
-
const unmatched = paths.filter((path58) => projected.every((
|
|
49950
|
+
const unmatched = paths.filter((path58) => projected.every((row2) => row2[path58] === void 0));
|
|
49871
49951
|
if (projected.length === 0 || unmatched.length === 0) return { rows: projected, fields: paths };
|
|
49872
|
-
const carried = /* @__PURE__ */ new Set([...compact5.columns, ...raw.flatMap((
|
|
49952
|
+
const carried = /* @__PURE__ */ new Set([...compact5.columns, ...raw.flatMap((row2) => Object.keys(row2))]);
|
|
49873
49953
|
return {
|
|
49874
49954
|
rows: projected,
|
|
49875
49955
|
fields: paths,
|
|
@@ -49881,7 +49961,7 @@ function shapeListRows(rows, args8, compact5) {
|
|
|
49881
49961
|
}
|
|
49882
49962
|
if (args8.full) {
|
|
49883
49963
|
const columns = /* @__PURE__ */ new Set();
|
|
49884
|
-
for (const
|
|
49964
|
+
for (const row2 of raw) for (const key of Object.keys(row2)) columns.add(key);
|
|
49885
49965
|
return { rows: raw, fields: [...columns] };
|
|
49886
49966
|
}
|
|
49887
49967
|
return { rows: rows.map(compact5.row), fields: [...compact5.columns] };
|
|
@@ -49917,28 +49997,28 @@ var COMPACT_COLUMNS = [
|
|
|
49917
49997
|
"landingUrl",
|
|
49918
49998
|
"postUrn"
|
|
49919
49999
|
];
|
|
49920
|
-
function compactRow(
|
|
49921
|
-
const destination = creativeDestination(
|
|
50000
|
+
function compactRow(row2) {
|
|
50001
|
+
const destination = creativeDestination(row2.content);
|
|
49922
50002
|
return {
|
|
49923
|
-
id:
|
|
49924
|
-
urn:
|
|
49925
|
-
campaign:
|
|
49926
|
-
intendedStatus:
|
|
49927
|
-
isServing:
|
|
49928
|
-
reviewStatus:
|
|
50003
|
+
id: row2.id,
|
|
50004
|
+
urn: row2.urn,
|
|
50005
|
+
campaign: row2.campaign,
|
|
50006
|
+
intendedStatus: row2.intendedStatus,
|
|
50007
|
+
isServing: row2.isServing,
|
|
50008
|
+
reviewStatus: row2.reviewStatus,
|
|
49929
50009
|
format: destination.format,
|
|
49930
50010
|
...destination.landingUrl ? { landingUrl: destination.landingUrl } : {},
|
|
49931
50011
|
...destination.postUrn ? { postUrn: destination.postUrn } : {}
|
|
49932
50012
|
};
|
|
49933
50013
|
}
|
|
49934
50014
|
function unmappedShapeWarnings(rows, rawContentReturned) {
|
|
49935
|
-
const unmapped = rows.filter((
|
|
50015
|
+
const unmapped = rows.filter((row2) => row2.content && creativeDestination(row2.content).format === "unknown");
|
|
49936
50016
|
if (unmapped.length === 0) return [];
|
|
49937
50017
|
const remedy = rawContentReturned ? "Their raw content is in this response \u2014 read it directly; this command cannot resolve a destination for them." : "Re-read those with --full before drawing any conclusion about where they point.";
|
|
49938
50018
|
return [
|
|
49939
50019
|
{
|
|
49940
50020
|
code: "UNMAPPED_CREATIVE_CONTENT",
|
|
49941
|
-
message: `${unmapped.length} of ${rows.length} creatives have a content shape this command can't read, so their destination is missing (ids: ${unmapped.slice(0, 5).map((
|
|
50021
|
+
message: `${unmapped.length} of ${rows.length} creatives have a content shape this command can't read, so their destination is missing (ids: ${unmapped.slice(0, 5).map((row2) => row2.id).join(", ")}). ${remedy}`
|
|
49942
50022
|
}
|
|
49943
50023
|
];
|
|
49944
50024
|
}
|
|
@@ -50976,18 +51056,18 @@ Examples:
|
|
|
50976
51056
|
import { defineCommand as defineCommand76 } from "citty";
|
|
50977
51057
|
|
|
50978
51058
|
// src/commands/ads/meta/list-rows.ts
|
|
50979
|
-
function pick(
|
|
51059
|
+
function pick(row2, keys) {
|
|
50980
51060
|
const picked = {};
|
|
50981
51061
|
for (const key of keys) {
|
|
50982
|
-
if (
|
|
51062
|
+
if (row2[key] !== void 0) picked[key] = row2[key];
|
|
50983
51063
|
}
|
|
50984
51064
|
return picked;
|
|
50985
51065
|
}
|
|
50986
51066
|
var CAMPAIGN_COLUMNS = ["id", "name", "effective_status", "daily_budget", "lifetime_budget", "created_date"];
|
|
50987
|
-
function compactCampaign(
|
|
50988
|
-
const created =
|
|
51067
|
+
function compactCampaign(row2) {
|
|
51068
|
+
const created = row2.created_time;
|
|
50989
51069
|
return {
|
|
50990
|
-
...pick(
|
|
51070
|
+
...pick(row2, ["id", "name", "effective_status", "daily_budget", "lifetime_budget"]),
|
|
50991
51071
|
...typeof created === "string" ? { created_date: created.slice(0, 10) } : {}
|
|
50992
51072
|
};
|
|
50993
51073
|
}
|
|
@@ -51006,12 +51086,12 @@ var ADSET_KEYS = [
|
|
|
51006
51086
|
"is_dynamic_creative"
|
|
51007
51087
|
];
|
|
51008
51088
|
var ADSET_COLUMNS = [...ADSET_KEYS, "learning_stage", "end_time", "created_time"];
|
|
51009
|
-
function compactAdSet(
|
|
51010
|
-
const learning = asRecord(
|
|
51089
|
+
function compactAdSet(row2) {
|
|
51090
|
+
const learning = asRecord(row2.learning_stage_info)?.status;
|
|
51011
51091
|
return {
|
|
51012
|
-
...pick(
|
|
51092
|
+
...pick(row2, ADSET_KEYS),
|
|
51013
51093
|
...typeof learning === "string" ? { learning_stage: learning } : {},
|
|
51014
|
-
...pick(
|
|
51094
|
+
...pick(row2, ["end_time", "created_time"])
|
|
51015
51095
|
};
|
|
51016
51096
|
}
|
|
51017
51097
|
var AD_COLUMNS = [
|
|
@@ -51032,14 +51112,14 @@ function adIssues(value2) {
|
|
|
51032
51112
|
return typeof text2 === "string" && text2 ? [text2] : [];
|
|
51033
51113
|
});
|
|
51034
51114
|
}
|
|
51035
|
-
function compactAd(
|
|
51036
|
-
const creativeId = asRecord(
|
|
51037
|
-
const issues = adIssues(
|
|
51115
|
+
function compactAd(row2) {
|
|
51116
|
+
const creativeId = asRecord(row2.creative)?.id;
|
|
51117
|
+
const issues = adIssues(row2.issues_info);
|
|
51038
51118
|
return {
|
|
51039
|
-
...pick(
|
|
51119
|
+
...pick(row2, ["id", "name", "adset_id", "campaign_id", "effective_status"]),
|
|
51040
51120
|
...creativeId !== void 0 ? { creative_id: creativeId } : {},
|
|
51041
51121
|
...issues.length > 0 ? { issues } : {},
|
|
51042
|
-
...pick(
|
|
51122
|
+
...pick(row2, ["created_time"])
|
|
51043
51123
|
};
|
|
51044
51124
|
}
|
|
51045
51125
|
var ACTIVITY_COLUMNS = [
|
|
@@ -51069,10 +51149,10 @@ function activityChange(extraData) {
|
|
|
51069
51149
|
const show = (value2) => value2 === null ? "(none)" : String(value2);
|
|
51070
51150
|
return `${show(before)} \u2192 ${show(after)}`;
|
|
51071
51151
|
}
|
|
51072
|
-
function compactActivity(
|
|
51073
|
-
const change = activityChange(
|
|
51152
|
+
function compactActivity(row2) {
|
|
51153
|
+
const change = activityChange(row2.extra_data);
|
|
51074
51154
|
return {
|
|
51075
|
-
...pick(
|
|
51155
|
+
...pick(row2, ["event_time", "event_type", "actor_name", "object_type", "object_name", "object_id"]),
|
|
51076
51156
|
...change !== void 0 ? { change } : {}
|
|
51077
51157
|
};
|
|
51078
51158
|
}
|
|
@@ -53502,10 +53582,10 @@ Example: baker ads meta ads retag 120252158038400247 --url-tags "utm_source={{si
|
|
|
53502
53582
|
}
|
|
53503
53583
|
},
|
|
53504
53584
|
run: async ({ args: args8 }) => {
|
|
53505
|
-
const { apiPost: apiPost2 } = await import("./client-
|
|
53506
|
-
const { requireChatId: requireChatId2 } = await import("./env-
|
|
53507
|
-
const { writeJsonEnvelope: writeJsonEnvelope2 } = await import("./output-
|
|
53508
|
-
const { handleMetaError: handleMetaError2 } = await import("./shared-
|
|
53585
|
+
const { apiPost: apiPost2 } = await import("./client-22ED7NUR.js");
|
|
53586
|
+
const { requireChatId: requireChatId2 } = await import("./env-E565GJBV.js");
|
|
53587
|
+
const { writeJsonEnvelope: writeJsonEnvelope2 } = await import("./output-F6NKGZ6E.js");
|
|
53588
|
+
const { handleMetaError: handleMetaError2 } = await import("./shared-YSUGIUS4.js");
|
|
53509
53589
|
try {
|
|
53510
53590
|
const accountId = bareAccountId2(args8);
|
|
53511
53591
|
const urlTags = typeof args8["url-tags"] === "string" ? args8["url-tags"] : void 0;
|
|
@@ -53656,10 +53736,10 @@ function duplicateCommand2(entity, label) {
|
|
|
53656
53736
|
replace: { type: "boolean", description: "Pause the original once the copy publishes" }
|
|
53657
53737
|
},
|
|
53658
53738
|
run: async ({ args: args8 }) => {
|
|
53659
|
-
const { apiPost: apiPost2 } = await import("./client-
|
|
53660
|
-
const { requireChatId: requireChatId2 } = await import("./env-
|
|
53661
|
-
const { writeJsonEnvelope: writeJsonEnvelope2 } = await import("./output-
|
|
53662
|
-
const { handleMetaError: handleMetaError2 } = await import("./shared-
|
|
53739
|
+
const { apiPost: apiPost2 } = await import("./client-22ED7NUR.js");
|
|
53740
|
+
const { requireChatId: requireChatId2 } = await import("./env-E565GJBV.js");
|
|
53741
|
+
const { writeJsonEnvelope: writeJsonEnvelope2 } = await import("./output-F6NKGZ6E.js");
|
|
53742
|
+
const { handleMetaError: handleMetaError2 } = await import("./shared-YSUGIUS4.js");
|
|
53663
53743
|
try {
|
|
53664
53744
|
const accountId = bareAccountId2(args8);
|
|
53665
53745
|
const chatId = requireChatId2();
|
|
@@ -54084,16 +54164,16 @@ Examples:
|
|
|
54084
54164
|
|
|
54085
54165
|
// src/commands/ads/meta/custom-conversions.ts
|
|
54086
54166
|
import { defineCommand as defineCommand84 } from "citty";
|
|
54087
|
-
function compactCustomConversion(
|
|
54167
|
+
function compactCustomConversion(row2) {
|
|
54088
54168
|
return {
|
|
54089
|
-
id:
|
|
54090
|
-
name:
|
|
54091
|
-
custom_event_type:
|
|
54092
|
-
counts:
|
|
54093
|
-
pixel_id:
|
|
54094
|
-
last_fired_time:
|
|
54095
|
-
...
|
|
54096
|
-
...
|
|
54169
|
+
id: row2.id,
|
|
54170
|
+
name: row2.name,
|
|
54171
|
+
custom_event_type: row2.custom_event_type,
|
|
54172
|
+
counts: row2.rule_summary,
|
|
54173
|
+
pixel_id: row2.pixel?.id,
|
|
54174
|
+
last_fired_time: row2.last_fired_time,
|
|
54175
|
+
...row2.is_archived ? { archived: true } : {},
|
|
54176
|
+
...row2.is_unavailable ? { unavailable: true } : {}
|
|
54097
54177
|
};
|
|
54098
54178
|
}
|
|
54099
54179
|
function customConversionHints(rows) {
|
|
@@ -54105,10 +54185,10 @@ function customConversionHints(rows) {
|
|
|
54105
54185
|
const hints2 = [
|
|
54106
54186
|
"To optimize an ad set toward one: `baker ads meta adsets create \u2026 --optimization-goal OFFSITE_CONVERSIONS --custom-conversion-id <id>`. Baker fills the pixel and the event category from the conversion \u2014 do not also pass --pixel-id or --custom-event-type."
|
|
54107
54187
|
];
|
|
54108
|
-
const neverFired = rows.filter((
|
|
54188
|
+
const neverFired = rows.filter((row2) => !row2.is_archived && !row2.last_fired_time);
|
|
54109
54189
|
if (neverFired.length > 0) {
|
|
54110
54190
|
hints2.push(
|
|
54111
|
-
`${neverFired.length === 1 ? "This conversion has" : `${neverFired.length} of these have`} never fired (${neverFired.map((
|
|
54191
|
+
`${neverFired.length === 1 ? "This conversion has" : `${neverFired.length} of these have`} never fired (${neverFired.map((row2) => row2.name ?? row2.id).join(
|
|
54112
54192
|
", "
|
|
54113
54193
|
)}). Meta cannot optimize toward an event it has never seen, so an ad set pointed at one delivers without learning \u2014 check the rule matches a page the site actually serves before spending on it.`
|
|
54114
54194
|
);
|
|
@@ -54146,7 +54226,7 @@ var listCommand10 = defineCommand84({
|
|
|
54146
54226
|
if (args8.limit) params.limit = args8.limit;
|
|
54147
54227
|
if (args8["no-cache"]) params["skip-cache"] = "true";
|
|
54148
54228
|
const rows = await apiGet("/api/ads/meta/custom-conversions", params);
|
|
54149
|
-
const data = args8.full ? rows.map((
|
|
54229
|
+
const data = args8.full ? rows.map((row2) => ({ ...row2 })) : rows.map((row2) => ({ ...compactCustomConversion(row2) }));
|
|
54150
54230
|
const fmt = csvOrJson(args8);
|
|
54151
54231
|
if (fmt !== "json") {
|
|
54152
54232
|
writeAdsOutput(data, fmt);
|
|
@@ -54406,16 +54486,16 @@ function sumActionValues(value2) {
|
|
|
54406
54486
|
function aggregate(rows) {
|
|
54407
54487
|
const byPlacement = /* @__PURE__ */ new Map();
|
|
54408
54488
|
let totalImpressions = 0;
|
|
54409
|
-
for (const
|
|
54410
|
-
const position =
|
|
54489
|
+
for (const row2 of rows) {
|
|
54490
|
+
const position = row2.platform_position;
|
|
54411
54491
|
if (typeof position !== "string" || position.length === 0) continue;
|
|
54412
|
-
const platform = typeof
|
|
54413
|
-
const impressions = toNumber(
|
|
54492
|
+
const platform = typeof row2.publisher_platform === "string" ? row2.publisher_platform : "";
|
|
54493
|
+
const impressions = toNumber(row2.impressions);
|
|
54414
54494
|
totalImpressions += impressions;
|
|
54415
54495
|
const key = `${platform}/${position}`;
|
|
54416
54496
|
const current = byPlacement.get(key) ?? { platform, position, impressions: 0, plays: 0, playRate: 0, share: 0 };
|
|
54417
54497
|
current.impressions += impressions;
|
|
54418
|
-
current.plays += sumActionValues(
|
|
54498
|
+
current.plays += sumActionValues(row2.video_play_actions);
|
|
54419
54499
|
byPlacement.set(key, current);
|
|
54420
54500
|
}
|
|
54421
54501
|
return [...byPlacement.values()].map((placement) => ({
|
|
@@ -54430,14 +54510,14 @@ function previewCommand(placement) {
|
|
|
54430
54510
|
}
|
|
54431
54511
|
function isSingleAdQuery(rows) {
|
|
54432
54512
|
const adIds = /* @__PURE__ */ new Set();
|
|
54433
|
-
for (const
|
|
54434
|
-
if (typeof
|
|
54435
|
-
adIds.add(
|
|
54513
|
+
for (const row2 of rows) {
|
|
54514
|
+
if (typeof row2.ad_id !== "string" || row2.ad_id.length === 0) return false;
|
|
54515
|
+
adIds.add(row2.ad_id);
|
|
54436
54516
|
}
|
|
54437
54517
|
return adIds.size === 1;
|
|
54438
54518
|
}
|
|
54439
54519
|
function placementDeliveryHints(rows) {
|
|
54440
|
-
const carriesVideoMetrics = rows.some((
|
|
54520
|
+
const carriesVideoMetrics = rows.some((row2) => Array.isArray(row2.video_play_actions));
|
|
54441
54521
|
if (!carriesVideoMetrics || !isSingleAdQuery(rows)) return [];
|
|
54442
54522
|
const placements = aggregate(rows);
|
|
54443
54523
|
const judgeable = placements.filter((p) => p.impressions >= MIN_IMPRESSIONS);
|
|
@@ -58335,7 +58415,7 @@ function forwarding() {
|
|
|
58335
58415
|
"| Field | Meta | Google | Held as |",
|
|
58336
58416
|
"| --- | --- | --- | --- |",
|
|
58337
58417
|
...MATCH_FIELD_FORWARDING.map(
|
|
58338
|
-
(
|
|
58418
|
+
(row2) => `| \`${row2.field}\` | \`${row2.meta}\` | ${row2.google === null ? "\u2014" : `\`${row2.google}\``} | ${row2.hashed ? "SHA-256" : "plain text"} |`
|
|
58339
58419
|
)
|
|
58340
58420
|
].join("\n");
|
|
58341
58421
|
}
|
|
@@ -58909,7 +58989,7 @@ function parseConversionsArgs(raw, argv) {
|
|
|
58909
58989
|
return args8;
|
|
58910
58990
|
}
|
|
58911
58991
|
function existingNames(existing) {
|
|
58912
|
-
return [...new Set(existing.map((
|
|
58992
|
+
return [...new Set(existing.map((row2) => row2.name))];
|
|
58913
58993
|
}
|
|
58914
58994
|
function checkNameCollision(name, existing) {
|
|
58915
58995
|
const collision = findNameCollision(name, existingNames(existing));
|
|
@@ -58919,7 +58999,7 @@ function checkNameCollision(name, existing) {
|
|
|
58919
58999
|
);
|
|
58920
59000
|
}
|
|
58921
59001
|
function under(name, existing) {
|
|
58922
|
-
const rows = existing.filter((
|
|
59002
|
+
const rows = existing.filter((row2) => row2.name === name);
|
|
58923
59003
|
if (rows.length === 0) {
|
|
58924
59004
|
throw new ConversionArgsError(
|
|
58925
59005
|
`Nothing is counted under "${name}". This company counts: ${existingNames(existing).join(", ") || "nothing yet"}.`
|
|
@@ -58939,7 +59019,7 @@ function setFromEvents(args8, existing) {
|
|
|
58939
59019
|
}));
|
|
58940
59020
|
}
|
|
58941
59021
|
return args8.eventKeys.map((eventKey) => {
|
|
58942
|
-
const current = existing.find((
|
|
59022
|
+
const current = existing.find((row2) => row2.eventKey === eventKey);
|
|
58943
59023
|
if (!current) {
|
|
58944
59024
|
throw new ConversionArgsError(
|
|
58945
59025
|
`"${eventKey}" is not counted, so there is no count mode to change. Add it with --event "${eventKey}" --name "<what a person calls it>" --count-mode ${args8.countMode}.`
|
|
@@ -58952,52 +59032,52 @@ function setFromRename(args8, existing) {
|
|
|
58952
59032
|
if (args8.renameFrom === void 0 || args8.renameTo === void 0) return [];
|
|
58953
59033
|
const renameTo = args8.renameTo;
|
|
58954
59034
|
checkNameCollision(renameTo, existing);
|
|
58955
|
-
return under(args8.renameFrom, existing).map((
|
|
58956
|
-
eventKey:
|
|
59035
|
+
return under(args8.renameFrom, existing).map((row2) => ({
|
|
59036
|
+
eventKey: row2.eventKey,
|
|
58957
59037
|
name: renameTo,
|
|
58958
|
-
countMode:
|
|
59038
|
+
countMode: row2.countMode
|
|
58959
59039
|
}));
|
|
58960
59040
|
}
|
|
58961
59041
|
function conversionsWrite(args8, existing) {
|
|
58962
59042
|
const set = [...setFromEvents(args8, existing), ...setFromRename(args8, existing)];
|
|
58963
59043
|
const remove = [
|
|
58964
59044
|
...args8.removeKeys,
|
|
58965
|
-
...args8.removeName === void 0 ? [] : under(args8.removeName, existing).map((
|
|
59045
|
+
...args8.removeName === void 0 ? [] : under(args8.removeName, existing).map((row2) => row2.eventKey)
|
|
58966
59046
|
];
|
|
58967
59047
|
if (set.length === 0 && remove.length === 0) return null;
|
|
58968
59048
|
return { ...set.length > 0 ? { set } : {}, ...remove.length > 0 ? { remove } : {} };
|
|
58969
59049
|
}
|
|
58970
59050
|
|
|
58971
59051
|
// src/commands/analytics/conversionCandidates.ts
|
|
58972
|
-
function compact3(
|
|
59052
|
+
function compact3(row2) {
|
|
58973
59053
|
return {
|
|
58974
|
-
eventKey:
|
|
58975
|
-
events:
|
|
58976
|
-
sessions:
|
|
58977
|
-
...
|
|
59054
|
+
eventKey: row2.eventKey,
|
|
59055
|
+
events: row2.events,
|
|
59056
|
+
sessions: row2.sessions,
|
|
59057
|
+
...row2.isCounted ? { countedAs: row2.countedAs } : {}
|
|
58978
59058
|
};
|
|
58979
59059
|
}
|
|
58980
59060
|
function foldByForm(rows) {
|
|
58981
59061
|
const byForm = /* @__PURE__ */ new Map();
|
|
58982
|
-
for (const
|
|
58983
|
-
const form = byForm.get(
|
|
59062
|
+
for (const row2 of rows) {
|
|
59063
|
+
const form = byForm.get(row2.flowSlug) ?? { form: row2.flowSlug, keys: 0, countedKeys: 0, events: 0 };
|
|
58984
59064
|
form.keys += 1;
|
|
58985
|
-
if (
|
|
58986
|
-
form.events +=
|
|
58987
|
-
byForm.set(
|
|
59065
|
+
if (row2.isCounted) form.countedKeys += 1;
|
|
59066
|
+
form.events += row2.events;
|
|
59067
|
+
byForm.set(row2.flowSlug, form);
|
|
58988
59068
|
}
|
|
58989
59069
|
return [...byForm.values()];
|
|
58990
59070
|
}
|
|
58991
59071
|
function candidatesForFlow(catalogue, flowSlug) {
|
|
58992
|
-
return flowSlug === void 0 ? [...catalogue] : catalogue.filter((
|
|
59072
|
+
return flowSlug === void 0 ? [...catalogue] : catalogue.filter((row2) => row2.flowSlug === flowSlug);
|
|
58993
59073
|
}
|
|
58994
59074
|
var FOLDED_FORMS_HINT = "A Form's candidates are folded into its `flows` row (`keys` fired, `events`; no `counted` means it counts nothing), or a `formCandidates` row when not listed. `--candidates --flow <slug>` lists that Form's keys; `--full` adds every field of every key.";
|
|
58995
59075
|
function candidatesView(rows, options) {
|
|
58996
59076
|
if (options.full) return { candidates: rows };
|
|
58997
59077
|
if (options.flowSlug !== void 0) return { candidates: rows.map(compact3) };
|
|
58998
|
-
const forms = foldByForm(rows.filter((
|
|
59078
|
+
const forms = foldByForm(rows.filter((row2) => row2.flowSlug !== ""));
|
|
58999
59079
|
return {
|
|
59000
|
-
candidates: rows.filter((
|
|
59080
|
+
candidates: rows.filter((row2) => row2.flowSlug === "").map(compact3),
|
|
59001
59081
|
...forms.length > 0 ? { formCandidates: forms } : {}
|
|
59002
59082
|
};
|
|
59003
59083
|
}
|
|
@@ -59043,24 +59123,24 @@ function conversionHints2(definitions, candidates, askedForCandidates) {
|
|
|
59043
59123
|
"Nothing is counted as a conversion, so EVERY conversion number in every other report is zero \u2014 whatever visitors actually did. Baker never guesses which event is the point of a page. Run `baker analytics conversions --candidates` to see what these pages produce, then count the ones that are worth money."
|
|
59044
59124
|
);
|
|
59045
59125
|
if (!askedForCandidates && candidates.length > 0) {
|
|
59046
|
-
const top = candidates.slice(0, NAMED_CANDIDATES).map((
|
|
59126
|
+
const top = candidates.slice(0, NAMED_CANDIDATES).map((row2) => row2.eventKey).join(", ");
|
|
59047
59127
|
hints2.push(`${candidates.length} distinct events are available to count. Busiest: ${top}.`);
|
|
59048
59128
|
}
|
|
59049
59129
|
return hints2;
|
|
59050
59130
|
}
|
|
59051
|
-
const silent = definitions.filter((
|
|
59131
|
+
const silent = definitions.filter((row2) => row2.lastSeen === null);
|
|
59052
59132
|
if (silent.length > 0) {
|
|
59053
59133
|
hints2.push(
|
|
59054
|
-
`${silent.length} counted outcome(s) have never fired in this window: ${silent.slice(0, NAMED_CANDIDATES).map((
|
|
59134
|
+
`${silent.length} counted outcome(s) have never fired in this window: ${silent.slice(0, NAMED_CANDIDATES).map((row2) => row2.name).join(
|
|
59055
59135
|
", "
|
|
59056
59136
|
)}. Either the page never reaches them, or the wrong event was named \u2014 check against --candidates before reporting a conversion rate.`
|
|
59057
59137
|
);
|
|
59058
59138
|
}
|
|
59059
|
-
const uncounted = candidates.filter((
|
|
59139
|
+
const uncounted = candidates.filter((row2) => !row2.isCounted);
|
|
59060
59140
|
const busiest = uncounted[0];
|
|
59061
59141
|
if (busiest && busiest.sessions > 0) {
|
|
59062
|
-
const counted = candidates.filter((
|
|
59063
|
-
const busiestCounted = counted.reduce((max,
|
|
59142
|
+
const counted = candidates.filter((row2) => row2.isCounted);
|
|
59143
|
+
const busiestCounted = counted.reduce((max, row2) => Math.max(max, row2.sessions), 0);
|
|
59064
59144
|
if (busiest.sessions > busiestCounted) {
|
|
59065
59145
|
hints2.push(
|
|
59066
59146
|
`\`${busiest.eventKey}\` happened in ${busiest.sessions} visits and is not counted \u2014 more than anything that is. Check it is not the real outcome.`
|
|
@@ -59070,7 +59150,7 @@ function conversionHints2(definitions, candidates, askedForCandidates) {
|
|
|
59070
59150
|
return hints2;
|
|
59071
59151
|
}
|
|
59072
59152
|
function namingHints(definitions) {
|
|
59073
|
-
const names = [...new Set(definitions.map((
|
|
59153
|
+
const names = [...new Set(definitions.map((row2) => row2.name))];
|
|
59074
59154
|
if (names.length === 0) {
|
|
59075
59155
|
return [
|
|
59076
59156
|
`Nothing is named yet, so the first name sets the vocabulary for this company. Start from the standard set \u2014 ${STANDARD_CONVERSION_NAMES.map((entry) => entry.name).join(", ")} \u2014 and stay in the company's own language once one exists.`
|
|
@@ -59081,29 +59161,29 @@ function namingHints(definitions) {
|
|
|
59081
59161
|
];
|
|
59082
59162
|
}
|
|
59083
59163
|
function stagedHints(definitions) {
|
|
59084
|
-
const staged = definitions.filter((
|
|
59164
|
+
const staged = definitions.filter((row2) => row2.staged === true);
|
|
59085
59165
|
if (staged.length === 0) return [];
|
|
59086
59166
|
return [
|
|
59087
|
-
`Staged on this chat, not counted yet: ${staged.map((
|
|
59167
|
+
`Staged on this chat, not counted yet: ${staged.map((row2) => `"${row2.name}"`).join(", ")}. The person sees ${staged.length === 1 ? "it" : "them"} under Sources in the chat's changes, on the event's own row, and ${staged.length === 1 ? "it counts" : "they count"} from when they publish the chat; discarding the chat drops ${staged.length === 1 ? "it" : "them"}. Publishing also rescores events Baker ALREADY RECORDED under the key \u2014 never anything that happened in HubSpot or elsewhere before the event existed, so an event this chat just made starts at zero. Tell them that, not that it is already counted.`,
|
|
59088
59168
|
'When you talk to the person, call each event by its name ("Appointment scheduled"), never its key (`page:Appointment scheduled`): the key is how Baker spells it internally, and the `page:` part means nothing to them.'
|
|
59089
59169
|
];
|
|
59090
59170
|
}
|
|
59091
59171
|
|
|
59092
59172
|
// src/commands/analytics/conversionList.ts
|
|
59093
59173
|
function mergeStoredWithCounts(stored, reported) {
|
|
59094
|
-
const counts = new Map(reported.map((
|
|
59174
|
+
const counts = new Map(reported.map((row2) => [row2.name, row2]));
|
|
59095
59175
|
const groups = /* @__PURE__ */ new Map();
|
|
59096
|
-
for (const
|
|
59097
|
-
const group = groups.get(
|
|
59098
|
-
group.push(
|
|
59099
|
-
groups.set(
|
|
59176
|
+
for (const row2 of stored) {
|
|
59177
|
+
const group = groups.get(row2.name) ?? [];
|
|
59178
|
+
group.push(row2);
|
|
59179
|
+
groups.set(row2.name, group);
|
|
59100
59180
|
}
|
|
59101
59181
|
return [...groups.entries()].map(([name, rows]) => {
|
|
59102
|
-
const modes = new Set(rows.map((
|
|
59182
|
+
const modes = new Set(rows.map((row2) => row2.countMode));
|
|
59103
59183
|
const counted = counts.get(name);
|
|
59104
59184
|
return {
|
|
59105
59185
|
name,
|
|
59106
|
-
eventKeys: rows.map((
|
|
59186
|
+
eventKeys: rows.map((row2) => row2.eventKey).sort(),
|
|
59107
59187
|
// A real state and usually an editing accident, which is why it is said
|
|
59108
59188
|
// out loud rather than resolved to one of them.
|
|
59109
59189
|
countMode: modes.size === 1 ? [...modes][0] : "mixed",
|
|
@@ -59115,7 +59195,7 @@ function mergeStoredWithCounts(stored, reported) {
|
|
|
59115
59195
|
unplaced: counted?.unplaced ?? 0,
|
|
59116
59196
|
lastSeen: counted?.lastSeen ?? null,
|
|
59117
59197
|
doors: counted?.doors ?? [],
|
|
59118
|
-
...rows.some((
|
|
59198
|
+
...rows.some((row2) => row2.staged === true) ? { staged: true } : {}
|
|
59119
59199
|
};
|
|
59120
59200
|
}).sort((a, b) => a.name.localeCompare(b.name));
|
|
59121
59201
|
}
|
|
@@ -59152,9 +59232,9 @@ function pruneValue(value2, full) {
|
|
|
59152
59232
|
}
|
|
59153
59233
|
return value2;
|
|
59154
59234
|
}
|
|
59155
|
-
function pruneRow(
|
|
59235
|
+
function pruneRow(row2, full) {
|
|
59156
59236
|
const out = {};
|
|
59157
|
-
for (const [key, value2] of Object.entries(
|
|
59237
|
+
for (const [key, value2] of Object.entries(row2)) {
|
|
59158
59238
|
if (DASHBOARD_ONLY_FIELDS.has(key)) continue;
|
|
59159
59239
|
if (key === "sparkline" && Array.isArray(value2)) {
|
|
59160
59240
|
if (!full) continue;
|
|
@@ -59171,7 +59251,7 @@ function pruneForAgent(data, full) {
|
|
|
59171
59251
|
}
|
|
59172
59252
|
function isTabular(rows) {
|
|
59173
59253
|
return rows.every(
|
|
59174
|
-
(
|
|
59254
|
+
(row2) => typeof row2 === "object" && row2 !== null && !Array.isArray(row2) && Object.values(row2).every(
|
|
59175
59255
|
(value2) => value2 === null || typeof value2 !== "object" || Array.isArray(value2) && value2.every((e) => typeof e !== "object")
|
|
59176
59256
|
)
|
|
59177
59257
|
);
|
|
@@ -59225,40 +59305,40 @@ function byBlockOrder(a, b) {
|
|
|
59225
59305
|
}
|
|
59226
59306
|
function columnsOf(rows) {
|
|
59227
59307
|
const seen = [];
|
|
59228
|
-
for (const
|
|
59229
|
-
for (const key of Object.keys(
|
|
59308
|
+
for (const row2 of rows) {
|
|
59309
|
+
for (const key of Object.keys(row2)) {
|
|
59230
59310
|
if (!seen.includes(key)) seen.push(key);
|
|
59231
59311
|
}
|
|
59232
59312
|
}
|
|
59233
|
-
return seen.filter((key) => rows.some((
|
|
59313
|
+
return seen.filter((key) => rows.some((row2) => !isAbsent(row2[key]) && row2[key] !== null && row2[key] !== void 0)).sort(byIdentityFirst);
|
|
59234
59314
|
}
|
|
59235
59315
|
function table2(rows) {
|
|
59236
59316
|
const cols = columnsOf(rows);
|
|
59237
59317
|
if (cols.length === 0) return "";
|
|
59238
59318
|
const head = `| ${cols.join(" | ")} |`;
|
|
59239
59319
|
const rule = `| ${cols.map(() => "---").join(" | ")} |`;
|
|
59240
|
-
const body = rows.map((
|
|
59320
|
+
const body = rows.map((row2) => `| ${cols.map((col) => cell2(row2[col], col)).join(" | ")} |`);
|
|
59241
59321
|
return [head, rule, ...body].join("\n");
|
|
59242
59322
|
}
|
|
59243
59323
|
function isRowList(value2) {
|
|
59244
59324
|
return Array.isArray(value2) && value2.length > 0 && value2.every((entry) => typeof entry === "object" && entry !== null && !Array.isArray(entry));
|
|
59245
59325
|
}
|
|
59246
|
-
function labelOf(
|
|
59326
|
+
function labelOf(row2, index) {
|
|
59247
59327
|
for (const key of IDENTITY_COLUMNS) {
|
|
59248
|
-
const value2 =
|
|
59328
|
+
const value2 = row2[key];
|
|
59249
59329
|
if (typeof value2 === "string" && value2 !== "") return value2;
|
|
59250
59330
|
}
|
|
59251
59331
|
return `#${index + 1}`;
|
|
59252
59332
|
}
|
|
59253
59333
|
function nestedBlock(name, rows) {
|
|
59254
59334
|
const parents = rows.map(
|
|
59255
|
-
(
|
|
59335
|
+
(row2) => Object.fromEntries(Object.entries(row2).filter(([, value2]) => !isRowList(value2) && !isPlainRow(value2)))
|
|
59256
59336
|
);
|
|
59257
59337
|
const parts = [`### ${name}`, table2(parents)];
|
|
59258
|
-
rows.forEach((
|
|
59259
|
-
for (const [key, value2] of Object.entries(
|
|
59260
|
-
if (isRowList(value2)) parts.push(`#### ${name}[${labelOf(
|
|
59261
|
-
else if (isPlainRow(value2)) parts.push(`#### ${name}[${labelOf(
|
|
59338
|
+
rows.forEach((row2, index) => {
|
|
59339
|
+
for (const [key, value2] of Object.entries(row2)) {
|
|
59340
|
+
if (isRowList(value2)) parts.push(`#### ${name}[${labelOf(row2, index)}].${key}`, table2(value2));
|
|
59341
|
+
else if (isPlainRow(value2)) parts.push(`#### ${name}[${labelOf(row2, index)}].${key}`, table2([value2]));
|
|
59262
59342
|
}
|
|
59263
59343
|
});
|
|
59264
59344
|
return parts.filter((part) => part !== "").join("\n");
|
|
@@ -59303,7 +59383,7 @@ function missingBreakdownHint(data, asked) {
|
|
|
59303
59383
|
if (asked.eventName === void 0) return [];
|
|
59304
59384
|
const breakdown = data.eventBreakdown;
|
|
59305
59385
|
if (Array.isArray(breakdown) && breakdown.length > 0) return [];
|
|
59306
|
-
const known = Array.isArray(data.customEvents) ? data.customEvents.flatMap((
|
|
59386
|
+
const known = Array.isArray(data.customEvents) ? data.customEvents.flatMap((row2) => isPlainRow(row2) && typeof row2.eventName === "string" ? [row2.eventName] : []) : [];
|
|
59307
59387
|
return [
|
|
59308
59388
|
`No rows came back for --event ${asked.eventName}${asked.property ? ` --property ${asked.property}` : ""}. That event or property does not exist on these pages${known.length > 0 ? `; the ones that do are: ${known.slice(0, 12).join(", ")}${known.length > 12 ? ", \u2026" : ""}` : ""}.`
|
|
59309
59389
|
];
|
|
@@ -59348,13 +59428,13 @@ function eventKeysCell(eventKeys) {
|
|
|
59348
59428
|
}
|
|
59349
59429
|
function trafficByForm(candidates) {
|
|
59350
59430
|
const byForm = /* @__PURE__ */ new Map();
|
|
59351
|
-
for (const
|
|
59352
|
-
const form = byForm.get(
|
|
59353
|
-
if (
|
|
59354
|
-
if (
|
|
59355
|
-
form.events +=
|
|
59356
|
-
if (
|
|
59357
|
-
byForm.set(
|
|
59431
|
+
for (const row2 of candidates) {
|
|
59432
|
+
const form = byForm.get(row2.flowSlug) ?? { "endings seen": 0, "endings counted": 0, events: 0, lastSeen: "" };
|
|
59433
|
+
if (row2.events > 0) form["endings seen"] += 1;
|
|
59434
|
+
if (row2.isCounted) form["endings counted"] += 1;
|
|
59435
|
+
form.events += row2.events;
|
|
59436
|
+
if (row2.lastSeen && row2.lastSeen.slice(0, 10) > form.lastSeen) form.lastSeen = row2.lastSeen.slice(0, 10);
|
|
59437
|
+
byForm.set(row2.flowSlug, form);
|
|
59358
59438
|
}
|
|
59359
59439
|
return byForm;
|
|
59360
59440
|
}
|
|
@@ -59363,32 +59443,32 @@ var FORM_KEYS_HINT = "A Form's candidates are one row per Form: `baker analytics
|
|
|
59363
59443
|
function renderConversionsMarkdown(envelope) {
|
|
59364
59444
|
const { definitions, flow, flows, candidates } = envelope.data;
|
|
59365
59445
|
const data = {
|
|
59366
|
-
definitions: definitions.map(({ name, eventKeys, ...
|
|
59446
|
+
definitions: definitions.map(({ name, eventKeys, ...row2 }) => ({
|
|
59367
59447
|
name,
|
|
59368
59448
|
eventKeys: eventKeysCell(eventKeys),
|
|
59369
|
-
...
|
|
59449
|
+
...row2
|
|
59370
59450
|
}))
|
|
59371
59451
|
};
|
|
59372
59452
|
if (flow) {
|
|
59373
59453
|
data.flow = { slug: flow.slug, noConversionReason: flow.noConversionReason };
|
|
59374
59454
|
data.flowEndings = flow.endings;
|
|
59375
59455
|
}
|
|
59376
|
-
const traffic = candidates ? trafficByForm(candidates.filter((
|
|
59456
|
+
const traffic = candidates ? trafficByForm(candidates.filter((row2) => row2.flowSlug !== "")) : /* @__PURE__ */ new Map();
|
|
59377
59457
|
if (flows) {
|
|
59378
|
-
data.flows = flows.map((
|
|
59379
|
-
slug:
|
|
59380
|
-
counted:
|
|
59381
|
-
noConversion:
|
|
59382
|
-
...candidates ? traffic.get(
|
|
59458
|
+
data.flows = flows.map((row2) => ({
|
|
59459
|
+
slug: row2.slug,
|
|
59460
|
+
counted: row2.counted.map((entry) => `${entry.name} @ ${entry.step}`).join("; "),
|
|
59461
|
+
noConversion: row2.noConversion,
|
|
59462
|
+
...candidates ? traffic.get(row2.slug) ?? NO_TRAFFIC : {}
|
|
59383
59463
|
}));
|
|
59384
59464
|
}
|
|
59385
59465
|
const hints2 = [...envelope.hints ?? []];
|
|
59386
59466
|
if (candidates) {
|
|
59387
|
-
const listed2 = new Set(flows?.map((
|
|
59467
|
+
const listed2 = new Set(flows?.map((row2) => row2.slug));
|
|
59388
59468
|
const unlisted = [...traffic].filter(([slug]) => !listed2.has(slug));
|
|
59389
|
-
if (unlisted.length > 0) data.formCandidates = unlisted.map(([form,
|
|
59390
|
-
data.candidates = candidates.filter((
|
|
59391
|
-
...
|
|
59469
|
+
if (unlisted.length > 0) data.formCandidates = unlisted.map(([form, row2]) => ({ form, ...row2 }));
|
|
59470
|
+
data.candidates = candidates.filter((row2) => row2.flowSlug === "").map(({ doors, flowSlug: _flowSlug, nodeType: _nodeType, ...row2 }) => ({
|
|
59471
|
+
...row2,
|
|
59392
59472
|
"doors (events/sessions)": doorsCell(doors)
|
|
59393
59473
|
}));
|
|
59394
59474
|
if (traffic.size > 0) hints2.push(FORM_KEYS_HINT);
|
|
@@ -59412,18 +59492,18 @@ function analyticsErrorEnvelope(err) {
|
|
|
59412
59492
|
function isStreamRow(value2) {
|
|
59413
59493
|
return typeof value2 === "object" && value2 !== null && !Array.isArray(value2);
|
|
59414
59494
|
}
|
|
59415
|
-
function enrich(
|
|
59416
|
-
const out = { ...
|
|
59417
|
-
const destination = typeof
|
|
59495
|
+
function enrich(row2) {
|
|
59496
|
+
const out = { ...row2 };
|
|
59497
|
+
const destination = typeof row2.sideEffectType === "string" ? row2.sideEffectType : "";
|
|
59418
59498
|
if (destination !== "") out.destination = destinationName(destination);
|
|
59419
|
-
const keys = rowMatchKeys(
|
|
59499
|
+
const keys = rowMatchKeys(row2.userData);
|
|
59420
59500
|
if (keys.length > 0) out.matchedBy = keys.map((key) => key.field);
|
|
59421
59501
|
return out;
|
|
59422
59502
|
}
|
|
59423
59503
|
function shapeFeed(stream, everything) {
|
|
59424
59504
|
if (!Array.isArray(stream)) return { rows: [], heldBack: 0 };
|
|
59425
59505
|
const rows = stream.filter(isStreamRow);
|
|
59426
|
-
const kept = everything ? rows : rows.filter((
|
|
59506
|
+
const kept = everything ? rows : rows.filter((row2) => !isBookkeepingRow({ eventType: row2.eventType ?? "", triggerId: row2.triggerId ?? "" }));
|
|
59427
59507
|
return { rows: kept.map(enrich), heldBack: rows.length - kept.length };
|
|
59428
59508
|
}
|
|
59429
59509
|
function feedHints(shape) {
|
|
@@ -59433,7 +59513,7 @@ function feedHints(shape) {
|
|
|
59433
59513
|
`${shape.heldBack} ${shape.heldBack === 1 ? "row is" : "rows are"} not listed: rows recorded to work the reports out \u2014 identifications, step views, session starts, a destination's answer already folded onto its dispatch \u2014 and embedded forms and calendars announcing that they drew. Add --everything to see them.`
|
|
59434
59514
|
);
|
|
59435
59515
|
}
|
|
59436
|
-
const upload = shape.rows.find((
|
|
59516
|
+
const upload = shape.rows.find((row2) => row2.sideEffectType !== void 0 && row2.eventId !== void 0);
|
|
59437
59517
|
if (upload !== void 0) {
|
|
59438
59518
|
hints2.push(
|
|
59439
59519
|
`A delivery row carries the event it was made for in \`eventId\`. \`baker analytics feed --uid ${String(upload.eventId)}\` returns that event and every upload made for it, each with the platform's verdict.`
|
|
@@ -59442,7 +59522,7 @@ function feedHints(shape) {
|
|
|
59442
59522
|
return hints2;
|
|
59443
59523
|
}
|
|
59444
59524
|
function peopleSearchHints(search, rows) {
|
|
59445
|
-
const found = new Set(rows.flatMap((
|
|
59525
|
+
const found = new Set(rows.flatMap((row2) => Array.isArray(row2.personTerms) ? row2.personTerms : []));
|
|
59446
59526
|
return search.filter((term) => !found.has(term.term)).map(
|
|
59447
59527
|
(term) => term.problem !== "" ? `${term.input}: ${term.problem}` : `${term.input}: nothing in this window on this page. \`baker analytics lookup --person '${term.input}'\` reads everything Baker ever saw of them.`
|
|
59448
59528
|
);
|
|
@@ -59474,10 +59554,10 @@ function joinFlowConversions(candidates, definitions) {
|
|
|
59474
59554
|
return candidates.map((candidate) => ({ ...candidate, countedAs: byKey.get(candidate.eventKey) ?? null }));
|
|
59475
59555
|
}
|
|
59476
59556
|
function flowConversionHints(slug, rows, noConversionReason) {
|
|
59477
|
-
const counted = rows.filter((
|
|
59557
|
+
const counted = rows.filter((row2) => row2.countedAs !== null);
|
|
59478
59558
|
if (counted.length > 0) {
|
|
59479
59559
|
return [
|
|
59480
|
-
`Baker counts ${counted.length} of this Form's endings: ${counted.map((
|
|
59560
|
+
`Baker counts ${counted.length} of this Form's endings: ${counted.map((row2) => `${row2.countedAs} (${row2.nodeName})`).join(
|
|
59481
59561
|
", "
|
|
59482
59562
|
)}. Every other ending here scores nothing \u2014 count another with \`--event <key> --name <outcome>\`, reusing the SAME name to make two Forms one number.`
|
|
59483
59563
|
];
|
|
@@ -59499,21 +59579,21 @@ function flowCoverage(forms, definitions) {
|
|
|
59499
59579
|
const seen = /* @__PURE__ */ new Set();
|
|
59500
59580
|
return {
|
|
59501
59581
|
slug,
|
|
59502
|
-
counted: rows.filter((
|
|
59503
|
-
const key = `${
|
|
59582
|
+
counted: rows.filter((row2) => row2.countedAs !== null).filter((row2) => {
|
|
59583
|
+
const key = `${row2.countedAs} ${row2.nodeName}`;
|
|
59504
59584
|
if (seen.has(key)) return false;
|
|
59505
59585
|
seen.add(key);
|
|
59506
59586
|
return true;
|
|
59507
|
-
}).map((
|
|
59587
|
+
}).map((row2) => ({ name: String(row2.countedAs), step: row2.nodeName })),
|
|
59508
59588
|
noConversion: typeof declared === "string" && declared.trim() !== "" ? declared.trim() : null
|
|
59509
59589
|
};
|
|
59510
59590
|
});
|
|
59511
59591
|
}
|
|
59512
59592
|
function flowCoverageHints(coverage) {
|
|
59513
|
-
const unset = coverage.filter((
|
|
59593
|
+
const unset = coverage.filter((row2) => row2.counted.length === 0 && row2.noConversion === null);
|
|
59514
59594
|
if (unset.length === 0) return [];
|
|
59515
59595
|
return [
|
|
59516
|
-
`${unset.length} of ${coverage.length} Form(s) here count nothing, so every report shows them converting nobody: ${unset.map((
|
|
59596
|
+
`${unset.length} of ${coverage.length} Form(s) here count nothing, so every report shows them converting nobody: ${unset.map((row2) => row2.slug).join(
|
|
59517
59597
|
", "
|
|
59518
59598
|
)}. Read each one's endings with \`baker analytics conversions --flow <slug>\` and name the outcome, or declare on its first step why it has none.`
|
|
59519
59599
|
];
|
|
@@ -59542,9 +59622,9 @@ function shapeHints(data) {
|
|
|
59542
59622
|
);
|
|
59543
59623
|
}
|
|
59544
59624
|
}
|
|
59545
|
-
const unread = (data.adParams ?? []).filter((
|
|
59625
|
+
const unread = (data.adParams ?? []).filter((row2) => row2.role === void 0 && row2.sessions > 0);
|
|
59546
59626
|
if (unread.length > 0) {
|
|
59547
|
-
const named = unread.slice(0, 8).map((
|
|
59627
|
+
const named = unread.slice(0, 8).map((row2) => `${row2.name} (${row2.sessions} visits)`).join(", ");
|
|
59548
59628
|
hints2.push(
|
|
59549
59629
|
`Nothing reads these parameters yet: ${named}${unread.length > 8 ? ", \u2026" : ""}. Their values are not being stored \u2014 only the fact that the name appeared \u2014 so any breakdown over them is empty rather than wrong. Name each one with \`baker analytics map --platform <platform> --set <name>=<role>\`; mapping also fixes the history for a parameter Baker was already capturing.`
|
|
59550
59630
|
);
|
|
@@ -59552,7 +59632,7 @@ function shapeHints(data) {
|
|
|
59552
59632
|
const unplaceable = data.adParamsUnattributed ?? [];
|
|
59553
59633
|
if (unplaceable.length > 0) {
|
|
59554
59634
|
hints2.push(
|
|
59555
|
-
`Some parameters arrive on visits with no click id and no recognised source, so no platform can be named for them: ${unplaceable.map((
|
|
59635
|
+
`Some parameters arrive on visits with no click id and no recognised source, so no platform can be named for them: ${unplaceable.map((row2) => row2.name).join(", ")}. If you know where they come from, map them with --platform on that platform.`
|
|
59556
59636
|
);
|
|
59557
59637
|
}
|
|
59558
59638
|
return hints2;
|
|
@@ -59563,7 +59643,7 @@ function adHierarchyHints(data, platform) {
|
|
|
59563
59643
|
if (traffic === void 0 || traffic.sessions < MIN_SESSIONS_FOR_TAGGING_CLAIM) return [];
|
|
59564
59644
|
if (traffic.taggedSessions === 0) return [];
|
|
59565
59645
|
const carried = new Set(
|
|
59566
|
-
(data.adParams ?? []).filter((
|
|
59646
|
+
(data.adParams ?? []).filter((row2) => row2.role !== void 0 && row2.awaitingTraffic !== true).map((row2) => row2.role)
|
|
59567
59647
|
);
|
|
59568
59648
|
const missing = essentialAdDimensions(platform).filter((entry) => !carried.has(entry.role));
|
|
59569
59649
|
if (missing.length === 0) return [];
|
|
@@ -59631,7 +59711,7 @@ function buildAnalyticsHints(data, platform, origin) {
|
|
|
59631
59711
|
}
|
|
59632
59712
|
function campaignOriginHints(rows) {
|
|
59633
59713
|
const campaigns = rows ?? [];
|
|
59634
|
-
const fromAds = campaigns.filter((
|
|
59714
|
+
const fromAds = campaigns.filter((row2) => row2.clickPlatform !== "");
|
|
59635
59715
|
if (fromAds.length === 0) return [];
|
|
59636
59716
|
const own = campaigns.length - fromAds.length;
|
|
59637
59717
|
return [
|
|
@@ -59675,28 +59755,28 @@ function peopleLimitError(args8) {
|
|
|
59675
59755
|
if (dropped === 0) return void 0;
|
|
59676
59756
|
return `${terms.length + dropped} people named; one search takes up to ${PEOPLE_SEARCH_MAX_TERMS}. Split the list and run each part.`;
|
|
59677
59757
|
}
|
|
59678
|
-
function compactRow2(
|
|
59679
|
-
const clicks = [...
|
|
59758
|
+
function compactRow2(row2) {
|
|
59759
|
+
const clicks = [...row2.googleClick ? ["google"] : [], ...row2.metaClick ? ["meta"] : []];
|
|
59680
59760
|
const candidates = {
|
|
59681
|
-
input:
|
|
59682
|
-
readAs:
|
|
59683
|
-
found:
|
|
59684
|
-
problem:
|
|
59685
|
-
contacts:
|
|
59686
|
-
events:
|
|
59687
|
-
firstSeen:
|
|
59688
|
-
lastSeen:
|
|
59689
|
-
pageViews:
|
|
59690
|
-
landings:
|
|
59691
|
-
visits:
|
|
59692
|
-
formSubmits:
|
|
59693
|
-
firstSource:
|
|
59694
|
-
systemEvents:
|
|
59695
|
-
pageEvents:
|
|
59696
|
-
uploads:
|
|
59697
|
-
uploadedTo:
|
|
59761
|
+
input: row2.input,
|
|
59762
|
+
readAs: row2.kind,
|
|
59763
|
+
found: row2.found,
|
|
59764
|
+
problem: row2.problem,
|
|
59765
|
+
contacts: row2.contacts,
|
|
59766
|
+
events: row2.events,
|
|
59767
|
+
firstSeen: row2.firstSeen,
|
|
59768
|
+
lastSeen: row2.lastSeen,
|
|
59769
|
+
pageViews: row2.pageViews,
|
|
59770
|
+
landings: row2.landings,
|
|
59771
|
+
visits: row2.visits,
|
|
59772
|
+
formSubmits: row2.formSubmits,
|
|
59773
|
+
firstSource: row2.firstSource,
|
|
59774
|
+
systemEvents: row2.systemEvents,
|
|
59775
|
+
pageEvents: row2.pageEvents,
|
|
59776
|
+
uploads: row2.uploads,
|
|
59777
|
+
uploadedTo: row2.uploadedTo,
|
|
59698
59778
|
clicks,
|
|
59699
|
-
knownBy:
|
|
59779
|
+
knownBy: row2.knownBy
|
|
59700
59780
|
};
|
|
59701
59781
|
return Object.fromEntries(
|
|
59702
59782
|
Object.entries(candidates).filter(
|
|
@@ -59711,17 +59791,17 @@ function lookupHints(data) {
|
|
|
59711
59791
|
`${data.dropped} lines past the limit of ${PEOPLE_SEARCH_MAX_TERMS} were not looked up. Run the rest separately.`
|
|
59712
59792
|
);
|
|
59713
59793
|
}
|
|
59714
|
-
const unseen = data.people.filter((
|
|
59794
|
+
const unseen = data.people.filter((row2) => !row2.found && row2.problem === "");
|
|
59715
59795
|
if (unseen.length > 0) {
|
|
59716
59796
|
hints2.push(
|
|
59717
|
-
`Not seen by Baker: ${unseen.map((
|
|
59797
|
+
`Not seen by Baker: ${unseen.map((row2) => row2.input).join(", ")}. Baker knows a person by what its pages, Forms and connected systems recorded \u2014 a lead that came in through a form or site Baker does not measure, or a source not connected, is not here.`
|
|
59718
59798
|
);
|
|
59719
59799
|
}
|
|
59720
|
-
for (const
|
|
59721
|
-
hints2.push(`${
|
|
59800
|
+
for (const row2 of data.people.filter((person) => person.problem !== "")) {
|
|
59801
|
+
hints2.push(`${row2.input}: ${row2.problem}`);
|
|
59722
59802
|
}
|
|
59723
|
-
const found = data.people.filter((
|
|
59724
|
-
const neverVisited = found.filter((
|
|
59803
|
+
const found = data.people.filter((row2) => row2.found);
|
|
59804
|
+
const neverVisited = found.filter((row2) => row2.pageViews === 0);
|
|
59725
59805
|
if (neverVisited.length > 0) {
|
|
59726
59806
|
hints2.push(
|
|
59727
59807
|
`${neverVisited.length} of ${found.length} found never visited a page Baker publishes: Baker knows them only from what their systems reported, so no landing can be credited with them.`
|
|
@@ -59735,13 +59815,13 @@ function lookupHints(data) {
|
|
|
59735
59815
|
return hints2;
|
|
59736
59816
|
}
|
|
59737
59817
|
function lookupReport(data, full = false) {
|
|
59738
|
-
const found = data.people.filter((
|
|
59818
|
+
const found = data.people.filter((row2) => row2.found);
|
|
59739
59819
|
return {
|
|
59740
59820
|
summary: {
|
|
59741
59821
|
searched: data.people.length,
|
|
59742
59822
|
found: found.length,
|
|
59743
59823
|
notFound: data.people.length - found.length,
|
|
59744
|
-
visitedABakerPage: found.filter((
|
|
59824
|
+
visitedABakerPage: found.filter((row2) => row2.pageViews > 0).length
|
|
59745
59825
|
},
|
|
59746
59826
|
people: full ? data.people : data.people.map(compactRow2),
|
|
59747
59827
|
hints: lookupHints(data)
|
|
@@ -60216,9 +60296,9 @@ var SOURCE_NAME_MAX = 80;
|
|
|
60216
60296
|
var sourceNameSchema = z49.string().trim().min(1).max(SOURCE_NAME_MAX).refine((name) => validateEventName(name) === null, REJECTION_MESSAGES.invalid_name);
|
|
60217
60297
|
var sourceIdSchema = z49.string().min(1);
|
|
60218
60298
|
var sourceMappingSchema = z49.record(z49.string(), z49.string().min(1)).superRefine((mapping, ctx) => {
|
|
60219
|
-
for (const
|
|
60220
|
-
const problem = mappingRowProblem(
|
|
60221
|
-
if (problem !== null) ctx.addIssue({ code: "custom", message: problem, path: [
|
|
60299
|
+
for (const row2 of Object.keys(mapping)) {
|
|
60300
|
+
const problem = mappingRowProblem(row2);
|
|
60301
|
+
if (problem !== null) ctx.addIssue({ code: "custom", message: problem, path: [row2] });
|
|
60222
60302
|
}
|
|
60223
60303
|
});
|
|
60224
60304
|
var currencyCodeSchema = z49.string().trim().toUpperCase().regex(/^[A-Z]{3}$/, "A currency is a three-letter code, like EUR or USD.");
|
|
@@ -77167,43 +77247,43 @@ var experimentFinishResponseSchema = z62.object({
|
|
|
77167
77247
|
|
|
77168
77248
|
// src/commands/experiment/hints.ts
|
|
77169
77249
|
var LIVE_HINT = {
|
|
77170
|
-
keep_running: (
|
|
77171
|
-
winner: (
|
|
77172
|
-
no_difference: (
|
|
77173
|
-
cannot_win: (
|
|
77174
|
-
stopped_early_harmful: (
|
|
77250
|
+
keep_running: (row2, now) => `${row2.experimentId} cannot yet tell the two pages apart \u2014 do not end it hoping for a result. ${describeWait2(row2, now)} To the user, say only this in plain words: "${row2.summary}" plus how much more data it needs and roughly when. Never quote confidence, chance-better or intervals to them \u2014 those numbers confuse marketers and decide nothing.`,
|
|
77251
|
+
winner: (row2) => row2.winner === "variant" ? `${row2.experimentId} has a winner: the new variant. Run \`baker experiment finish --id ${row2.experimentId} --keep variant\` to show it to everyone, then \`baker experiment fold\`.` : `${row2.experimentId}: the new version is proven worse and is STILL being shown to half the visitors. Run \`baker experiment finish --id ${row2.experimentId} --keep original\` now.`,
|
|
77252
|
+
no_difference: (row2) => `${row2.experimentId} measured the two pages as alike \u2014 it collected enough traffic to see the change it was looking for, and there was none. End it with \`--keep original\` and test a bigger change \u2014 a headline, an offer, the shape of the page, not a button colour.`,
|
|
77253
|
+
cannot_win: (row2) => `${row2.experimentId}: the new version cannot win \u2014 even its best case is under the lift this test was looking for, so there is nothing left to find. Run \`baker experiment finish --id ${row2.experimentId} --keep original --reason numbers_clear\` and write down what it taught.`,
|
|
77254
|
+
stopped_early_harmful: (row2) => `${row2.experimentId} is doing damage and is STILL being shown to visitors. Run \`baker experiment finish --id ${row2.experimentId} --keep original\` now.`,
|
|
77175
77255
|
// Unreachable on a live test — only ending one produces it. The Record is
|
|
77176
77256
|
// exhaustive by type so a verdict added upstream fails to compile here rather
|
|
77177
77257
|
// than printing nothing.
|
|
77178
|
-
inconclusive: (
|
|
77179
|
-
invalid: (
|
|
77258
|
+
inconclusive: (row2) => `${row2.experimentId} was ended before it concluded and found nothing.`,
|
|
77259
|
+
invalid: (row2) => `${row2.experimentId} cannot be read: ${row2.invalidReason === "crossover" ? "too many visitors saw both versions" : "the traffic did not split evenly"}. End it with \`--keep original\` and start again rather than reporting anything from it.`
|
|
77180
77260
|
};
|
|
77181
|
-
function describeWait2(
|
|
77182
|
-
if (
|
|
77261
|
+
function describeWait2(row2, now) {
|
|
77262
|
+
if (row2.willNotConclude) {
|
|
77183
77263
|
return "This page's traffic will not settle it at any point, so end it with `--keep original` and test a bigger change.";
|
|
77184
77264
|
}
|
|
77185
|
-
if (
|
|
77265
|
+
if (row2.earliestDecisionAt === null) {
|
|
77186
77266
|
return "This page has produced no visitors yet, so there is nothing to project a finish date from.";
|
|
77187
77267
|
}
|
|
77188
|
-
if (
|
|
77189
|
-
return `It already has the data it needs; the verdict waits only until it has seen a full day of visitors \u2014 ${describeWait(
|
|
77268
|
+
if (row2.stillNeeded === null) {
|
|
77269
|
+
return `It already has the data it needs; the verdict waits only until it has seen a full day of visitors \u2014 ${describeWait(row2.earliestDecisionAt, now)}.`;
|
|
77190
77270
|
}
|
|
77191
|
-
const needed = `It needs ${roughCount(
|
|
77192
|
-
return `${needed}${describeWait(
|
|
77271
|
+
const needed = `It needs ${roughCount(row2.stillNeeded.visitors)} more visitors (${roughCount(row2.stillNeeded.conversions)} more conversions) for an answer if the gap holds \u2014 `;
|
|
77272
|
+
return `${needed}${describeWait(row2.earliestDecisionAt, now)} at today's traffic (${new Date(row2.earliestDecisionAt).toISOString().slice(0, 10)}). A test is gated on this data, never on days.`;
|
|
77193
77273
|
}
|
|
77194
|
-
function pausedNote(
|
|
77195
|
-
return
|
|
77274
|
+
function pausedNote(row2) {
|
|
77275
|
+
return row2.status === "paused" ? `${row2.experimentId} is paused \u2014 everyone sees the original. \`baker experiment resume --id ${row2.experimentId}\` restarts the split with the same sides. ` : "";
|
|
77196
77276
|
}
|
|
77197
77277
|
function unlearnedHint(experiments) {
|
|
77198
77278
|
const unlearned = experiments.filter(
|
|
77199
|
-
(
|
|
77279
|
+
(row2) => row2.status === "finished" && row2.learning === null && row2.verdict !== "inconclusive"
|
|
77200
77280
|
);
|
|
77201
77281
|
if (unlearned.length === 0) return null;
|
|
77202
|
-
const ids2 = unlearned.map((
|
|
77282
|
+
const ids2 = unlearned.map((row2) => row2.experimentId).join(", ");
|
|
77203
77283
|
return `${unlearned.length === 1 ? "One finished test has" : `${unlearned.length} finished tests have`} no learning written down yet (${ids2}). Say what it taught in one or two sentences \u2014 what the client should believe about this page now \u2014 with \`baker experiment update --id <id> --learning "\u2026"\`. It is what \`plan\` hands the next test.`;
|
|
77204
77284
|
}
|
|
77205
77285
|
function buildStatusHints(experiments, now = Date.now()) {
|
|
77206
|
-
const hints2 = experiments.filter((
|
|
77286
|
+
const hints2 = experiments.filter((row2) => row2.status !== "finished").map((row2) => pausedNote(row2) + LIVE_HINT[row2.verdict](row2, now));
|
|
77207
77287
|
const unlearned = unlearnedHint(experiments);
|
|
77208
77288
|
if (unlearned) hints2.push(unlearned);
|
|
77209
77289
|
if (experiments.length === 0) {
|
|
@@ -77483,52 +77563,52 @@ function fullArm(arm) {
|
|
|
77483
77563
|
...arm.snapshotCapturedAt === void 0 ? {} : { snapshotCapturedAt: isoMoment(arm.snapshotCapturedAt) }
|
|
77484
77564
|
};
|
|
77485
77565
|
}
|
|
77486
|
-
function statusReadout(
|
|
77566
|
+
function statusReadout(row2, { full, now }) {
|
|
77487
77567
|
const decisionWhen = {
|
|
77488
|
-
earliestDecisionAt: isoDay2(
|
|
77489
|
-
...
|
|
77568
|
+
earliestDecisionAt: isoDay2(row2.earliestDecisionAt),
|
|
77569
|
+
...row2.earliestDecisionAt === null ? {} : { earliestDecisionIn: describeWait(row2.earliestDecisionAt, now) }
|
|
77490
77570
|
};
|
|
77491
77571
|
const moments = {
|
|
77492
|
-
startedAt: isoMoment(
|
|
77493
|
-
pausedAt: isoMoment(
|
|
77494
|
-
finishedAt: isoMoment(
|
|
77572
|
+
startedAt: isoMoment(row2.startedAt),
|
|
77573
|
+
pausedAt: isoMoment(row2.pausedAt),
|
|
77574
|
+
finishedAt: isoMoment(row2.finishedAt)
|
|
77495
77575
|
};
|
|
77496
77576
|
if (full) {
|
|
77497
77577
|
return {
|
|
77498
|
-
...
|
|
77578
|
+
...row2,
|
|
77499
77579
|
...moments,
|
|
77500
77580
|
...decisionWhen,
|
|
77501
|
-
control: fullArm(
|
|
77502
|
-
variant: fullArm(
|
|
77581
|
+
control: fullArm(row2.control),
|
|
77582
|
+
variant: fullArm(row2.variant)
|
|
77503
77583
|
};
|
|
77504
77584
|
}
|
|
77505
77585
|
return {
|
|
77506
|
-
experimentId:
|
|
77507
|
-
landingSlug:
|
|
77508
|
-
variantSlug:
|
|
77509
|
-
status:
|
|
77510
|
-
verdict:
|
|
77511
|
-
summary:
|
|
77512
|
-
...
|
|
77513
|
-
...
|
|
77514
|
-
stillNeeded:
|
|
77586
|
+
experimentId: row2.experimentId,
|
|
77587
|
+
landingSlug: row2.landingSlug,
|
|
77588
|
+
variantSlug: row2.variantSlug,
|
|
77589
|
+
status: row2.status,
|
|
77590
|
+
verdict: row2.verdict,
|
|
77591
|
+
summary: row2.summary,
|
|
77592
|
+
...row2.winner === null ? {} : { winner: row2.winner },
|
|
77593
|
+
...row2.invalidReason === null ? {} : { invalidReason: row2.invalidReason },
|
|
77594
|
+
stillNeeded: row2.stillNeeded,
|
|
77515
77595
|
...decisionWhen,
|
|
77516
|
-
willNotConclude:
|
|
77517
|
-
control: compactArm(
|
|
77518
|
-
variant: compactArm(
|
|
77519
|
-
secondary:
|
|
77520
|
-
hypothesisStatement:
|
|
77521
|
-
minDetectableRelativeLift:
|
|
77522
|
-
goal:
|
|
77523
|
-
...
|
|
77524
|
-
goalLabel:
|
|
77596
|
+
willNotConclude: row2.willNotConclude,
|
|
77597
|
+
control: compactArm(row2.control),
|
|
77598
|
+
variant: compactArm(row2.variant),
|
|
77599
|
+
secondary: row2.secondary.map(compactMetric),
|
|
77600
|
+
hypothesisStatement: row2.hypothesisStatement,
|
|
77601
|
+
minDetectableRelativeLift: row2.minDetectableRelativeLift,
|
|
77602
|
+
goal: row2.goal,
|
|
77603
|
+
...row2.variantGoal === null ? {} : { variantGoal: row2.variantGoal },
|
|
77604
|
+
goalLabel: row2.goalLabel,
|
|
77525
77605
|
...moments,
|
|
77526
|
-
...
|
|
77527
|
-
survivor:
|
|
77528
|
-
hypothesisOutcome:
|
|
77529
|
-
fold:
|
|
77530
|
-
learning:
|
|
77531
|
-
endReason:
|
|
77606
|
+
...row2.status === "finished" ? {
|
|
77607
|
+
survivor: row2.survivor,
|
|
77608
|
+
hypothesisOutcome: row2.hypothesisOutcome,
|
|
77609
|
+
fold: row2.fold,
|
|
77610
|
+
learning: row2.learning,
|
|
77611
|
+
endReason: row2.endReason
|
|
77532
77612
|
} : {}
|
|
77533
77613
|
};
|
|
77534
77614
|
}
|
|
@@ -77806,7 +77886,7 @@ var statusCommand7 = defineCommand149({
|
|
|
77806
77886
|
writeJsonEnvelope({
|
|
77807
77887
|
ok: true,
|
|
77808
77888
|
data: {
|
|
77809
|
-
experiments: response.data.experiments.map((
|
|
77889
|
+
experiments: response.data.experiments.map((row2) => statusReadout(row2, { full: args8.full === true, now }))
|
|
77810
77890
|
},
|
|
77811
77891
|
hints: buildStatusHints(response.data.experiments, now)
|
|
77812
77892
|
});
|
|
@@ -79202,7 +79282,7 @@ function assertDestinationReady(slug, tree, chosen, into) {
|
|
|
79202
79282
|
function collectConfigStatusFor(tree, _slug, sideEffectId) {
|
|
79203
79283
|
const rows = [];
|
|
79204
79284
|
collectConfigStatus(tree, rows);
|
|
79205
|
-
return rows.find((
|
|
79285
|
+
return rows.find((row2) => row2.sideEffectId === sideEffectId);
|
|
79206
79286
|
}
|
|
79207
79287
|
function slotHintFor(type, into) {
|
|
79208
79288
|
const others = otherSlots(type, shapeFor(type, into));
|
|
@@ -79629,9 +79709,9 @@ function statusFor(slug) {
|
|
|
79629
79709
|
return config;
|
|
79630
79710
|
}
|
|
79631
79711
|
function pendingInputHints(slug, config) {
|
|
79632
|
-
const pending = config.filter((
|
|
79712
|
+
const pending = config.filter((row2) => row2.needsInput);
|
|
79633
79713
|
if (pending.length === 0) return [];
|
|
79634
|
-
const calls = pending.slice(0, MAX_PENDING_HINTS).map((
|
|
79714
|
+
const calls = pending.slice(0, MAX_PENDING_HINTS).map((row2) => `${row2.kind}: ${requestFlowInputCall(slug, row2)}`);
|
|
79635
79715
|
const rest = pending.length - calls.length;
|
|
79636
79716
|
return [
|
|
79637
79717
|
`${pending.length} item${pending.length === 1 ? "" : "s"} still need the user. Each is one blocking call, and its result carries the destination \u2014 read the names from there rather than looking them up again.`,
|
|
@@ -80555,7 +80635,7 @@ var funnelCommand2 = defineCommand155({
|
|
|
80555
80635
|
...namedByCaller.length === 0 ? {} : { namedByCaller }
|
|
80556
80636
|
};
|
|
80557
80637
|
const response = await apiPost("/api/funnel", request);
|
|
80558
|
-
const counted = new Map((response.data.counted ?? []).map((
|
|
80638
|
+
const counted = new Map((response.data.counted ?? []).map((row2) => [row2.eventKey, row2.name]));
|
|
80559
80639
|
const data = response.data.moments === void 0 ? response.data : { ...response.data, moments: withFormMoments(response.data.moments, forms, counted) };
|
|
80560
80640
|
const hints2 = [...response.hints ?? [], ...unplacedFormHints(response.data.steps ?? [], forms, counted)];
|
|
80561
80641
|
writeJsonEnvelope({
|
|
@@ -81173,11 +81253,11 @@ function writeRowsToFile2(filePath, rows, append) {
|
|
|
81173
81253
|
writeFileSync4(filePath, `${toCsvRow(fields)}
|
|
81174
81254
|
`, "utf-8");
|
|
81175
81255
|
}
|
|
81176
|
-
const csvRows = rows.map((
|
|
81256
|
+
const csvRows = rows.map((row2) => toCsvRow(fields.map((f) => String(row2[f] ?? ""))));
|
|
81177
81257
|
appendFileSync2(filePath, `${csvRows.join("\n")}
|
|
81178
81258
|
`, "utf-8");
|
|
81179
81259
|
} else if (ext === "jsonl") {
|
|
81180
|
-
const lines = rows.map((
|
|
81260
|
+
const lines = rows.map((row2) => JSON.stringify(row2));
|
|
81181
81261
|
const content = `${lines.join("\n")}
|
|
81182
81262
|
`;
|
|
81183
81263
|
if (append && existsSync10(filePath)) {
|
|
@@ -82174,11 +82254,11 @@ function writeRowsToFile3(filePath, rows, append) {
|
|
|
82174
82254
|
writeFileSync5(filePath, `${toCsvRow(fields)}
|
|
82175
82255
|
`, "utf-8");
|
|
82176
82256
|
}
|
|
82177
|
-
const csvRows = rows.map((
|
|
82257
|
+
const csvRows = rows.map((row2) => toCsvRow(fields.map((f) => String(row2[f] ?? ""))));
|
|
82178
82258
|
appendFileSync3(filePath, `${csvRows.join("\n")}
|
|
82179
82259
|
`, "utf-8");
|
|
82180
82260
|
} else if (ext === "jsonl") {
|
|
82181
|
-
const content = `${rows.map((
|
|
82261
|
+
const content = `${rows.map((row2) => JSON.stringify(row2)).join("\n")}
|
|
82182
82262
|
`;
|
|
82183
82263
|
if (append && existsSync11(filePath)) {
|
|
82184
82264
|
appendFileSync3(filePath, content, "utf-8");
|
|
@@ -90311,7 +90391,7 @@ async function composeFilmstrip(frames) {
|
|
|
90311
90391
|
const width = FRAME_WIDTH * Math.min(GRID_COLUMNS, scaled.length);
|
|
90312
90392
|
const composites = scaled.flatMap((frame, index) => {
|
|
90313
90393
|
const column = index % GRID_COLUMNS;
|
|
90314
|
-
const
|
|
90394
|
+
const row2 = Math.floor(index / GRID_COLUMNS);
|
|
90315
90395
|
const label = Buffer.from(
|
|
90316
90396
|
`<svg width="${FRAME_WIDTH}" height="${LABEL_HEIGHT}">
|
|
90317
90397
|
<rect width="100%" height="100%" fill="#111827"/>
|
|
@@ -90319,8 +90399,8 @@ async function composeFilmstrip(frames) {
|
|
|
90319
90399
|
</svg>`
|
|
90320
90400
|
);
|
|
90321
90401
|
return [
|
|
90322
|
-
{ input: label, left: column * FRAME_WIDTH, top:
|
|
90323
|
-
{ input: frame, left: column * FRAME_WIDTH, top:
|
|
90402
|
+
{ input: label, left: column * FRAME_WIDTH, top: row2 * cellHeight },
|
|
90403
|
+
{ input: frame, left: column * FRAME_WIDTH, top: row2 * cellHeight + LABEL_HEIGHT }
|
|
90324
90404
|
];
|
|
90325
90405
|
});
|
|
90326
90406
|
return await sharp6({
|
|
@@ -92477,7 +92557,7 @@ Full guide: __tooling__/docs/tools/baker/media-sources.md`
|
|
|
92477
92557
|
});
|
|
92478
92558
|
|
|
92479
92559
|
// src/commands/research/index.ts
|
|
92480
|
-
import { defineCommand as
|
|
92560
|
+
import { defineCommand as defineCommand228 } from "citty";
|
|
92481
92561
|
|
|
92482
92562
|
// src/commands/research/advertisers.ts
|
|
92483
92563
|
import { defineCommand as defineCommand215 } from "citty";
|
|
@@ -92559,7 +92639,7 @@ function keywordMetricsHints({
|
|
|
92559
92639
|
}
|
|
92560
92640
|
const provenance = "DataForSEO resells Google's Keyword Planner volume \u2014 planner_search_volume here is the SAME number `baker ads google keywords metrics` returns, not an independent reading of it. Quoting the two as agreeing sources is not corroboration." + (clickstream ? " clickstream_search_volume IS independent (DataForSEO's own panels); when the two disagree, say which one you are quoting." : " For a genuinely independent estimate of demand, re-run with --clickstream (costs 2x), or use first-party data: `baker gsc query` for what already reaches the site, or the account's own search terms.");
|
|
92561
92641
|
const hints2 = [provenance];
|
|
92562
|
-
const empty = rows.filter((
|
|
92642
|
+
const empty = rows.filter((row2) => row2.search_volume === null).map((row2) => row2.keyword);
|
|
92563
92643
|
if (empty.length > 0) {
|
|
92564
92644
|
hints2.push(
|
|
92565
92645
|
`${empty.length} of ${asked.length} keywords came back with no data in ${queryContext.location} / ${queryContext.language}: ${empty.join(", ")}. That is missing coverage, NOT zero demand \u2014 do not report them as unsearched, and do not re-query them reworded. \`baker research autocomplete\` on the head term is the way to find the phrasing that market uses.`
|
|
@@ -92567,6 +92647,70 @@ function keywordMetricsHints({
|
|
|
92567
92647
|
}
|
|
92568
92648
|
return hints2;
|
|
92569
92649
|
}
|
|
92650
|
+
var ARCHIVE_NOTE = "Read from the Reddit archive: the words are as posted, but points and comment counts on anything under ~36h old are as first captured \u2014 don't quote those numbers as current.";
|
|
92651
|
+
function redditSearchHints({
|
|
92652
|
+
resultCount,
|
|
92653
|
+
kind,
|
|
92654
|
+
source
|
|
92655
|
+
}) {
|
|
92656
|
+
const hints2 = [];
|
|
92657
|
+
if (resultCount === 0) {
|
|
92658
|
+
hints2.push(
|
|
92659
|
+
'Nothing matched. Reddit search matches words, not meaning: try the audience\'s own phrasing (one distinctive word, or a seed from `baker research autocomplete`), a longer --since window, or other subreddits \u2014 `baker research reddit subreddits "<topic>"` finds where the audience actually talks' + (kind === "posts" ? ", and try --kind comments \u2014 most of the voice is in the replies." : ".")
|
|
92660
|
+
);
|
|
92661
|
+
} else if (kind === "posts") {
|
|
92662
|
+
hints2.push(
|
|
92663
|
+
"Titles rarely carry the voice. Read the promising threads with `baker research reddit thread <permalink>` for the replies, or search the replies directly with --kind comments."
|
|
92664
|
+
);
|
|
92665
|
+
}
|
|
92666
|
+
if (source === "archive" && resultCount > 0) hints2.push(ARCHIVE_NOTE);
|
|
92667
|
+
return hints2;
|
|
92668
|
+
}
|
|
92669
|
+
function redditThreadHints({
|
|
92670
|
+
commentsShown,
|
|
92671
|
+
commentsAsked,
|
|
92672
|
+
commentCount,
|
|
92673
|
+
source
|
|
92674
|
+
}) {
|
|
92675
|
+
const hints2 = [];
|
|
92676
|
+
if (commentsAsked > 0 && commentsShown === 0 && (commentCount ?? 0) > 0) {
|
|
92677
|
+
hints2.push(
|
|
92678
|
+
`This thread has ${commentCount} comments but none could be read just now. Quote the post only, and don't describe the replies.`
|
|
92679
|
+
);
|
|
92680
|
+
}
|
|
92681
|
+
if (source === "archive") hints2.push(ARCHIVE_NOTE);
|
|
92682
|
+
return hints2;
|
|
92683
|
+
}
|
|
92684
|
+
var REDDIT_HOST = /(^|\.)reddit\.com$|^redd\.it$/i;
|
|
92685
|
+
function redditSubredditsHints({ resultCount }) {
|
|
92686
|
+
if (resultCount === 0) {
|
|
92687
|
+
return [
|
|
92688
|
+
'No subreddits matched. Try the audience\'s role or the platform they work on ("amazon flex", "deliveroo", "nurses"), one word at a time, or a web search for `site:reddit.com <topic>`.'
|
|
92689
|
+
];
|
|
92690
|
+
}
|
|
92691
|
+
return [
|
|
92692
|
+
'Members say how big a subreddit is, not how active it is. Before mining one, run `baker research reddit search "<word>" --subreddit <name> --since <a recent date>`: nothing back means it is quiet, so pick another. `restricted` can still be read; `private` cannot.'
|
|
92693
|
+
];
|
|
92694
|
+
}
|
|
92695
|
+
var REDDIT_LINK_REJECTED = {
|
|
92696
|
+
action: "reject",
|
|
92697
|
+
explanation: "Do not quote anything attributed to this link \u2014 it does not lead to those words. Find the real thread with `baker research reddit search`, and if you already wrote a quote from it, remove it."
|
|
92698
|
+
};
|
|
92699
|
+
function redditPageFix(url, code) {
|
|
92700
|
+
let host;
|
|
92701
|
+
try {
|
|
92702
|
+
host = new URL(url).hostname;
|
|
92703
|
+
} catch {
|
|
92704
|
+
return null;
|
|
92705
|
+
}
|
|
92706
|
+
if (!REDDIT_HOST.test(host)) return null;
|
|
92707
|
+
if (code === "NOT_FOUND") return REDDIT_LINK_REJECTED;
|
|
92708
|
+
if (code !== "FORBIDDEN") return null;
|
|
92709
|
+
return {
|
|
92710
|
+
action: "retry_with_changes",
|
|
92711
|
+
explanation: 'Read Reddit with its own commands: `baker research reddit search "<words>" --subreddit <name>` to find what people said, `baker research reddit thread <url>` for one thread.'
|
|
92712
|
+
};
|
|
92713
|
+
}
|
|
92570
92714
|
|
|
92571
92715
|
// src/commands/research/output.ts
|
|
92572
92716
|
var RESEARCH_DATA_NOTE = "Estimates based on third-party SERP data \u2014 not exact figures. Use for directional insights, not precise measurement.";
|
|
@@ -92582,9 +92726,9 @@ function toCsvRow2(values) {
|
|
|
92582
92726
|
return v;
|
|
92583
92727
|
}).join(",");
|
|
92584
92728
|
}
|
|
92585
|
-
function flattenRow(
|
|
92729
|
+
function flattenRow(row2) {
|
|
92586
92730
|
const flat = {};
|
|
92587
|
-
for (const [key, val] of Object.entries(
|
|
92731
|
+
for (const [key, val] of Object.entries(row2)) {
|
|
92588
92732
|
flat[key] = typeof val === "object" && val !== null ? JSON.stringify(val) : String(val ?? "");
|
|
92589
92733
|
}
|
|
92590
92734
|
return flat;
|
|
@@ -92594,15 +92738,15 @@ function writeCsv(data, fields) {
|
|
|
92594
92738
|
const cols = fields ?? Object.keys(data[0] ?? {});
|
|
92595
92739
|
process.stdout.write(`${toCsvRow2(cols)}
|
|
92596
92740
|
`);
|
|
92597
|
-
for (const
|
|
92598
|
-
const flat = flattenRow(
|
|
92741
|
+
for (const row2 of data) {
|
|
92742
|
+
const flat = flattenRow(row2);
|
|
92599
92743
|
process.stdout.write(`${toCsvRow2(cols.map((f) => flat[f] ?? ""))}
|
|
92600
92744
|
`);
|
|
92601
92745
|
}
|
|
92602
92746
|
}
|
|
92603
92747
|
function writeJsonl(data) {
|
|
92604
|
-
for (const
|
|
92605
|
-
process.stdout.write(`${JSON.stringify(
|
|
92748
|
+
for (const row2 of data) {
|
|
92749
|
+
process.stdout.write(`${JSON.stringify(row2)}
|
|
92606
92750
|
`);
|
|
92607
92751
|
}
|
|
92608
92752
|
}
|
|
@@ -92613,8 +92757,8 @@ function writeMd(data, fields) {
|
|
|
92613
92757
|
`);
|
|
92614
92758
|
process.stdout.write(`| ${cols.map(() => "---").join(" | ")} |
|
|
92615
92759
|
`);
|
|
92616
|
-
for (const
|
|
92617
|
-
const flat = flattenRow(
|
|
92760
|
+
for (const row2 of data) {
|
|
92761
|
+
const flat = flattenRow(row2);
|
|
92618
92762
|
process.stdout.write(`| ${cols.map((f) => flat[f] ?? "").join(" | ")} |
|
|
92619
92763
|
`);
|
|
92620
92764
|
}
|
|
@@ -93028,7 +93172,7 @@ Examples:
|
|
|
93028
93172
|
})
|
|
93029
93173
|
});
|
|
93030
93174
|
} catch (err) {
|
|
93031
|
-
handleResearchError(err, fetchFix);
|
|
93175
|
+
handleResearchError(err, (code) => redditPageFix(url, code) ?? fetchFix(code));
|
|
93032
93176
|
}
|
|
93033
93177
|
}
|
|
93034
93178
|
});
|
|
@@ -93213,24 +93357,24 @@ import { defineCommand as defineCommand221 } from "citty";
|
|
|
93213
93357
|
|
|
93214
93358
|
// src/commands/research/keyword-metrics-rows.ts
|
|
93215
93359
|
var KEYWORD_METRICS_SOURCE = "keyword_planner_estimate_via_dataforseo";
|
|
93216
|
-
function toOutputRow(
|
|
93360
|
+
function toOutputRow(row2, options) {
|
|
93217
93361
|
const out = {
|
|
93218
93362
|
source: KEYWORD_METRICS_SOURCE,
|
|
93219
|
-
keyword:
|
|
93220
|
-
planner_search_volume:
|
|
93221
|
-
planner_cpc:
|
|
93222
|
-
planner_low_top_of_page_bid:
|
|
93223
|
-
planner_high_top_of_page_bid:
|
|
93224
|
-
planner_competition:
|
|
93225
|
-
planner_competition_index:
|
|
93363
|
+
keyword: row2.keyword,
|
|
93364
|
+
planner_search_volume: row2.search_volume,
|
|
93365
|
+
planner_cpc: row2.cpc,
|
|
93366
|
+
planner_low_top_of_page_bid: row2.low_top_of_page_bid,
|
|
93367
|
+
planner_high_top_of_page_bid: row2.high_top_of_page_bid,
|
|
93368
|
+
planner_competition: row2.competition,
|
|
93369
|
+
planner_competition_index: row2.competition_index
|
|
93226
93370
|
};
|
|
93227
93371
|
if (options.clickstream) {
|
|
93228
|
-
out.clickstream_search_volume =
|
|
93372
|
+
out.clickstream_search_volume = row2.clickstream_search_volume;
|
|
93229
93373
|
}
|
|
93230
93374
|
if (options.full) {
|
|
93231
|
-
out.keyword_difficulty =
|
|
93232
|
-
out.main_intent =
|
|
93233
|
-
out.planner_monthly_searches =
|
|
93375
|
+
out.keyword_difficulty = row2.keyword_difficulty;
|
|
93376
|
+
out.main_intent = row2.main_intent;
|
|
93377
|
+
out.planner_monthly_searches = row2.monthly_searches;
|
|
93234
93378
|
}
|
|
93235
93379
|
return out;
|
|
93236
93380
|
}
|
|
@@ -93347,7 +93491,7 @@ Examples:
|
|
|
93347
93491
|
skipCache: args8["no-cache"] ? true : void 0
|
|
93348
93492
|
});
|
|
93349
93493
|
const columns = { clickstream, full };
|
|
93350
|
-
const rows = result.data.map((
|
|
93494
|
+
const rows = result.data.map((row2) => toOutputRow(row2, columns));
|
|
93351
93495
|
const hints2 = keywordMetricsHints({ rows: result.data, asked: keywords, clickstream, queryContext });
|
|
93352
93496
|
warnDefaults(queryContext);
|
|
93353
93497
|
const format = args8.output || "json";
|
|
@@ -93563,8 +93707,273 @@ Examples:
|
|
|
93563
93707
|
}
|
|
93564
93708
|
});
|
|
93565
93709
|
|
|
93566
|
-
// src/commands/research/
|
|
93710
|
+
// src/commands/research/reddit.ts
|
|
93567
93711
|
import { defineCommand as defineCommand225 } from "citty";
|
|
93712
|
+
var TIMEOUT_MS2 = 18e4;
|
|
93713
|
+
var TEXT_PREVIEW_CHARS = 1500;
|
|
93714
|
+
var ITEM_FIELDS = {
|
|
93715
|
+
kind: "post or comment",
|
|
93716
|
+
subreddit: "Where it was said",
|
|
93717
|
+
title: "The post's title (on a comment: the post it answers)",
|
|
93718
|
+
text: "Verbatim \u2014 quote this, exactly",
|
|
93719
|
+
text_truncated: "The text was cut; re-run with --full before quoting the end of it",
|
|
93720
|
+
author: "Reddit username, or null once the account is deleted",
|
|
93721
|
+
score: "Points",
|
|
93722
|
+
comment_count: "Posts only",
|
|
93723
|
+
created: "Date written (UTC)",
|
|
93724
|
+
permalink: "Cite THIS link \u2014 it is built from where the words actually are",
|
|
93725
|
+
depth: "Thread comments: 0 answers the post, 1 answers a comment",
|
|
93726
|
+
source: "reddit_api / reddit_web = live Reddit; archive = the Arctic Shift archive of Reddit"
|
|
93727
|
+
};
|
|
93728
|
+
registerSchema({
|
|
93729
|
+
command: "research.reddit.search",
|
|
93730
|
+
description: "Search Reddit posts or comments for the audience's own words. Returns verbatim text with a real permalink for each hit. Start here for voice-of-customer work on Reddit.",
|
|
93731
|
+
args: {
|
|
93732
|
+
query: {
|
|
93733
|
+
type: "string",
|
|
93734
|
+
description: "Words to match \u2014 the audience's phrasing, not a description of it",
|
|
93735
|
+
required: true
|
|
93736
|
+
},
|
|
93737
|
+
subreddit: {
|
|
93738
|
+
type: "string",
|
|
93739
|
+
description: "Subreddits to search (up to 10): comma-separated (couriersofreddit,AmazonFlexUK) or the flag repeated. Needed for --kind comments",
|
|
93740
|
+
required: false
|
|
93741
|
+
},
|
|
93742
|
+
kind: {
|
|
93743
|
+
type: "string",
|
|
93744
|
+
description: "posts (default) or comments \u2014 the replies are where most of the voice is",
|
|
93745
|
+
required: false,
|
|
93746
|
+
enum: ["posts", "comments"]
|
|
93747
|
+
},
|
|
93748
|
+
since: { type: "string", description: "Only things written on or after this day, YYYY-MM-DD", required: false },
|
|
93749
|
+
limit: { type: "number", description: "Results to return (1-50, default 25)", required: false },
|
|
93750
|
+
full: {
|
|
93751
|
+
type: "boolean",
|
|
93752
|
+
description: "Return every text whole instead of a preview",
|
|
93753
|
+
required: false,
|
|
93754
|
+
default: false
|
|
93755
|
+
}
|
|
93756
|
+
}
|
|
93757
|
+
});
|
|
93758
|
+
registerSchema({
|
|
93759
|
+
command: "research.reddit.thread",
|
|
93760
|
+
description: "Read one Reddit thread verbatim: the post and its best comments, each with its own permalink. Use it on any Reddit link before quoting it \u2014 it also exposes links that point somewhere other than they claim.",
|
|
93761
|
+
args: {
|
|
93762
|
+
target: {
|
|
93763
|
+
type: "string",
|
|
93764
|
+
description: "The thread's link (any Reddit form, including share links) or post id",
|
|
93765
|
+
required: true
|
|
93766
|
+
},
|
|
93767
|
+
comments: { type: "number", description: "Comments to return, best first (0-200, default 40)", required: false },
|
|
93768
|
+
full: {
|
|
93769
|
+
type: "boolean",
|
|
93770
|
+
description: "Return every text whole instead of a preview",
|
|
93771
|
+
required: false,
|
|
93772
|
+
default: false
|
|
93773
|
+
}
|
|
93774
|
+
}
|
|
93775
|
+
});
|
|
93776
|
+
registerSchema({
|
|
93777
|
+
command: "research.reddit.subreddits",
|
|
93778
|
+
description: "Find the subreddits where an audience talks about a topic, with member counts and whether they can be read. Run it before searching, instead of guessing subreddit names.",
|
|
93779
|
+
args: {
|
|
93780
|
+
query: { type: "string", description: 'The audience or topic, e.g. "amazon flex uk", "deliveroo"', required: true },
|
|
93781
|
+
limit: { type: "number", description: "Subreddits to return (1-25, default 10)", required: false }
|
|
93782
|
+
}
|
|
93783
|
+
});
|
|
93784
|
+
function row(item, full) {
|
|
93785
|
+
const cut = !full && item.text.length > TEXT_PREVIEW_CHARS;
|
|
93786
|
+
return {
|
|
93787
|
+
kind: item.kind,
|
|
93788
|
+
subreddit: item.subreddit,
|
|
93789
|
+
title: item.title,
|
|
93790
|
+
text: cut ? `${item.text.slice(0, TEXT_PREVIEW_CHARS)}\u2026` : item.text,
|
|
93791
|
+
...cut ? { text_truncated: true } : {},
|
|
93792
|
+
author: item.author,
|
|
93793
|
+
score: item.score,
|
|
93794
|
+
...item.kind === "post" ? { comment_count: item.commentCount } : {},
|
|
93795
|
+
created: item.createdAt.slice(0, 10),
|
|
93796
|
+
permalink: item.permalink,
|
|
93797
|
+
...item.depth !== null ? { depth: item.depth } : {}
|
|
93798
|
+
};
|
|
93799
|
+
}
|
|
93800
|
+
function redditFix(code) {
|
|
93801
|
+
if (code === "NOT_FOUND") return REDDIT_LINK_REJECTED;
|
|
93802
|
+
if (code === "BAD_REQUEST" || code === "VALIDATION_ERROR") {
|
|
93803
|
+
return { action: "retry_with_changes", explanation: "Follow the message above and run the command again." };
|
|
93804
|
+
}
|
|
93805
|
+
return {
|
|
93806
|
+
action: "continue_without",
|
|
93807
|
+
explanation: "Don't loop on it. Finish the job with the other sources, say plainly that Reddit is a gap in this research, and never stand in a summary's paraphrase for a Reddit quote."
|
|
93808
|
+
};
|
|
93809
|
+
}
|
|
93810
|
+
function failValidation4(message) {
|
|
93811
|
+
writeResearchJson({ ok: false, error: { code: "VALIDATION_ERROR", message, fix: redditFix("VALIDATION_ERROR") } });
|
|
93812
|
+
process.exit(1);
|
|
93813
|
+
}
|
|
93814
|
+
function subredditsFromArgs(rawArgs, parsed) {
|
|
93815
|
+
return repeatedValues(rawArgs, "subreddit", parsed).flatMap((value2) => value2.split(",")).map((name) => name.trim()).filter(Boolean);
|
|
93816
|
+
}
|
|
93817
|
+
var searchCommand3 = defineCommand225({
|
|
93818
|
+
meta: {
|
|
93819
|
+
name: "search",
|
|
93820
|
+
description: `Search Reddit for the audience's own words, verbatim, each with a permalink you can cite.
|
|
93821
|
+
|
|
93822
|
+
Start here for Reddit voice-of-customer. Matches words, not meaning \u2014 search the way the audience writes, and quote a phrase to keep it together ('"right to work"').
|
|
93823
|
+
|
|
93824
|
+
Examples:
|
|
93825
|
+
baker research reddit search "agency never paid" --subreddit couriersofreddit,AmazonFlexUK
|
|
93826
|
+
baker research reddit search '"right to work"' --subreddit UKJobs,AmazonFlexUK
|
|
93827
|
+
baker research reddit search "visa" --subreddit UberEATS --kind comments --since 2025-01-01
|
|
93828
|
+
baker research reddit search "side hustle student deliveries"`
|
|
93829
|
+
},
|
|
93830
|
+
args: {
|
|
93831
|
+
query: { type: "positional", description: "Words to match", required: false },
|
|
93832
|
+
subreddit: {
|
|
93833
|
+
type: "string",
|
|
93834
|
+
description: "Subreddits (up to 10): comma-separated, or repeat the flag",
|
|
93835
|
+
required: false
|
|
93836
|
+
},
|
|
93837
|
+
kind: { type: "string", description: "posts (default) or comments", required: false },
|
|
93838
|
+
since: { type: "string", description: "YYYY-MM-DD", required: false },
|
|
93839
|
+
limit: { type: "string", description: "1-50, default 25", required: false },
|
|
93840
|
+
full: { type: "boolean", description: "Whole texts, not previews", required: false }
|
|
93841
|
+
},
|
|
93842
|
+
run: async ({ args: args8, rawArgs }) => {
|
|
93843
|
+
const query = args8.query?.trim();
|
|
93844
|
+
if (!query) failValidation4('Say what to search for: baker research reddit search "<words>"');
|
|
93845
|
+
const kind = args8.kind ?? "posts";
|
|
93846
|
+
if (kind !== "posts" && kind !== "comments") failValidation4("--kind must be posts or comments");
|
|
93847
|
+
const body = {
|
|
93848
|
+
query,
|
|
93849
|
+
kind,
|
|
93850
|
+
subreddits: subredditsFromArgs(rawArgs, args8.subreddit)
|
|
93851
|
+
};
|
|
93852
|
+
if (args8.since) body.since = args8.since;
|
|
93853
|
+
if (args8.limit) body.limit = Number(args8.limit);
|
|
93854
|
+
try {
|
|
93855
|
+
const data = await apiPost("/api/research/reddit/search", body, {
|
|
93856
|
+
timeoutMs: TIMEOUT_MS2
|
|
93857
|
+
});
|
|
93858
|
+
writeResearchJson({
|
|
93859
|
+
ok: true,
|
|
93860
|
+
data: data.results.map((item) => row(item, Boolean(args8.full))),
|
|
93861
|
+
source: data.source,
|
|
93862
|
+
fields: ITEM_FIELDS,
|
|
93863
|
+
hints: redditSearchHints({ resultCount: data.results.length, kind, source: data.source })
|
|
93864
|
+
});
|
|
93865
|
+
} catch (err) {
|
|
93866
|
+
handleResearchError(err, redditFix);
|
|
93867
|
+
}
|
|
93868
|
+
}
|
|
93869
|
+
});
|
|
93870
|
+
var threadCommand = defineCommand225({
|
|
93871
|
+
meta: {
|
|
93872
|
+
name: "thread",
|
|
93873
|
+
description: `Read one Reddit thread verbatim \u2014 the post and its best comments, each with its own permalink.
|
|
93874
|
+
|
|
93875
|
+
Run it on every Reddit link before you quote from it, including links a research summary gave you: it refuses a link whose post is somewhere other than the link claims.
|
|
93876
|
+
|
|
93877
|
+
Examples:
|
|
93878
|
+
baker research reddit thread "https://www.reddit.com/r/AmazonFlexUK/comments/1abc2de/agency_still_hasnt_paid_me/"
|
|
93879
|
+
baker research reddit thread "https://www.reddit.com/r/UberEATS/s/3TzXiyxaMD" --comments 100
|
|
93880
|
+
baker research reddit thread 1abc2de --full`
|
|
93881
|
+
},
|
|
93882
|
+
args: {
|
|
93883
|
+
target: { type: "positional", description: "Thread link or post id", required: false },
|
|
93884
|
+
comments: { type: "string", description: "0-200, default 40", required: false },
|
|
93885
|
+
full: { type: "boolean", description: "Whole texts, not previews", required: false }
|
|
93886
|
+
},
|
|
93887
|
+
run: async ({ args: args8 }) => {
|
|
93888
|
+
const target2 = args8.target?.trim();
|
|
93889
|
+
if (!target2) failValidation4("Pass the thread's link or post id: baker research reddit thread <url>");
|
|
93890
|
+
const commentsAsked = args8.comments ? Number(args8.comments) : RESEARCH_REDDIT_THREAD_DEFAULT_COMMENTS;
|
|
93891
|
+
const body = { target: target2, comments: commentsAsked };
|
|
93892
|
+
try {
|
|
93893
|
+
const data = await apiPost("/api/research/reddit/thread", body, {
|
|
93894
|
+
timeoutMs: TIMEOUT_MS2
|
|
93895
|
+
});
|
|
93896
|
+
const full = Boolean(args8.full);
|
|
93897
|
+
writeResearchJson({
|
|
93898
|
+
ok: true,
|
|
93899
|
+
data: { post: row(data.post, full), comments: data.comments.map((item) => row(item, full)) },
|
|
93900
|
+
source: data.source,
|
|
93901
|
+
fields: ITEM_FIELDS,
|
|
93902
|
+
hints: redditThreadHints({
|
|
93903
|
+
commentsShown: data.comments.length,
|
|
93904
|
+
commentsAsked,
|
|
93905
|
+
commentCount: data.post.commentCount,
|
|
93906
|
+
source: data.source
|
|
93907
|
+
})
|
|
93908
|
+
});
|
|
93909
|
+
} catch (err) {
|
|
93910
|
+
handleResearchError(err, redditFix);
|
|
93911
|
+
}
|
|
93912
|
+
}
|
|
93913
|
+
});
|
|
93914
|
+
var subredditsCommand = defineCommand225({
|
|
93915
|
+
meta: {
|
|
93916
|
+
name: "subreddits",
|
|
93917
|
+
description: `Find the subreddits where an audience talks \u2014 name, members, and whether it can be read.
|
|
93918
|
+
|
|
93919
|
+
Run it before \`reddit search\` instead of guessing names: a plausible-sounding subreddit can be dead (r/CouriersUK has one post), while the conversation sits in r/AmazonFlexUK or r/deliveroos.
|
|
93920
|
+
|
|
93921
|
+
Examples:
|
|
93922
|
+
baker research reddit subreddits "amazon flex uk"
|
|
93923
|
+
baker research reddit subreddits "deliveroo" --limit 5`
|
|
93924
|
+
},
|
|
93925
|
+
args: {
|
|
93926
|
+
query: { type: "positional", description: "Audience or topic", required: false },
|
|
93927
|
+
limit: { type: "string", description: "1-25, default 10", required: false }
|
|
93928
|
+
},
|
|
93929
|
+
run: async ({ args: args8 }) => {
|
|
93930
|
+
const query = args8.query?.trim();
|
|
93931
|
+
if (!query) failValidation4('Say what to look for: baker research reddit subreddits "<audience or topic>"');
|
|
93932
|
+
const body = { query };
|
|
93933
|
+
if (args8.limit) body.limit = Number(args8.limit);
|
|
93934
|
+
try {
|
|
93935
|
+
const data = await apiPost("/api/research/reddit/subreddits", body, {
|
|
93936
|
+
timeoutMs: TIMEOUT_MS2
|
|
93937
|
+
});
|
|
93938
|
+
writeResearchJson({
|
|
93939
|
+
ok: true,
|
|
93940
|
+
data: data.results,
|
|
93941
|
+
source: data.source,
|
|
93942
|
+
fields: {
|
|
93943
|
+
name: "Pass this to --subreddit",
|
|
93944
|
+
subscribers: "Members \u2014 size, not activity",
|
|
93945
|
+
access: "public / restricted (readable, members post) / private (unreadable) / null when the source doesn't say",
|
|
93946
|
+
description: "The subreddit's own summary",
|
|
93947
|
+
url: "The subreddit"
|
|
93948
|
+
},
|
|
93949
|
+
hints: redditSubredditsHints({ resultCount: data.results.length })
|
|
93950
|
+
});
|
|
93951
|
+
} catch (err) {
|
|
93952
|
+
handleResearchError(err, redditFix);
|
|
93953
|
+
}
|
|
93954
|
+
}
|
|
93955
|
+
});
|
|
93956
|
+
var redditCommand = defineCommand225({
|
|
93957
|
+
meta: {
|
|
93958
|
+
name: "reddit",
|
|
93959
|
+
description: `Read Reddit verbatim \u2014 the one site no page reader will open for us.
|
|
93960
|
+
|
|
93961
|
+
Commands:
|
|
93962
|
+
subreddits \u2014 Find where the audience talks (start here)
|
|
93963
|
+
search \u2014 Find posts or comments in the audience's own words
|
|
93964
|
+
thread \u2014 Read one thread: the post and its best comments
|
|
93965
|
+
|
|
93966
|
+
Examples:
|
|
93967
|
+
baker research reddit subreddits "amazon flex uk"
|
|
93968
|
+
baker research reddit search "agency never paid" --subreddit couriersofreddit,AmazonFlexUK --kind comments
|
|
93969
|
+
baker research reddit thread "https://www.reddit.com/r/AmazonFlexUK/comments/1abc2de/"
|
|
93970
|
+
Full guide: __tooling__/docs/tools/baker/research.md`
|
|
93971
|
+
},
|
|
93972
|
+
subCommands: { subreddits: subredditsCommand, search: searchCommand3, thread: threadCommand }
|
|
93973
|
+
});
|
|
93974
|
+
|
|
93975
|
+
// src/commands/research/relevant-pages.ts
|
|
93976
|
+
import { defineCommand as defineCommand226 } from "citty";
|
|
93568
93977
|
registerSchema({
|
|
93569
93978
|
command: "research.relevant-pages",
|
|
93570
93979
|
description: "Get the top pages of a competitor domain with organic traffic and ranking data. Shows which pages drive the most traffic. If --location and --language are omitted, defaults to United States (us) and English (en).",
|
|
@@ -93590,7 +93999,7 @@ var FIELDS12 = {
|
|
|
93590
93999
|
keywords: "Total organic keywords the page ranks for",
|
|
93591
94000
|
top_10: "Keywords in positions 1-10"
|
|
93592
94001
|
};
|
|
93593
|
-
var relevantPagesCommand =
|
|
94002
|
+
var relevantPagesCommand = defineCommand226({
|
|
93594
94003
|
meta: {
|
|
93595
94004
|
name: "relevant-pages",
|
|
93596
94005
|
description: `Get the top pages of a competitor domain with traffic data.
|
|
@@ -93637,7 +94046,7 @@ Examples:
|
|
|
93637
94046
|
});
|
|
93638
94047
|
|
|
93639
94048
|
// src/commands/research/web.ts
|
|
93640
|
-
import { defineCommand as
|
|
94049
|
+
import { defineCommand as defineCommand227 } from "citty";
|
|
93641
94050
|
registerSchema({
|
|
93642
94051
|
command: "research.web",
|
|
93643
94052
|
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).",
|
|
@@ -93655,7 +94064,7 @@ registerSchema({
|
|
|
93655
94064
|
}
|
|
93656
94065
|
}
|
|
93657
94066
|
});
|
|
93658
|
-
var
|
|
94067
|
+
var TIMEOUT_MS3 = {
|
|
93659
94068
|
medium: 18e4,
|
|
93660
94069
|
high: 36e4,
|
|
93661
94070
|
xhigh: 9e5
|
|
@@ -93671,7 +94080,7 @@ async function runDeepResearch(question) {
|
|
|
93671
94080
|
const { interactionId } = await apiPost("/api/research/deep-research/start", { question });
|
|
93672
94081
|
process.stderr.write(`Deep research started (${interactionId}). Polling...
|
|
93673
94082
|
`);
|
|
93674
|
-
const deadline = Date.now() +
|
|
94083
|
+
const deadline = Date.now() + TIMEOUT_MS3.xhigh;
|
|
93675
94084
|
while (Date.now() < deadline) {
|
|
93676
94085
|
await sleep3(1e4);
|
|
93677
94086
|
const poll = await apiGet("/api/research/deep-research/poll", {
|
|
@@ -93688,7 +94097,7 @@ async function runDeepResearch(question) {
|
|
|
93688
94097
|
}
|
|
93689
94098
|
throw new Error("Deep research timed out");
|
|
93690
94099
|
}
|
|
93691
|
-
var webCommand =
|
|
94100
|
+
var webCommand = defineCommand227({
|
|
93692
94101
|
meta: {
|
|
93693
94102
|
name: "web",
|
|
93694
94103
|
description: `Search the web with AI to answer any open-ended marketing question. Uses live internet data via Google Search.
|
|
@@ -93726,7 +94135,7 @@ Examples:
|
|
|
93726
94135
|
process.exit(1);
|
|
93727
94136
|
}
|
|
93728
94137
|
try {
|
|
93729
|
-
const data = depth === "xhigh" ? await runDeepResearch(question) : await apiPost("/api/research/explore", { question, depth }, { timeoutMs:
|
|
94138
|
+
const data = depth === "xhigh" ? await runDeepResearch(question) : await apiPost("/api/research/explore", { question, depth }, { timeoutMs: TIMEOUT_MS3[depth] });
|
|
93730
94139
|
const format = args8.output || "json";
|
|
93731
94140
|
const hints2 = webDepthHints({ answer: data.answer, sourceCount: data.sources.length, depth });
|
|
93732
94141
|
if (format === "md") {
|
|
@@ -93750,7 +94159,7 @@ Examples:
|
|
|
93750
94159
|
});
|
|
93751
94160
|
|
|
93752
94161
|
// src/commands/research/index.ts
|
|
93753
|
-
var researchCommand =
|
|
94162
|
+
var researchCommand = defineCommand228({
|
|
93754
94163
|
meta: {
|
|
93755
94164
|
name: "research",
|
|
93756
94165
|
description: `Competitive intelligence and AI-powered research commands.
|
|
@@ -93758,6 +94167,7 @@ var researchCommand = defineCommand227({
|
|
|
93758
94167
|
Commands:
|
|
93759
94168
|
web \u2014 Search the web with AI (ask any question)
|
|
93760
94169
|
fetch \u2014 Read a page an ordinary web fetch could not
|
|
94170
|
+
reddit \u2014 Read Reddit verbatim: search posts/comments, read a thread
|
|
93761
94171
|
advertisers \u2014 Who's bidding on a keyword?
|
|
93762
94172
|
autocomplete \u2014 Google Autocomplete suggestions
|
|
93763
94173
|
intent \u2014 Google Search intent classification
|
|
@@ -93773,6 +94183,7 @@ Examples:
|
|
|
93773
94183
|
baker research web "Who are the main competitors of HubSpot?"
|
|
93774
94184
|
baker research web "What is the ICP for CRM buyers?" --depth high
|
|
93775
94185
|
baker research fetch "https://competitor.com/pricing"
|
|
94186
|
+
baker research reddit search "agency never paid" --subreddit AmazonFlexUK --kind comments
|
|
93776
94187
|
baker research advertisers "running shoes"
|
|
93777
94188
|
baker research intent "buy running shoes,best running shoes 2026"
|
|
93778
94189
|
baker research keyword-metrics "chatbot whatsapp,crm whatsapp" --location mx --language es
|
|
@@ -93783,6 +94194,7 @@ Full guide: __tooling__/docs/tools/baker/research.md`
|
|
|
93783
94194
|
subCommands: {
|
|
93784
94195
|
web: webCommand,
|
|
93785
94196
|
fetch: fetchCommand,
|
|
94197
|
+
reddit: redditCommand,
|
|
93786
94198
|
advertisers: advertisersCommand,
|
|
93787
94199
|
autocomplete: autocompleteCommand,
|
|
93788
94200
|
countries: countriesCommand,
|
|
@@ -93797,10 +94209,10 @@ Full guide: __tooling__/docs/tools/baker/research.md`
|
|
|
93797
94209
|
});
|
|
93798
94210
|
|
|
93799
94211
|
// src/commands/scheduled-agents/index.ts
|
|
93800
|
-
import { defineCommand as
|
|
94212
|
+
import { defineCommand as defineCommand239 } from "citty";
|
|
93801
94213
|
|
|
93802
94214
|
// src/commands/scheduled-agents/create.ts
|
|
93803
|
-
import { defineCommand as
|
|
94215
|
+
import { defineCommand as defineCommand229 } from "citty";
|
|
93804
94216
|
|
|
93805
94217
|
// src/commands/scheduled-agents/shared.ts
|
|
93806
94218
|
var TEMP_SCHEDULED_AGENT_PREFIX = "temp_agent_";
|
|
@@ -93808,7 +94220,7 @@ var TEMP_ID_PREFIX = "temp_";
|
|
|
93808
94220
|
function writeOk2(data, hints2) {
|
|
93809
94221
|
writeJson({ ok: true, data: data ?? null, ...hints2 && hints2.length > 0 ? { hints: hints2 } : {} });
|
|
93810
94222
|
}
|
|
93811
|
-
function
|
|
94223
|
+
function failValidation5(message) {
|
|
93812
94224
|
writeJson({ ok: false, error: { code: "VALIDATION_ERROR", message } });
|
|
93813
94225
|
process.exit(1);
|
|
93814
94226
|
}
|
|
@@ -93856,7 +94268,7 @@ function isOtherTempId(id) {
|
|
|
93856
94268
|
}
|
|
93857
94269
|
function validateScheduledAgentRef(ref2) {
|
|
93858
94270
|
if (isOtherTempId(ref2)) {
|
|
93859
|
-
|
|
94271
|
+
failValidation5(`Scheduled agent temp IDs must start with ${TEMP_SCHEDULED_AGENT_PREFIX}.`);
|
|
93860
94272
|
}
|
|
93861
94273
|
if (!isTempScheduledAgentId(ref2)) {
|
|
93862
94274
|
validateConvexId(ref2);
|
|
@@ -93903,14 +94315,14 @@ var NARROWING_ARGS = {
|
|
|
93903
94315
|
};
|
|
93904
94316
|
function validateRunAt(runAt) {
|
|
93905
94317
|
if (!runAt.endsWith("Z")) {
|
|
93906
|
-
|
|
94318
|
+
failValidation5("--run-at must be an ISO UTC timestamp ending in Z.");
|
|
93907
94319
|
}
|
|
93908
94320
|
const parsed = Date.parse(runAt);
|
|
93909
94321
|
if (!Number.isFinite(parsed)) {
|
|
93910
|
-
|
|
94322
|
+
failValidation5("--run-at must be a valid ISO timestamp.");
|
|
93911
94323
|
}
|
|
93912
94324
|
if (parsed <= Date.now()) {
|
|
93913
|
-
|
|
94325
|
+
failValidation5(
|
|
93914
94326
|
`--run-at ${runAt} has already passed. A one-off item only runs at a time still to come \u2014 pass a later ISO UTC timestamp, and check which timezone you converted from if you worked it out from a local time.`
|
|
93915
94327
|
);
|
|
93916
94328
|
}
|
|
@@ -93922,7 +94334,7 @@ function buildTriggerBody(args8, options) {
|
|
|
93922
94334
|
const kind = args8.trigger;
|
|
93923
94335
|
const given = [cron, runAt, kind].filter(Boolean).length;
|
|
93924
94336
|
if (given > 1) {
|
|
93925
|
-
|
|
94337
|
+
failValidation5("--cron, --run-at and --trigger are mutually exclusive.");
|
|
93926
94338
|
}
|
|
93927
94339
|
refuseNarrowingWithoutKind(args8, kind, given);
|
|
93928
94340
|
if (runAt) {
|
|
@@ -93939,7 +94351,7 @@ function buildTriggerBody(args8, options) {
|
|
|
93939
94351
|
return { timezone };
|
|
93940
94352
|
}
|
|
93941
94353
|
if (options.required) {
|
|
93942
|
-
|
|
94354
|
+
failValidation5(
|
|
93943
94355
|
`A trigger is required. Pass --cron or --run-at for a time-based one, or --trigger with one of: ${TRIGGER_KIND_IDS.join(", ")}.`
|
|
93944
94356
|
);
|
|
93945
94357
|
}
|
|
@@ -93951,13 +94363,13 @@ function flagText(args8, key) {
|
|
|
93951
94363
|
}
|
|
93952
94364
|
function refuseMisusedKinds(kind, args8) {
|
|
93953
94365
|
if (kind === "time.once") {
|
|
93954
|
-
|
|
94366
|
+
failValidation5("Use --run-at for a one-off, rather than --trigger time.once.");
|
|
93955
94367
|
}
|
|
93956
94368
|
if (kind === "time.cron") {
|
|
93957
|
-
|
|
94369
|
+
failValidation5("Use --cron for a repeating schedule, rather than --trigger time.cron.");
|
|
93958
94370
|
}
|
|
93959
94371
|
if (kind === "experiment.started" && flagText(args8, "experiment")) {
|
|
93960
|
-
|
|
94372
|
+
failValidation5(
|
|
93961
94373
|
'A test that exists has already started, so --experiment never fires on experiment.started. Leave it off and add --when "page = <page>" to watch one page.'
|
|
93962
94374
|
);
|
|
93963
94375
|
}
|
|
@@ -93970,7 +94382,7 @@ function refuseStrayFlags(kind, args8) {
|
|
|
93970
94382
|
if (stray.length === 0) {
|
|
93971
94383
|
return;
|
|
93972
94384
|
}
|
|
93973
|
-
|
|
94385
|
+
failValidation5(
|
|
93974
94386
|
`${stray.map((flag) => `--${flag}`).join(", ")} does not narrow ${kind}. ${allowed.size > 0 ? `It can be pointed with ${[...allowed].map((flag) => `--${flag}`).join(", ")}.` : "It runs every time it happens \u2014 narrow it with --when rules over its payload instead."}`
|
|
93975
94387
|
);
|
|
93976
94388
|
}
|
|
@@ -93984,7 +94396,7 @@ function refuseNarrowingWithoutKind(args8, kind, given) {
|
|
|
93984
94396
|
return;
|
|
93985
94397
|
}
|
|
93986
94398
|
const flags = stray.map((flag) => `--${flag}`).join(", ");
|
|
93987
|
-
|
|
94399
|
+
failValidation5(
|
|
93988
94400
|
given > 0 ? `${flags} does not narrow --cron or --run-at: a time trigger runs every time it comes round. Use --trigger <kind> with ${flags} instead, or leave ${flags} off.` : `${flags} narrows a trigger, and no trigger was given. Pass --trigger <kind> too \u2014 the item's whole trigger, with ${flags} \u2014 or leave ${flags} off.`
|
|
93989
94401
|
);
|
|
93990
94402
|
}
|
|
@@ -93994,7 +94406,7 @@ function configFromFlag(kind, args8) {
|
|
|
93994
94406
|
return {};
|
|
93995
94407
|
}
|
|
93996
94408
|
if (kind !== "app.event") {
|
|
93997
|
-
|
|
94409
|
+
failValidation5("--config is only for --trigger app.event: the settings of what happens in the tool.");
|
|
93998
94410
|
}
|
|
93999
94411
|
let parsed;
|
|
94000
94412
|
try {
|
|
@@ -94003,13 +94415,13 @@ function configFromFlag(kind, args8) {
|
|
|
94003
94415
|
parsed = null;
|
|
94004
94416
|
}
|
|
94005
94417
|
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
|
|
94006
|
-
|
|
94418
|
+
failValidation5(`--config must be a JSON object, e.g. '{"labelIds":"INBOX"}'.`);
|
|
94007
94419
|
}
|
|
94008
94420
|
return { configJson: config };
|
|
94009
94421
|
}
|
|
94010
94422
|
function triggerFromFlags(kind, args8) {
|
|
94011
94423
|
if (!isTriggerKind(kind)) {
|
|
94012
|
-
|
|
94424
|
+
failValidation5(`--trigger must be one of: ${TRIGGER_KIND_IDS.join(", ")}.`);
|
|
94013
94425
|
}
|
|
94014
94426
|
refuseMisusedKinds(kind, args8);
|
|
94015
94427
|
refuseStrayFlags(kind, args8);
|
|
@@ -94019,7 +94431,7 @@ function triggerFromFlags(kind, args8) {
|
|
|
94019
94431
|
if (value2) {
|
|
94020
94432
|
narrowings[field] = value2;
|
|
94021
94433
|
} else if (required) {
|
|
94022
|
-
|
|
94434
|
+
failValidation5(
|
|
94023
94435
|
`--trigger ${kind} needs --${TRIGGER_TARGET_FIELDS[field].flag}. \`baker scheduled-agents targets --trigger ${kind} --field ${field}\` lists what it can be.`
|
|
94024
94436
|
);
|
|
94025
94437
|
}
|
|
@@ -94031,12 +94443,12 @@ function parseOccurrences(raw) {
|
|
|
94031
94443
|
return void 0;
|
|
94032
94444
|
}
|
|
94033
94445
|
if (typeof raw !== "string") {
|
|
94034
|
-
|
|
94446
|
+
failValidation5("--occurrences must be a comma-separated list of whole numbers, e.g. 1 or 1,3.");
|
|
94035
94447
|
}
|
|
94036
94448
|
const parts = raw.split(",").map((part) => part.trim()).filter((part) => part.length > 0);
|
|
94037
94449
|
const numbers = parts.map((part) => Number(part));
|
|
94038
94450
|
if (numbers.length === 0 || numbers.some((n) => !Number.isInteger(n) || n <= 0)) {
|
|
94039
|
-
|
|
94451
|
+
failValidation5("--occurrences must be a comma-separated list of whole numbers above zero, e.g. 1 or 1,3.");
|
|
94040
94452
|
}
|
|
94041
94453
|
return numbers;
|
|
94042
94454
|
}
|
|
@@ -94050,7 +94462,7 @@ function parseBooleanFlag(raw, flagName) {
|
|
|
94050
94462
|
if (raw === false || raw === "false") {
|
|
94051
94463
|
return false;
|
|
94052
94464
|
}
|
|
94053
|
-
|
|
94465
|
+
failValidation5(`${flagName} must be true or false.`);
|
|
94054
94466
|
}
|
|
94055
94467
|
var REACTION_ARGS = {
|
|
94056
94468
|
when: {
|
|
@@ -94080,7 +94492,7 @@ function wholeNumber(raw, flag, { min }) {
|
|
|
94080
94492
|
}
|
|
94081
94493
|
const value2 = Number(raw);
|
|
94082
94494
|
if (!Number.isInteger(value2) || value2 < min) {
|
|
94083
|
-
|
|
94495
|
+
failValidation5(`${flag} must be a whole number of at least ${min}.`);
|
|
94084
94496
|
}
|
|
94085
94497
|
return value2;
|
|
94086
94498
|
}
|
|
@@ -94100,7 +94512,7 @@ function occurrencesFromFlags(args8) {
|
|
|
94100
94512
|
const times = wholeNumber(args8.times, "--times", { min: 1 });
|
|
94101
94513
|
const occurrences = parseOccurrences(args8.occurrences);
|
|
94102
94514
|
if (times !== void 0 && occurrences !== void 0) {
|
|
94103
|
-
|
|
94515
|
+
failValidation5("Pass --times or --occurrences, not both \u2014 --times 3 is --occurrences 1,2,3.");
|
|
94104
94516
|
}
|
|
94105
94517
|
return times !== void 0 ? firstTimes(times) : occurrences;
|
|
94106
94518
|
}
|
|
@@ -94114,7 +94526,7 @@ function whenFromFlag(raw) {
|
|
|
94114
94526
|
}
|
|
94115
94527
|
const parsed = parseConditionsExpression(text2);
|
|
94116
94528
|
if (!parsed.ok) {
|
|
94117
|
-
|
|
94529
|
+
failValidation5(parsed.error);
|
|
94118
94530
|
}
|
|
94119
94531
|
return text2;
|
|
94120
94532
|
}
|
|
@@ -94123,7 +94535,7 @@ function payloadFromFlag(raw) {
|
|
|
94123
94535
|
return void 0;
|
|
94124
94536
|
}
|
|
94125
94537
|
if (raw !== "include" && raw !== "omit") {
|
|
94126
|
-
|
|
94538
|
+
failValidation5("--payload must be include or omit.");
|
|
94127
94539
|
}
|
|
94128
94540
|
return raw === "include";
|
|
94129
94541
|
}
|
|
@@ -94167,7 +94579,7 @@ registerSchema({
|
|
|
94167
94579
|
}
|
|
94168
94580
|
}
|
|
94169
94581
|
});
|
|
94170
|
-
var createCommand3 =
|
|
94582
|
+
var createCommand3 = defineCommand229({
|
|
94171
94583
|
meta: {
|
|
94172
94584
|
name: "create",
|
|
94173
94585
|
description: 'Stage a scheduled agent. Examples: baker scheduled-agents create --name "Weekly report" --description "..." --prompt "..." --cron "0 9 * * MON" | baker scheduled-agents create --name "Chase a new lead" --description "..." --prompt "Research {{payload.answers.company}} and draft a reply" --trigger form.submitted --form quote | baker scheduled-agents create --name "Big deals" --description "..." --prompt "..." --trigger webhook.received --when "deal.stage = won AND deal.amount > 10000" --times 3'
|
|
@@ -94195,13 +94607,13 @@ var createCommand3 = defineCommand228({
|
|
|
94195
94607
|
const prompt = args8.prompt;
|
|
94196
94608
|
const template = typeof args8.template === "string" ? args8.template.trim() : "";
|
|
94197
94609
|
if (!name || name.trim().length === 0) {
|
|
94198
|
-
|
|
94610
|
+
failValidation5("--name is required.");
|
|
94199
94611
|
}
|
|
94200
94612
|
if (!description || description.trim().length === 0) {
|
|
94201
|
-
|
|
94613
|
+
failValidation5("--description is required.");
|
|
94202
94614
|
}
|
|
94203
94615
|
if (template.length === 0 && (!prompt || prompt.trim().length === 0)) {
|
|
94204
|
-
|
|
94616
|
+
failValidation5("--prompt is required: it is the whole of what a run does. Or pass --template to copy a brief.");
|
|
94205
94617
|
}
|
|
94206
94618
|
const trigger = buildTriggerBody(args8, { required: true });
|
|
94207
94619
|
const reaction = reactionBody(args8);
|
|
@@ -94224,7 +94636,7 @@ var createCommand3 = defineCommand228({
|
|
|
94224
94636
|
});
|
|
94225
94637
|
|
|
94226
94638
|
// src/commands/scheduled-agents/delete.ts
|
|
94227
|
-
import { defineCommand as
|
|
94639
|
+
import { defineCommand as defineCommand230 } from "citty";
|
|
94228
94640
|
registerSchema({
|
|
94229
94641
|
command: "scheduled-agents.delete",
|
|
94230
94642
|
description: "Stage deletion of a published scheduled agent, or cancel one this chat staged (temp_agent_*).",
|
|
@@ -94232,7 +94644,7 @@ registerSchema({
|
|
|
94232
94644
|
id: { type: "string", description: "Published scheduled agent ID or temp_agent_* draft ID", required: true }
|
|
94233
94645
|
}
|
|
94234
94646
|
});
|
|
94235
|
-
var deleteCommand3 =
|
|
94647
|
+
var deleteCommand3 = defineCommand230({
|
|
94236
94648
|
meta: {
|
|
94237
94649
|
name: "delete",
|
|
94238
94650
|
description: "Stage a scheduled agent deletion. Example: baker scheduled-agents delete <id-or-temp_agent_id>"
|
|
@@ -94249,7 +94661,7 @@ var deleteCommand3 = defineCommand229({
|
|
|
94249
94661
|
try {
|
|
94250
94662
|
const id = args8.id || args8["scheduled-agent-id"];
|
|
94251
94663
|
if (!id) {
|
|
94252
|
-
|
|
94664
|
+
failValidation5("Scheduled agent ID is required.");
|
|
94253
94665
|
}
|
|
94254
94666
|
validateScheduledAgentRef(id);
|
|
94255
94667
|
await apiPost("/api/scheduled-agents/delete", { chatId: requireChatId(), id });
|
|
@@ -94261,7 +94673,7 @@ var deleteCommand3 = defineCommand229({
|
|
|
94261
94673
|
});
|
|
94262
94674
|
|
|
94263
94675
|
// src/commands/scheduled-agents/get.ts
|
|
94264
|
-
import { defineCommand as
|
|
94676
|
+
import { defineCommand as defineCommand231 } from "citty";
|
|
94265
94677
|
registerSchema({
|
|
94266
94678
|
command: "scheduled-agents.get",
|
|
94267
94679
|
description: "Get a published scheduled agent, or one this chat has staged (temp_agent_*). A published one comes with runsAs: who each run acts as ({ name, personalTools, companyTools, notSignedIn?, toolsOff? }) \u2014 the tools a run loads, which decides whether a job like reading someone's inbox can work. Its recentRuns and any draftOps this chat staged on it come with it.",
|
|
@@ -94270,7 +94682,7 @@ registerSchema({
|
|
|
94270
94682
|
chat: { type: "string", description: CHAT_READ_ARG.description, required: false }
|
|
94271
94683
|
}
|
|
94272
94684
|
});
|
|
94273
|
-
var getCommand4 =
|
|
94685
|
+
var getCommand4 = defineCommand231({
|
|
94274
94686
|
meta: {
|
|
94275
94687
|
name: "get",
|
|
94276
94688
|
description: "Get a scheduled agent. Example: baker scheduled-agents get <id-or-temp_agent_id>"
|
|
@@ -94288,13 +94700,13 @@ var getCommand4 = defineCommand230({
|
|
|
94288
94700
|
try {
|
|
94289
94701
|
const id = args8.id || args8["scheduled-agent-id"];
|
|
94290
94702
|
if (!id) {
|
|
94291
|
-
|
|
94703
|
+
failValidation5("Scheduled agent ID is required.");
|
|
94292
94704
|
}
|
|
94293
94705
|
validateScheduledAgentRef(id);
|
|
94294
94706
|
const env = getEnv();
|
|
94295
94707
|
const chatId = typeof args8.chat === "string" && args8.chat.length > 0 ? args8.chat : env.BAKER_CHAT_ID;
|
|
94296
94708
|
if (isTempScheduledAgentId(id) && !chatId) {
|
|
94297
|
-
|
|
94709
|
+
failValidation5("BAKER_CHAT_ID or --chat is required to get a staged scheduled agent ID.");
|
|
94298
94710
|
}
|
|
94299
94711
|
const body = { id };
|
|
94300
94712
|
if (chatId) {
|
|
@@ -94309,7 +94721,7 @@ var getCommand4 = defineCommand230({
|
|
|
94309
94721
|
});
|
|
94310
94722
|
|
|
94311
94723
|
// src/commands/scheduled-agents/list.ts
|
|
94312
|
-
import { defineCommand as
|
|
94724
|
+
import { defineCommand as defineCommand232 } from "citty";
|
|
94313
94725
|
var FULL_DESCRIPTION2 = "Return every item and staged change as stored, briefs included (tens of KB). Prefer `get <id>` for one item.";
|
|
94314
94726
|
registerSchema({
|
|
94315
94727
|
command: "scheduled-agents.list",
|
|
@@ -94319,7 +94731,7 @@ registerSchema({
|
|
|
94319
94731
|
full: { type: "boolean", description: FULL_DESCRIPTION2, required: false }
|
|
94320
94732
|
}
|
|
94321
94733
|
});
|
|
94322
|
-
var listCommand19 =
|
|
94734
|
+
var listCommand19 = defineCommand232({
|
|
94323
94735
|
meta: {
|
|
94324
94736
|
name: "list",
|
|
94325
94737
|
description: "List scheduled agents: id, name, trigger and status for each, plus this chat's staged changes when BAKER_CHAT_ID is set (or --chat <id> for an earlier chat's). Briefs are left out. Start here: baker scheduled-agents list; then baker scheduled-agents get <id> for one item's brief."
|
|
@@ -94345,7 +94757,7 @@ var listCommand19 = defineCommand231({
|
|
|
94345
94757
|
});
|
|
94346
94758
|
|
|
94347
94759
|
// src/commands/scheduled-agents/run.ts
|
|
94348
|
-
import { defineCommand as
|
|
94760
|
+
import { defineCommand as defineCommand233 } from "citty";
|
|
94349
94761
|
registerSchema({
|
|
94350
94762
|
command: "scheduled-agents.run",
|
|
94351
94763
|
description: "Run a published scheduled agent now, whatever its trigger says. Opens a Session immediately and returns its chatId. Does not need BAKER_CHAT_ID, and refuses a temp_agent_* id \u2014 a staged item has to be published before it can run.",
|
|
@@ -94353,7 +94765,7 @@ registerSchema({
|
|
|
94353
94765
|
id: { type: "string", description: "Published scheduled agent ID", required: true }
|
|
94354
94766
|
}
|
|
94355
94767
|
});
|
|
94356
|
-
var runCommand2 =
|
|
94768
|
+
var runCommand2 = defineCommand233({
|
|
94357
94769
|
meta: {
|
|
94358
94770
|
name: "run",
|
|
94359
94771
|
description: "Run a published scheduled agent now. Example: baker scheduled-agents run <id>"
|
|
@@ -94370,10 +94782,10 @@ var runCommand2 = defineCommand232({
|
|
|
94370
94782
|
try {
|
|
94371
94783
|
const id = args8.id || args8["scheduled-agent-id"];
|
|
94372
94784
|
if (!id) {
|
|
94373
|
-
|
|
94785
|
+
failValidation5("Scheduled agent ID is required.");
|
|
94374
94786
|
}
|
|
94375
94787
|
if (isTempScheduledAgentId(id)) {
|
|
94376
|
-
|
|
94788
|
+
failValidation5("run needs a published scheduled agent ID, not temp_agent_*. Publish this chat first.");
|
|
94377
94789
|
}
|
|
94378
94790
|
validateConvexId(id);
|
|
94379
94791
|
const response = await apiPost("/api/scheduled-agents/run", { id });
|
|
@@ -94385,7 +94797,7 @@ var runCommand2 = defineCommand232({
|
|
|
94385
94797
|
});
|
|
94386
94798
|
|
|
94387
94799
|
// src/commands/scheduled-agents/targets.ts
|
|
94388
|
-
import { defineCommand as
|
|
94800
|
+
import { defineCommand as defineCommand234 } from "citty";
|
|
94389
94801
|
var ARGS9 = {
|
|
94390
94802
|
trigger: {
|
|
94391
94803
|
type: "string",
|
|
@@ -94419,7 +94831,7 @@ registerSchema({
|
|
|
94419
94831
|
description: "What a trigger can be pointed at: the open Tasks, the company's scheduled agents, its review sources, followed competitors, pages, Forms and their steps, Knowledge collections, tools. Returns each option's value (pass it to the matching flag on create/update) with its name.",
|
|
94420
94832
|
args: ARGS9
|
|
94421
94833
|
});
|
|
94422
|
-
var targetsCommand =
|
|
94834
|
+
var targetsCommand = defineCommand234({
|
|
94423
94835
|
meta: {
|
|
94424
94836
|
name: "targets",
|
|
94425
94837
|
description: `What a trigger can be pointed at \u2014 so "when a Task is picked up" becomes "when THIS Task is picked up".
|
|
@@ -94440,7 +94852,7 @@ Full guide: __tooling__/docs/tools/baker/scheduled-agents.md`
|
|
|
94440
94852
|
run: async ({ args: args8 }) => {
|
|
94441
94853
|
const trigger = args8.trigger;
|
|
94442
94854
|
if (!TRIGGER_KIND_IDS.some((kind) => kind === trigger)) {
|
|
94443
|
-
|
|
94855
|
+
failValidation5(`--trigger must be one of: ${TRIGGER_KIND_IDS.join(", ")}.`);
|
|
94444
94856
|
}
|
|
94445
94857
|
try {
|
|
94446
94858
|
const response = await apiPost("/api/scheduled-agents/targets", {
|
|
@@ -94462,7 +94874,7 @@ Full guide: __tooling__/docs/tools/baker/scheduled-agents.md`
|
|
|
94462
94874
|
// src/commands/scheduled-agents/templates.ts
|
|
94463
94875
|
import { readFile as readFile42 } from "fs/promises";
|
|
94464
94876
|
import path55 from "path";
|
|
94465
|
-
import { defineCommand as
|
|
94877
|
+
import { defineCommand as defineCommand235 } from "citty";
|
|
94466
94878
|
registerSchema({
|
|
94467
94879
|
command: "scheduled-agents.templates",
|
|
94468
94880
|
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.",
|
|
@@ -94517,7 +94929,7 @@ registerSchema({
|
|
|
94517
94929
|
}
|
|
94518
94930
|
}
|
|
94519
94931
|
});
|
|
94520
|
-
var templatesCommand =
|
|
94932
|
+
var templatesCommand = defineCommand235({
|
|
94521
94933
|
meta: {
|
|
94522
94934
|
name: "templates",
|
|
94523
94935
|
description: `The recipes this company can run \u2014 Baker's own plus theirs, with what each one produces.
|
|
@@ -94564,13 +94976,13 @@ Full guide: __tooling__/docs/tools/baker/scheduled-agents.md`
|
|
|
94564
94976
|
const publish = flag("publish");
|
|
94565
94977
|
const remove = flag("delete");
|
|
94566
94978
|
if ([save, publish, remove].filter((id) => id.length > 0).length > 1) {
|
|
94567
|
-
|
|
94979
|
+
failValidation5("Pass one of --save, --publish or --delete at a time.");
|
|
94568
94980
|
}
|
|
94569
94981
|
if (save.length > 0) {
|
|
94570
94982
|
const briefFile = flag("brief-file");
|
|
94571
94983
|
const brief2 = briefFile.length > 0 ? await readFile42(path55.resolve(briefFile), "utf8") : flag("brief");
|
|
94572
94984
|
if (brief2.trim().length === 0) {
|
|
94573
|
-
|
|
94985
|
+
failValidation5("--brief-file (preferred) or --brief is required: the brief is the recipe.");
|
|
94574
94986
|
}
|
|
94575
94987
|
const response2 = await apiPost("/api/marketplace/save", {
|
|
94576
94988
|
chatId: requireChatId(),
|
|
@@ -94613,7 +95025,7 @@ Full guide: __tooling__/docs/tools/baker/scheduled-agents.md`
|
|
|
94613
95025
|
});
|
|
94614
95026
|
|
|
94615
95027
|
// src/commands/scheduled-agents/triggers.ts
|
|
94616
|
-
import { defineCommand as
|
|
95028
|
+
import { defineCommand as defineCommand236 } from "citty";
|
|
94617
95029
|
var ARGS10 = {
|
|
94618
95030
|
trigger: {
|
|
94619
95031
|
type: "string",
|
|
@@ -94699,7 +95111,7 @@ function shapeTriggerCatalog(response, filter) {
|
|
|
94699
95111
|
}
|
|
94700
95112
|
return { ok: true, data: { groups, reacting: catalog.reacting } };
|
|
94701
95113
|
}
|
|
94702
|
-
var triggersCommand2 =
|
|
95114
|
+
var triggersCommand2 = defineCommand236({
|
|
94703
95115
|
meta: {
|
|
94704
95116
|
name: "triggers",
|
|
94705
95117
|
description: `Everything that can start a scheduled agent.
|
|
@@ -94729,7 +95141,7 @@ Full guide: __tooling__/docs/tools/baker/scheduled-agents.md`
|
|
|
94729
95141
|
});
|
|
94730
95142
|
|
|
94731
95143
|
// src/commands/scheduled-agents/unstage.ts
|
|
94732
|
-
import { defineCommand as
|
|
95144
|
+
import { defineCommand as defineCommand237 } from "citty";
|
|
94733
95145
|
registerSchema({
|
|
94734
95146
|
command: "scheduled-agents.unstage",
|
|
94735
95147
|
description: "Take back what this chat staged on one scheduled agent, before Publish \u2014 the same as discarding its row in the change list. With --index, only that one change (its `index` in `baker scheduled-agents list` \u2192 draft.ops). Taking back a create also takes back the edits staged on it. Never touches a published item: to change or remove one, stage update/delete instead.",
|
|
@@ -94749,13 +95161,13 @@ function unstageBody(args8, chatId) {
|
|
|
94749
95161
|
}
|
|
94750
95162
|
const index = Number(args8.index);
|
|
94751
95163
|
if (args8.index.trim() === "" || !Number.isInteger(index) || index < 0) {
|
|
94752
|
-
|
|
95164
|
+
failValidation5(
|
|
94753
95165
|
"--index must be a whole number from `baker scheduled-agents list` \u2192 draft.ops[].index. Leave it off to take back everything staged on the item."
|
|
94754
95166
|
);
|
|
94755
95167
|
}
|
|
94756
95168
|
return { chatId, ref: args8.ref, index };
|
|
94757
95169
|
}
|
|
94758
|
-
var unstageCommand =
|
|
95170
|
+
var unstageCommand = defineCommand237({
|
|
94759
95171
|
meta: {
|
|
94760
95172
|
name: "unstage",
|
|
94761
95173
|
description: "Take back what this chat staged on a scheduled agent, before Publish. Examples: baker scheduled-agents unstage temp_agent_abc123 | baker scheduled-agents unstage <id> --index 2"
|
|
@@ -94773,7 +95185,7 @@ var unstageCommand = defineCommand236({
|
|
|
94773
95185
|
try {
|
|
94774
95186
|
const ref2 = args8.id || args8["scheduled-agent-id"];
|
|
94775
95187
|
if (!ref2) {
|
|
94776
|
-
|
|
95188
|
+
failValidation5("Scheduled agent ID is required.");
|
|
94777
95189
|
}
|
|
94778
95190
|
const index = typeof args8.index === "string" ? args8.index : void 0;
|
|
94779
95191
|
const body = unstageBody({ ref: ref2, ...index !== void 0 ? { index } : {} }, requireChatId());
|
|
@@ -94786,7 +95198,7 @@ var unstageCommand = defineCommand236({
|
|
|
94786
95198
|
});
|
|
94787
95199
|
|
|
94788
95200
|
// src/commands/scheduled-agents/update.ts
|
|
94789
|
-
import { defineCommand as
|
|
95201
|
+
import { defineCommand as defineCommand238 } from "citty";
|
|
94790
95202
|
registerSchema({
|
|
94791
95203
|
command: "scheduled-agents.update",
|
|
94792
95204
|
description: "Stage an update to a published scheduled agent, or to one this chat staged (temp_agent_*).",
|
|
@@ -94813,7 +95225,7 @@ registerSchema({
|
|
|
94813
95225
|
enabled: { type: "string", description: "Replacement enabled state", required: false, enum: ["true", "false"] }
|
|
94814
95226
|
}
|
|
94815
95227
|
});
|
|
94816
|
-
var updateCommand4 =
|
|
95228
|
+
var updateCommand4 = defineCommand238({
|
|
94817
95229
|
meta: {
|
|
94818
95230
|
name: "update",
|
|
94819
95231
|
description: "Stage a scheduled agent update. Examples: baker scheduled-agents update <id> --enabled false | baker scheduled-agents update <id> --trigger form.submitted --form quote"
|
|
@@ -94843,7 +95255,7 @@ var updateCommand4 = defineCommand237({
|
|
|
94843
95255
|
refuseAutoPublish(args8);
|
|
94844
95256
|
const id = args8.id || args8["scheduled-agent-id"];
|
|
94845
95257
|
if (!id) {
|
|
94846
|
-
|
|
95258
|
+
failValidation5("Scheduled agent ID is required.");
|
|
94847
95259
|
}
|
|
94848
95260
|
validateScheduledAgentRef(id);
|
|
94849
95261
|
const body = { id };
|
|
@@ -94870,7 +95282,7 @@ var updateCommand4 = defineCommand237({
|
|
|
94870
95282
|
hasPatch = true;
|
|
94871
95283
|
}
|
|
94872
95284
|
if (!hasPatch) {
|
|
94873
|
-
|
|
95285
|
+
failValidation5(
|
|
94874
95286
|
"Provide at least one of --name, --description, --prompt, --cron, --run-at, --trigger, --occurrences, --times, --when, --payload, --cooldown, --timezone, --enabled."
|
|
94875
95287
|
);
|
|
94876
95288
|
}
|
|
@@ -94884,7 +95296,7 @@ var updateCommand4 = defineCommand237({
|
|
|
94884
95296
|
});
|
|
94885
95297
|
|
|
94886
95298
|
// src/commands/scheduled-agents/index.ts
|
|
94887
|
-
var scheduledAgentsCommand =
|
|
95299
|
+
var scheduledAgentsCommand = defineCommand239({
|
|
94888
95300
|
meta: {
|
|
94889
95301
|
name: "scheduled-agents",
|
|
94890
95302
|
description: `Manage Scheduled agents. Subcommands: list, get, triggers, targets, create, update, delete, unstage, run, templates.
|
|
@@ -94927,14 +95339,14 @@ Full guide: __tooling__/docs/tools/baker/scheduled-agents.md`
|
|
|
94927
95339
|
});
|
|
94928
95340
|
|
|
94929
95341
|
// src/commands/schema.ts
|
|
94930
|
-
import { defineCommand as
|
|
95342
|
+
import { defineCommand as defineCommand240 } from "citty";
|
|
94931
95343
|
function narrowToFamily(commandName, available) {
|
|
94932
95344
|
const segments = commandName.split(".");
|
|
94933
95345
|
const prefix = segments[0] === "ads" && segments[1] ? `ads.${segments[1]}.` : `${segments[0]}.`;
|
|
94934
95346
|
const siblings = available.filter((name) => name.startsWith(prefix));
|
|
94935
95347
|
return siblings.length > 0 ? siblings : available;
|
|
94936
95348
|
}
|
|
94937
|
-
var schemaCommand2 =
|
|
95349
|
+
var schemaCommand2 = defineCommand240({
|
|
94938
95350
|
meta: {
|
|
94939
95351
|
name: "schema",
|
|
94940
95352
|
description: "Inspect command argument schemas (for AI agent introspection). Lists all commands if no argument given. Example: baker schema images search (or images.search)"
|
|
@@ -94979,10 +95391,10 @@ var schemaCommand2 = defineCommand239({
|
|
|
94979
95391
|
});
|
|
94980
95392
|
|
|
94981
95393
|
// src/commands/studio/index.ts
|
|
94982
|
-
import { defineCommand as
|
|
95394
|
+
import { defineCommand as defineCommand249 } from "citty";
|
|
94983
95395
|
|
|
94984
95396
|
// src/commands/studio/animate.ts
|
|
94985
|
-
import { defineCommand as
|
|
95397
|
+
import { defineCommand as defineCommand241 } from "citty";
|
|
94986
95398
|
|
|
94987
95399
|
// src/commands/studio/spokenPace.ts
|
|
94988
95400
|
var WORDS_PER_SECOND = SPOKEN_WORDS_PER_SECOND;
|
|
@@ -95495,7 +95907,7 @@ async function adByHandHintFor(body) {
|
|
|
95495
95907
|
return null;
|
|
95496
95908
|
}
|
|
95497
95909
|
}
|
|
95498
|
-
var animateCommand =
|
|
95910
|
+
var animateCommand = defineCommand241({
|
|
95499
95911
|
meta: {
|
|
95500
95912
|
name: "animate",
|
|
95501
95913
|
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 'she looks to camera and says: \"Hola, soy Elena\"' --avatar elena --quality 720p --aspect-ratio 9:16\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"
|
|
@@ -95620,7 +96032,7 @@ var animateCommand = defineCommand240({
|
|
|
95620
96032
|
});
|
|
95621
96033
|
|
|
95622
96034
|
// src/commands/studio/generate.ts
|
|
95623
|
-
import { defineCommand as
|
|
96035
|
+
import { defineCommand as defineCommand242 } from "citty";
|
|
95624
96036
|
var MODEL_LIST2 = IMAGE_MODEL_IDS;
|
|
95625
96037
|
var DEFAULT_MAX_WAIT_MS2 = 24e4;
|
|
95626
96038
|
registerSchema({
|
|
@@ -95756,7 +96168,7 @@ function buildGenerateBody(args8, prompt) {
|
|
|
95756
96168
|
}
|
|
95757
96169
|
return body;
|
|
95758
96170
|
}
|
|
95759
|
-
var generateCommand =
|
|
96171
|
+
var generateCommand = defineCommand242({
|
|
95760
96172
|
meta: {
|
|
95761
96173
|
name: "generate",
|
|
95762
96174
|
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 (default \u2014 fast, best at editing a reference and at extreme ratios), google/gemini-3-pro-image (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]]'"
|
|
@@ -95839,7 +96251,7 @@ var generateCommand = defineCommand241({
|
|
|
95839
96251
|
});
|
|
95840
96252
|
|
|
95841
96253
|
// src/commands/studio/get.ts
|
|
95842
|
-
import { defineCommand as
|
|
96254
|
+
import { defineCommand as defineCommand243 } from "citty";
|
|
95843
96255
|
registerSchema({
|
|
95844
96256
|
command: "studio.get",
|
|
95845
96257
|
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.",
|
|
@@ -95848,7 +96260,7 @@ registerSchema({
|
|
|
95848
96260
|
full: { type: "boolean", description: "Include settings, references and attribution", required: false }
|
|
95849
96261
|
}
|
|
95850
96262
|
});
|
|
95851
|
-
var getCommand5 =
|
|
96263
|
+
var getCommand5 = defineCommand243({
|
|
95852
96264
|
meta: {
|
|
95853
96265
|
name: "get",
|
|
95854
96266
|
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"
|
|
@@ -95877,7 +96289,7 @@ var getCommand5 = defineCommand242({
|
|
|
95877
96289
|
});
|
|
95878
96290
|
|
|
95879
96291
|
// src/commands/studio/improve.ts
|
|
95880
|
-
import { defineCommand as
|
|
96292
|
+
import { defineCommand as defineCommand244 } from "citty";
|
|
95881
96293
|
var DESCRIPTION7 = "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.";
|
|
95882
96294
|
registerSchema({
|
|
95883
96295
|
command: "studio.improve",
|
|
@@ -95902,7 +96314,7 @@ registerSchema({
|
|
|
95902
96314
|
}
|
|
95903
96315
|
}
|
|
95904
96316
|
});
|
|
95905
|
-
var improveCommand =
|
|
96317
|
+
var improveCommand = defineCommand244({
|
|
95906
96318
|
meta: {
|
|
95907
96319
|
name: "improve",
|
|
95908
96320
|
description: `${DESCRIPTION7}
|
|
@@ -95946,7 +96358,7 @@ Examples:
|
|
|
95946
96358
|
});
|
|
95947
96359
|
|
|
95948
96360
|
// src/commands/studio/keep.ts
|
|
95949
|
-
import { defineCommand as
|
|
96361
|
+
import { defineCommand as defineCommand245 } from "citty";
|
|
95950
96362
|
registerSchema({
|
|
95951
96363
|
command: "studio.keep",
|
|
95952
96364
|
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.",
|
|
@@ -95956,7 +96368,7 @@ registerSchema({
|
|
|
95956
96368
|
undo: { type: "boolean", description: "Un-star an image, or take a kept clip back out", required: false }
|
|
95957
96369
|
}
|
|
95958
96370
|
});
|
|
95959
|
-
var keepCommand =
|
|
96371
|
+
var keepCommand = defineCommand245({
|
|
95960
96372
|
meta: {
|
|
95961
96373
|
name: "keep",
|
|
95962
96374
|
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"
|
|
@@ -96007,7 +96419,7 @@ var keepCommand = defineCommand244({
|
|
|
96007
96419
|
});
|
|
96008
96420
|
|
|
96009
96421
|
// src/commands/studio/list.ts
|
|
96010
|
-
import { defineCommand as
|
|
96422
|
+
import { defineCommand as defineCommand246 } from "citty";
|
|
96011
96423
|
registerSchema({
|
|
96012
96424
|
command: "studio.list",
|
|
96013
96425
|
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.",
|
|
@@ -96018,7 +96430,7 @@ registerSchema({
|
|
|
96018
96430
|
full: { type: "boolean", description: "Include settings, references and attribution", required: false }
|
|
96019
96431
|
}
|
|
96020
96432
|
});
|
|
96021
|
-
var listCommand20 =
|
|
96433
|
+
var listCommand20 = defineCommand246({
|
|
96022
96434
|
meta: {
|
|
96023
96435
|
name: "list",
|
|
96024
96436
|
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"
|
|
@@ -96052,7 +96464,7 @@ var listCommand20 = defineCommand245({
|
|
|
96052
96464
|
});
|
|
96053
96465
|
|
|
96054
96466
|
// src/commands/studio/models.ts
|
|
96055
|
-
import { defineCommand as
|
|
96467
|
+
import { defineCommand as defineCommand247 } from "citty";
|
|
96056
96468
|
var DESCRIPTION8 = "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.";
|
|
96057
96469
|
registerSchema({
|
|
96058
96470
|
command: "studio.models",
|
|
@@ -96139,7 +96551,7 @@ function buildModelCards(kind, model) {
|
|
|
96139
96551
|
const selected = model ? ids2.filter((id) => id === model) : ids2;
|
|
96140
96552
|
return selected.map((id) => build(id));
|
|
96141
96553
|
}
|
|
96142
|
-
var modelsCommand =
|
|
96554
|
+
var modelsCommand = defineCommand247({
|
|
96143
96555
|
meta: {
|
|
96144
96556
|
name: "models",
|
|
96145
96557
|
description: `${DESCRIPTION8}
|
|
@@ -96186,13 +96598,13 @@ Examples:
|
|
|
96186
96598
|
});
|
|
96187
96599
|
|
|
96188
96600
|
// src/commands/studio/skills.ts
|
|
96189
|
-
import { defineCommand as
|
|
96601
|
+
import { defineCommand as defineCommand248 } from "citty";
|
|
96190
96602
|
registerSchema({
|
|
96191
96603
|
command: "studio.skills",
|
|
96192
96604
|
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.",
|
|
96193
96605
|
args: {}
|
|
96194
96606
|
});
|
|
96195
|
-
var skillsCommand =
|
|
96607
|
+
var skillsCommand = defineCommand248({
|
|
96196
96608
|
meta: {
|
|
96197
96609
|
name: "skills",
|
|
96198
96610
|
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"
|
|
@@ -96216,7 +96628,7 @@ var skillsCommand = defineCommand247({
|
|
|
96216
96628
|
});
|
|
96217
96629
|
|
|
96218
96630
|
// src/commands/studio/index.ts
|
|
96219
|
-
var studioCommand =
|
|
96631
|
+
var studioCommand = defineCommand249({
|
|
96220
96632
|
meta: {
|
|
96221
96633
|
name: "studio",
|
|
96222
96634
|
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.
|
|
@@ -96259,14 +96671,14 @@ Full guide: __tooling__/docs/tools/baker/studio.md`
|
|
|
96259
96671
|
});
|
|
96260
96672
|
|
|
96261
96673
|
// src/commands/tag-manager/index.ts
|
|
96262
|
-
import { defineCommand as
|
|
96674
|
+
import { defineCommand as defineCommand253 } from "citty";
|
|
96263
96675
|
|
|
96264
96676
|
// src/commands/tag-manager/draft.ts
|
|
96265
|
-
import { defineCommand as
|
|
96677
|
+
import { defineCommand as defineCommand250 } from "citty";
|
|
96266
96678
|
|
|
96267
96679
|
// src/commands/tag-manager/shared.ts
|
|
96268
96680
|
import { readFileSync as readFileSync23 } from "fs";
|
|
96269
|
-
function
|
|
96681
|
+
function failValidation6(message) {
|
|
96270
96682
|
writeJsonEnvelope({ ok: false, error: { code: "VALIDATION_ERROR", message } });
|
|
96271
96683
|
process.exit(1);
|
|
96272
96684
|
}
|
|
@@ -96274,7 +96686,7 @@ function requireTarget7(args8, entity) {
|
|
|
96274
96686
|
const positional = Array.isArray(args8._) ? args8._[0] : void 0;
|
|
96275
96687
|
const target2 = args8.id ?? args8.target ?? positional;
|
|
96276
96688
|
if (typeof target2 !== "string" || target2.length === 0) {
|
|
96277
|
-
|
|
96689
|
+
failValidation6(`pass the ${entity} id or path as the positional argument`);
|
|
96278
96690
|
}
|
|
96279
96691
|
return target2;
|
|
96280
96692
|
}
|
|
@@ -96283,16 +96695,16 @@ function loadJsonArg2(args8, flag = "json") {
|
|
|
96283
96695
|
const file = args8.file;
|
|
96284
96696
|
const raw = typeof file === "string" && file.length > 0 ? readFileSync23(file, "utf8") : typeof inline === "string" && inline.length > 0 ? inline : void 0;
|
|
96285
96697
|
if (raw === void 0) {
|
|
96286
|
-
|
|
96698
|
+
failValidation6(`pass --${flag} with inline JSON or --file with a path to a JSON file`);
|
|
96287
96699
|
}
|
|
96288
96700
|
try {
|
|
96289
96701
|
const parsed = JSON.parse(raw);
|
|
96290
96702
|
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
96291
|
-
|
|
96703
|
+
failValidation6(`--${flag} must be a JSON object`);
|
|
96292
96704
|
}
|
|
96293
96705
|
return parsed;
|
|
96294
96706
|
} catch {
|
|
96295
|
-
return
|
|
96707
|
+
return failValidation6(`--${flag} is not valid JSON`);
|
|
96296
96708
|
}
|
|
96297
96709
|
}
|
|
96298
96710
|
var RETRYABLE_CODES2 = /* @__PURE__ */ new Set(["RATE_LIMITED", "UNAVAILABLE", "INTERNAL_ERROR", "NETWORK_ERROR", "TIMEOUT"]);
|
|
@@ -96388,13 +96800,13 @@ registerSchema({
|
|
|
96388
96800
|
chat: { type: "string", description: CHAT_READ_ARG.description, required: false }
|
|
96389
96801
|
}
|
|
96390
96802
|
});
|
|
96391
|
-
var draftCommand6 =
|
|
96803
|
+
var draftCommand6 = defineCommand250({
|
|
96392
96804
|
meta: {
|
|
96393
96805
|
name: "draft",
|
|
96394
96806
|
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."
|
|
96395
96807
|
},
|
|
96396
96808
|
subCommands: {
|
|
96397
|
-
list:
|
|
96809
|
+
list: defineCommand250({
|
|
96398
96810
|
meta: {
|
|
96399
96811
|
name: "list",
|
|
96400
96812
|
description: "Review everything staged on this chat (--json for the raw envelope)"
|
|
@@ -96407,7 +96819,7 @@ var draftCommand6 = defineCommand249({
|
|
|
96407
96819
|
await draftList2(args8.json === true, args8.chat);
|
|
96408
96820
|
}
|
|
96409
96821
|
}),
|
|
96410
|
-
show:
|
|
96822
|
+
show: defineCommand250({
|
|
96411
96823
|
meta: {
|
|
96412
96824
|
name: "show",
|
|
96413
96825
|
description: "Print the full staged payload for one change \u2014 the receipt to verify it looks right before publish (never truncated)."
|
|
@@ -96424,7 +96836,7 @@ var draftCommand6 = defineCommand249({
|
|
|
96424
96836
|
);
|
|
96425
96837
|
}
|
|
96426
96838
|
}),
|
|
96427
|
-
amend:
|
|
96839
|
+
amend: defineCommand250({
|
|
96428
96840
|
meta: {
|
|
96429
96841
|
name: "amend",
|
|
96430
96842
|
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."
|
|
@@ -96441,7 +96853,7 @@ var draftCommand6 = defineCommand249({
|
|
|
96441
96853
|
});
|
|
96442
96854
|
}
|
|
96443
96855
|
}),
|
|
96444
|
-
remove:
|
|
96856
|
+
remove: defineCommand250({
|
|
96445
96857
|
meta: { name: "remove", description: "Remove one staged change (cascades to anything depending on it)" },
|
|
96446
96858
|
args: { ref: { type: "positional", description: "Staged ref (gtm_temp_*) or target", required: false } },
|
|
96447
96859
|
run: async ({ args: args8 }) => {
|
|
@@ -96450,7 +96862,7 @@ var draftCommand6 = defineCommand249({
|
|
|
96450
96862
|
});
|
|
96451
96863
|
}
|
|
96452
96864
|
}),
|
|
96453
|
-
clear:
|
|
96865
|
+
clear: defineCommand250({
|
|
96454
96866
|
meta: { name: "clear", description: "Discard all Tag Manager changes staged on this chat" },
|
|
96455
96867
|
run: async () => {
|
|
96456
96868
|
await draftAction3("/api/tag-manager/draft/clear", {});
|
|
@@ -96460,7 +96872,7 @@ var draftCommand6 = defineCommand249({
|
|
|
96460
96872
|
});
|
|
96461
96873
|
|
|
96462
96874
|
// src/commands/tag-manager/read.ts
|
|
96463
|
-
import { defineCommand as
|
|
96875
|
+
import { defineCommand as defineCommand251 } from "citty";
|
|
96464
96876
|
registerSchema({
|
|
96465
96877
|
command: "tagManager.containers",
|
|
96466
96878
|
description: "List the Google Tag Manager containers this company selected. There can be several, and Baker may read and change all of them. Start here to confirm which containers you are managing.",
|
|
@@ -96508,7 +96920,7 @@ function containersHints(containers, unavailableContainers = []) {
|
|
|
96508
96920
|
}
|
|
96509
96921
|
return hints2;
|
|
96510
96922
|
}
|
|
96511
|
-
var containersCommand =
|
|
96923
|
+
var containersCommand = defineCommand251({
|
|
96512
96924
|
meta: {
|
|
96513
96925
|
name: "containers",
|
|
96514
96926
|
description: `List Tag Manager containers selected by this company.
|
|
@@ -96525,7 +96937,7 @@ Start here:
|
|
|
96525
96937
|
}
|
|
96526
96938
|
}
|
|
96527
96939
|
});
|
|
96528
|
-
var readCommand =
|
|
96940
|
+
var readCommand = defineCommand251({
|
|
96529
96941
|
meta: {
|
|
96530
96942
|
name: "read",
|
|
96531
96943
|
description: `Read the current contents of the Tag Manager container \u2014 always do this before staging changes.
|
|
@@ -96567,7 +96979,7 @@ Examples:
|
|
|
96567
96979
|
});
|
|
96568
96980
|
|
|
96569
96981
|
// src/commands/tag-manager/write-commands.ts
|
|
96570
|
-
import { defineCommand as
|
|
96982
|
+
import { defineCommand as defineCommand252 } from "citty";
|
|
96571
96983
|
var CONTAINER_ARG_DESCRIPTION = "Numeric container id (optional only when one container is connected \u2014 run `baker tag-manager containers`)";
|
|
96572
96984
|
var ENTITIES = [
|
|
96573
96985
|
{
|
|
@@ -96623,10 +97035,10 @@ for (const { entity, noun, createHint } of ENTITIES) {
|
|
|
96623
97035
|
});
|
|
96624
97036
|
}
|
|
96625
97037
|
function entityCommand(entity, noun, example) {
|
|
96626
|
-
return
|
|
97038
|
+
return defineCommand252({
|
|
96627
97039
|
meta: { name: entity, description: `Stage ${noun} changes on this chat's Tag Manager draft` },
|
|
96628
97040
|
subCommands: {
|
|
96629
|
-
create:
|
|
97041
|
+
create: defineCommand252({
|
|
96630
97042
|
meta: {
|
|
96631
97043
|
name: "create",
|
|
96632
97044
|
description: `Stage a new ${noun}
|
|
@@ -96648,7 +97060,7 @@ Examples:
|
|
|
96648
97060
|
});
|
|
96649
97061
|
}
|
|
96650
97062
|
}),
|
|
96651
|
-
update:
|
|
97063
|
+
update: defineCommand252({
|
|
96652
97064
|
meta: {
|
|
96653
97065
|
name: "update",
|
|
96654
97066
|
description: `Stage an update to an existing ${noun} (pass its id or path)`
|
|
@@ -96668,7 +97080,7 @@ Examples:
|
|
|
96668
97080
|
});
|
|
96669
97081
|
}
|
|
96670
97082
|
}),
|
|
96671
|
-
delete:
|
|
97083
|
+
delete: defineCommand252({
|
|
96672
97084
|
meta: { name: "delete", description: `Stage the deletion of a ${noun} (pass its id or path)` },
|
|
96673
97085
|
args: {
|
|
96674
97086
|
id: { type: "positional", description: `${noun} id or path`, required: false },
|
|
@@ -96709,7 +97121,7 @@ function builtinTypes(args8) {
|
|
|
96709
97121
|
}
|
|
96710
97122
|
return raw.split(",").map((entry) => entry.trim());
|
|
96711
97123
|
}
|
|
96712
|
-
var builtinCommand =
|
|
97124
|
+
var builtinCommand = defineCommand252({
|
|
96713
97125
|
meta: {
|
|
96714
97126
|
name: "builtin",
|
|
96715
97127
|
description: `Enable or disable built-in variables
|
|
@@ -96719,7 +97131,7 @@ Examples:
|
|
|
96719
97131
|
baker tag-manager builtin disable --types formId`
|
|
96720
97132
|
},
|
|
96721
97133
|
subCommands: {
|
|
96722
|
-
enable:
|
|
97134
|
+
enable: defineCommand252({
|
|
96723
97135
|
meta: { name: "enable", description: "Stage enabling built-in variables" },
|
|
96724
97136
|
args: {
|
|
96725
97137
|
types: { type: "string", description: "Comma-separated types", required: false },
|
|
@@ -96733,7 +97145,7 @@ Examples:
|
|
|
96733
97145
|
});
|
|
96734
97146
|
}
|
|
96735
97147
|
}),
|
|
96736
|
-
disable:
|
|
97148
|
+
disable: defineCommand252({
|
|
96737
97149
|
meta: { name: "disable", description: "Stage disabling built-in variables" },
|
|
96738
97150
|
args: {
|
|
96739
97151
|
types: { type: "string", description: "Comma-separated types", required: false },
|
|
@@ -96751,7 +97163,7 @@ Examples:
|
|
|
96751
97163
|
});
|
|
96752
97164
|
|
|
96753
97165
|
// src/commands/tag-manager/index.ts
|
|
96754
|
-
var tagManagerCommand =
|
|
97166
|
+
var tagManagerCommand = defineCommand253({
|
|
96755
97167
|
meta: {
|
|
96756
97168
|
name: "tag-manager",
|
|
96757
97169
|
description: `Read and change what lives inside the client's Google Tag Manager container \u2014 tags, triggers, variables, folders and built-in variables.
|
|
@@ -96788,7 +97200,7 @@ Full guide: __tooling__/docs/tools/baker/tag-manager.md`
|
|
|
96788
97200
|
});
|
|
96789
97201
|
|
|
96790
97202
|
// src/commands/tags/index.ts
|
|
96791
|
-
import { defineCommand as
|
|
97203
|
+
import { defineCommand as defineCommand254 } from "citty";
|
|
96792
97204
|
|
|
96793
97205
|
// src/commands/tags/shared.ts
|
|
96794
97206
|
function failApi3(err) {
|
|
@@ -96868,7 +97280,7 @@ async function listTags(json) {
|
|
|
96868
97280
|
var listArgs12 = {
|
|
96869
97281
|
json: { type: "boolean", description: "Print the raw JSON envelope instead of the readable list" }
|
|
96870
97282
|
};
|
|
96871
|
-
var listCommand21 =
|
|
97283
|
+
var listCommand21 = defineCommand254({
|
|
96872
97284
|
meta: {
|
|
96873
97285
|
name: "list",
|
|
96874
97286
|
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"
|
|
@@ -96887,7 +97299,7 @@ async function listDraft4(chat) {
|
|
|
96887
97299
|
failApi3(err);
|
|
96888
97300
|
}
|
|
96889
97301
|
}
|
|
96890
|
-
var draftCommand7 =
|
|
97302
|
+
var draftCommand7 = defineCommand254({
|
|
96891
97303
|
meta: {
|
|
96892
97304
|
name: "draft",
|
|
96893
97305
|
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."
|
|
@@ -96897,7 +97309,7 @@ var draftCommand7 = defineCommand253({
|
|
|
96897
97309
|
await listDraft4(args8.chat);
|
|
96898
97310
|
}
|
|
96899
97311
|
});
|
|
96900
|
-
var tagsCommand4 =
|
|
97312
|
+
var tagsCommand4 = defineCommand254({
|
|
96901
97313
|
meta: {
|
|
96902
97314
|
name: "tags",
|
|
96903
97315
|
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.
|
|
@@ -96926,10 +97338,10 @@ Full guide: __tooling__/docs/tools/baker/tags.md`
|
|
|
96926
97338
|
});
|
|
96927
97339
|
|
|
96928
97340
|
// src/commands/testimonials/index.ts
|
|
96929
|
-
import { defineCommand as
|
|
97341
|
+
import { defineCommand as defineCommand258 } from "citty";
|
|
96930
97342
|
|
|
96931
97343
|
// src/commands/testimonials/get.ts
|
|
96932
|
-
import { defineCommand as
|
|
97344
|
+
import { defineCommand as defineCommand255 } from "citty";
|
|
96933
97345
|
registerSchema({
|
|
96934
97346
|
command: "testimonials.get",
|
|
96935
97347
|
description: "Get a single testimonial by ID",
|
|
@@ -96937,7 +97349,7 @@ registerSchema({
|
|
|
96937
97349
|
id: { type: "string", description: "Testimonial ID", required: true }
|
|
96938
97350
|
}
|
|
96939
97351
|
});
|
|
96940
|
-
var getCommand6 =
|
|
97352
|
+
var getCommand6 = defineCommand255({
|
|
96941
97353
|
meta: { name: "get", description: "Get a single testimonial by ID. Example: baker testimonials get j571abc123" },
|
|
96942
97354
|
args: {
|
|
96943
97355
|
id: { type: "positional", description: "Testimonial ID", required: false },
|
|
@@ -96974,7 +97386,7 @@ var getCommand6 = defineCommand254({
|
|
|
96974
97386
|
});
|
|
96975
97387
|
|
|
96976
97388
|
// src/commands/testimonials/list.ts
|
|
96977
|
-
import { defineCommand as
|
|
97389
|
+
import { defineCommand as defineCommand256 } from "citty";
|
|
96978
97390
|
|
|
96979
97391
|
// src/commands/testimonials/emptyCorpusHints.ts
|
|
96980
97392
|
function resolveEmptyReason({
|
|
@@ -97131,7 +97543,7 @@ function buildListParams(args8) {
|
|
|
97131
97543
|
}
|
|
97132
97544
|
return params;
|
|
97133
97545
|
}
|
|
97134
|
-
var listCommand22 =
|
|
97546
|
+
var listCommand22 = defineCommand256({
|
|
97135
97547
|
meta: {
|
|
97136
97548
|
name: "list",
|
|
97137
97549
|
description: "List testimonials with optional filters. Example: baker testimonials list --source google --sentiment positive"
|
|
@@ -97191,7 +97603,7 @@ var listCommand22 = defineCommand255({
|
|
|
97191
97603
|
});
|
|
97192
97604
|
|
|
97193
97605
|
// src/commands/testimonials/search.ts
|
|
97194
|
-
import { defineCommand as
|
|
97606
|
+
import { defineCommand as defineCommand257 } from "citty";
|
|
97195
97607
|
var FILTER_FLAGS2 = ["source", "rating-min", "rating-max", "status", "sentiment", "language", "tags"];
|
|
97196
97608
|
function languageBiasHint(results, requestedLanguage) {
|
|
97197
97609
|
if (requestedLanguage) {
|
|
@@ -97270,7 +97682,7 @@ function buildSearchRequest(query, args8) {
|
|
|
97270
97682
|
}
|
|
97271
97683
|
return body;
|
|
97272
97684
|
}
|
|
97273
|
-
var
|
|
97685
|
+
var searchCommand4 = defineCommand257({
|
|
97274
97686
|
meta: {
|
|
97275
97687
|
name: "search",
|
|
97276
97688
|
description: "Semantic search testimonials by text query. Uses hybrid BM25 + vector + reranking. Example: baker testimonials search 'great service' --rating-min 4"
|
|
@@ -97334,7 +97746,7 @@ var searchCommand3 = defineCommand256({
|
|
|
97334
97746
|
var tagsCommand5 = makeTagsCommand("testimonials", "testimonial", "/api/testimonials/tags");
|
|
97335
97747
|
|
|
97336
97748
|
// src/commands/testimonials/index.ts
|
|
97337
|
-
var testimonialsCommand =
|
|
97749
|
+
var testimonialsCommand = defineCommand258({
|
|
97338
97750
|
meta: {
|
|
97339
97751
|
name: "testimonials",
|
|
97340
97752
|
description: `Find and browse testimonials in Baker. Subcommands: search, get, list, tags.
|
|
@@ -97349,17 +97761,17 @@ Full guide: __tooling__/docs/tools/baker/testimonials.md`
|
|
|
97349
97761
|
},
|
|
97350
97762
|
subCommands: {
|
|
97351
97763
|
get: getCommand6,
|
|
97352
|
-
search:
|
|
97764
|
+
search: searchCommand4,
|
|
97353
97765
|
list: listCommand22,
|
|
97354
97766
|
tags: tagsCommand5
|
|
97355
97767
|
}
|
|
97356
97768
|
});
|
|
97357
97769
|
|
|
97358
97770
|
// src/commands/videos/index.ts
|
|
97359
|
-
import { defineCommand as
|
|
97771
|
+
import { defineCommand as defineCommand267 } from "citty";
|
|
97360
97772
|
|
|
97361
97773
|
// src/commands/videos/delete.ts
|
|
97362
|
-
import { defineCommand as
|
|
97774
|
+
import { defineCommand as defineCommand259 } from "citty";
|
|
97363
97775
|
registerSchema({
|
|
97364
97776
|
command: "videos.delete",
|
|
97365
97777
|
description: "Delete a video by ID",
|
|
@@ -97373,7 +97785,7 @@ registerSchema({
|
|
|
97373
97785
|
}
|
|
97374
97786
|
}
|
|
97375
97787
|
});
|
|
97376
|
-
var deleteCommand4 =
|
|
97788
|
+
var deleteCommand4 = defineCommand259({
|
|
97377
97789
|
meta: {
|
|
97378
97790
|
name: "delete",
|
|
97379
97791
|
description: "Delete a video by ID. Use --dry-run to preview. Example: baker videos delete j571abc123 --dry-run"
|
|
@@ -97414,7 +97826,7 @@ var deleteCommand4 = defineCommand258({
|
|
|
97414
97826
|
});
|
|
97415
97827
|
|
|
97416
97828
|
// src/commands/videos/describe.ts
|
|
97417
|
-
import { defineCommand as
|
|
97829
|
+
import { defineCommand as defineCommand260 } from "citty";
|
|
97418
97830
|
var DESCRIPTION_HELP2 = "What the clip actually shows, in the words someone would search for it by. This is what `baker videos search` retrieves on.";
|
|
97419
97831
|
registerSchema({
|
|
97420
97832
|
command: "videos.describe",
|
|
@@ -97431,7 +97843,7 @@ registerSchema({
|
|
|
97431
97843
|
full: { type: "boolean", description: "Return the whole library row, not just what changed", required: false }
|
|
97432
97844
|
}
|
|
97433
97845
|
});
|
|
97434
|
-
var describeCommand2 =
|
|
97846
|
+
var describeCommand2 = defineCommand260({
|
|
97435
97847
|
meta: {
|
|
97436
97848
|
name: "describe",
|
|
97437
97849
|
description: `Correct what the library says a video is. Only the fields you pass change; the rest keep their current values.
|
|
@@ -97493,7 +97905,7 @@ import { constants } from "fs";
|
|
|
97493
97905
|
import { copyFile as copyFile2, mkdir as mkdir17, mkdtemp as mkdtemp3, rm as rm10 } from "fs/promises";
|
|
97494
97906
|
import { tmpdir as tmpdir4 } from "os";
|
|
97495
97907
|
import path56 from "path";
|
|
97496
|
-
import { defineCommand as
|
|
97908
|
+
import { defineCommand as defineCommand261 } from "citty";
|
|
97497
97909
|
|
|
97498
97910
|
// src/commands/videos/videoPlatforms.ts
|
|
97499
97911
|
var PLATFORM_DOMAINS = {
|
|
@@ -97631,7 +98043,7 @@ function positiveInt(value2) {
|
|
|
97631
98043
|
const parsed = typeof value2 === "string" ? Number.parseInt(value2, 10) : Number.NaN;
|
|
97632
98044
|
return Number.isInteger(parsed) && parsed > 0 ? parsed : void 0;
|
|
97633
98045
|
}
|
|
97634
|
-
var fetchCommand2 =
|
|
98046
|
+
var fetchCommand2 = defineCommand261({
|
|
97635
98047
|
meta: {
|
|
97636
98048
|
name: "fetch",
|
|
97637
98049
|
description: "Download a video page to a local .mp4 without adding it to the library. Same downloader as `ingest` (proxy fallback, duration check).\n\nExample: baker videos fetch https://www.youtube.com/watch?v=abc123 --out ./clips"
|
|
@@ -97717,7 +98129,7 @@ async function placeInto(outDir, source, stem) {
|
|
|
97717
98129
|
}
|
|
97718
98130
|
|
|
97719
98131
|
// src/commands/videos/get.ts
|
|
97720
|
-
import { defineCommand as
|
|
98132
|
+
import { defineCommand as defineCommand262 } from "citty";
|
|
97721
98133
|
registerSchema({
|
|
97722
98134
|
command: "videos.get",
|
|
97723
98135
|
description: "Get a single video by ID",
|
|
@@ -97725,7 +98137,7 @@ registerSchema({
|
|
|
97725
98137
|
id: { type: "string", description: "Video ID", required: true }
|
|
97726
98138
|
}
|
|
97727
98139
|
});
|
|
97728
|
-
var getCommand7 =
|
|
98140
|
+
var getCommand7 = defineCommand262({
|
|
97729
98141
|
meta: { name: "get", description: "Get a single video by ID. Example: baker videos get j571abc123" },
|
|
97730
98142
|
args: {
|
|
97731
98143
|
id: { type: "positional", description: "Video ID", required: false },
|
|
@@ -97762,7 +98174,7 @@ var getCommand7 = defineCommand261({
|
|
|
97762
98174
|
});
|
|
97763
98175
|
|
|
97764
98176
|
// src/commands/videos/group.ts
|
|
97765
|
-
import { defineCommand as
|
|
98177
|
+
import { defineCommand as defineCommand263 } from "citty";
|
|
97766
98178
|
registerSchema({
|
|
97767
98179
|
command: "videos.group",
|
|
97768
98180
|
description: "List every clip and image that arrived in the same set as this video (carousel slides, one page)",
|
|
@@ -97771,7 +98183,7 @@ registerSchema({
|
|
|
97771
98183
|
"group-key": { type: "string", description: "The set key directly, when you already have it", required: false }
|
|
97772
98184
|
}
|
|
97773
98185
|
});
|
|
97774
|
-
var groupCommand2 =
|
|
98186
|
+
var groupCommand2 = defineCommand263({
|
|
97775
98187
|
meta: {
|
|
97776
98188
|
name: "group",
|
|
97777
98189
|
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>"
|
|
@@ -97794,7 +98206,7 @@ var groupCommand2 = defineCommand262({
|
|
|
97794
98206
|
import { mkdtemp as mkdtemp4, rm as rm11, stat as stat12 } from "fs/promises";
|
|
97795
98207
|
import { tmpdir as tmpdir5 } from "os";
|
|
97796
98208
|
import path57 from "path";
|
|
97797
|
-
import { defineCommand as
|
|
98209
|
+
import { defineCommand as defineCommand264 } from "citty";
|
|
97798
98210
|
|
|
97799
98211
|
// src/lib/streamUpload.ts
|
|
97800
98212
|
import { createHash as createHash3 } from "crypto";
|
|
@@ -97847,7 +98259,7 @@ registerSchema({
|
|
|
97847
98259
|
"dry-run": { type: "boolean", description: "Preview the operation without executing", required: false }
|
|
97848
98260
|
}
|
|
97849
98261
|
});
|
|
97850
|
-
var ingestCommand2 =
|
|
98262
|
+
var ingestCommand2 = defineCommand264({
|
|
97851
98263
|
meta: {
|
|
97852
98264
|
name: "ingest",
|
|
97853
98265
|
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"
|
|
@@ -98109,7 +98521,7 @@ async function uploadToAssetStore(filePath, sizeBytes) {
|
|
|
98109
98521
|
}
|
|
98110
98522
|
|
|
98111
98523
|
// src/commands/videos/search.ts
|
|
98112
|
-
import { defineCommand as
|
|
98524
|
+
import { defineCommand as defineCommand265 } from "citty";
|
|
98113
98525
|
registerSchema({
|
|
98114
98526
|
command: "videos.search",
|
|
98115
98527
|
description: "Search videos by text query. Only returns ready videos.",
|
|
@@ -98119,7 +98531,23 @@ registerSchema({
|
|
|
98119
98531
|
tags: { type: "string", description: "Comma-separated tags to filter by", required: false }
|
|
98120
98532
|
}
|
|
98121
98533
|
});
|
|
98122
|
-
|
|
98534
|
+
function searchHints(results) {
|
|
98535
|
+
const hints2 = [];
|
|
98536
|
+
const parody = results.filter((r) => r.analysis?.tone === "parody").map((r) => r._id);
|
|
98537
|
+
if (parody.length > 0) {
|
|
98538
|
+
hints2.push(
|
|
98539
|
+
`tone: parody \u2014 ${parody.join(", ")}. These play the offer for laughs: fine for a social post, wrong as proof or on a landing page.`
|
|
98540
|
+
);
|
|
98541
|
+
}
|
|
98542
|
+
const unchecked = results.filter((r) => r.analysis?.tone === void 0).map((r) => r._id);
|
|
98543
|
+
if (unchecked.length > 0) {
|
|
98544
|
+
hints2.push(
|
|
98545
|
+
`No format/tone/productClaims yet \u2014 ${unchecked.join(", ")}. Before putting one on a page, read its transcript, scenes and people (\`baker videos get <id> --full\`) and judge it yourself: is it about the offer, is it sincere, and who is speaking?`
|
|
98546
|
+
);
|
|
98547
|
+
}
|
|
98548
|
+
return hints2.length > 0 ? hints2 : void 0;
|
|
98549
|
+
}
|
|
98550
|
+
var searchCommand5 = defineCommand265({
|
|
98123
98551
|
meta: {
|
|
98124
98552
|
name: "search",
|
|
98125
98553
|
description: "Semantic search videos by text query. Uses hybrid BM25 + vector + reranking. Example: baker videos search 'product demo' --tags tutorial"
|
|
@@ -98148,7 +98576,7 @@ var searchCommand4 = defineCommand264({
|
|
|
98148
98576
|
}
|
|
98149
98577
|
const data = await apiPost("/api/videos/search", body);
|
|
98150
98578
|
writeOutput(
|
|
98151
|
-
{ ok: true, data },
|
|
98579
|
+
{ ok: true, data, hints: searchHints(data) },
|
|
98152
98580
|
args8.output || "json",
|
|
98153
98581
|
args8.fields ? args8.fields.split(",") : void 0,
|
|
98154
98582
|
args8.full,
|
|
@@ -98171,7 +98599,7 @@ var tagsCommand6 = makeTagsCommand("videos", "video", "/api/videos/tags");
|
|
|
98171
98599
|
// src/commands/videos/upload.ts
|
|
98172
98600
|
import { stat as stat13 } from "fs/promises";
|
|
98173
98601
|
import { basename as basename4 } from "path";
|
|
98174
|
-
import { defineCommand as
|
|
98602
|
+
import { defineCommand as defineCommand266 } from "citty";
|
|
98175
98603
|
registerSchema({
|
|
98176
98604
|
command: "videos.upload",
|
|
98177
98605
|
description: "Upload a video to Baker \u2014 a local file (via Mux direct upload) or a remote http(s) URL.",
|
|
@@ -98198,7 +98626,7 @@ registerSchema({
|
|
|
98198
98626
|
function isRemoteUrl3(value2) {
|
|
98199
98627
|
return /^https?:\/\//i.test(value2);
|
|
98200
98628
|
}
|
|
98201
|
-
var uploadCommand2 =
|
|
98629
|
+
var uploadCommand2 = defineCommand266({
|
|
98202
98630
|
meta: {
|
|
98203
98631
|
name: "upload",
|
|
98204
98632
|
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"
|
|
@@ -98267,7 +98695,7 @@ var uploadCommand2 = defineCommand265({
|
|
|
98267
98695
|
});
|
|
98268
98696
|
|
|
98269
98697
|
// src/commands/videos/index.ts
|
|
98270
|
-
var videosCommand =
|
|
98698
|
+
var videosCommand = defineCommand267({
|
|
98271
98699
|
meta: {
|
|
98272
98700
|
name: "videos",
|
|
98273
98701
|
description: `Find and manage videos in Baker. Subcommands: search, get, upload, ingest, fetch, describe, delete, tags.
|
|
@@ -98287,7 +98715,7 @@ Full guide: __tooling__/docs/tools/baker/videos.md`
|
|
|
98287
98715
|
subCommands: {
|
|
98288
98716
|
get: getCommand7,
|
|
98289
98717
|
group: groupCommand2,
|
|
98290
|
-
search:
|
|
98718
|
+
search: searchCommand5,
|
|
98291
98719
|
upload: uploadCommand2,
|
|
98292
98720
|
ingest: ingestCommand2,
|
|
98293
98721
|
fetch: fetchCommand2,
|
|
@@ -98298,10 +98726,10 @@ Full guide: __tooling__/docs/tools/baker/videos.md`
|
|
|
98298
98726
|
});
|
|
98299
98727
|
|
|
98300
98728
|
// src/commands/winning-ads/index.ts
|
|
98301
|
-
import { defineCommand as
|
|
98729
|
+
import { defineCommand as defineCommand278 } from "citty";
|
|
98302
98730
|
|
|
98303
98731
|
// src/commands/winning-ads/advertisers.ts
|
|
98304
|
-
import { defineCommand as
|
|
98732
|
+
import { defineCommand as defineCommand268 } from "citty";
|
|
98305
98733
|
|
|
98306
98734
|
// src/commands/winning-ads/shared.ts
|
|
98307
98735
|
function splitList4(value2) {
|
|
@@ -98354,7 +98782,7 @@ function advertiserNormalizer(record, full) {
|
|
|
98354
98782
|
last_synced_at: record.last_synced_at ?? null
|
|
98355
98783
|
};
|
|
98356
98784
|
}
|
|
98357
|
-
var advertisersCommand2 =
|
|
98785
|
+
var advertisersCommand2 = defineCommand268({
|
|
98358
98786
|
meta: {
|
|
98359
98787
|
name: "advertisers",
|
|
98360
98788
|
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'
|
|
@@ -98412,7 +98840,7 @@ var advertisersCommand2 = defineCommand267({
|
|
|
98412
98840
|
});
|
|
98413
98841
|
|
|
98414
98842
|
// src/commands/winning-ads/content.ts
|
|
98415
|
-
import { defineCommand as
|
|
98843
|
+
import { defineCommand as defineCommand269 } from "citty";
|
|
98416
98844
|
registerSchema({
|
|
98417
98845
|
command: "winning-ads.content",
|
|
98418
98846
|
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. Static and carousel ads return the text drawn into the image with the job each piece does (headline, benefit, cta\u2026), the card it sits on, and their format_pattern. Add --full for how it is built (composition, colours, CTA, markers), how it persuades (awareness, mechanism, pains, desires, proof, objections), what it offers (offer type, price, guarantee, urgency), plus speech, pacing and soundtrack for video.",
|
|
@@ -98425,7 +98853,7 @@ registerSchema({
|
|
|
98425
98853
|
}
|
|
98426
98854
|
}
|
|
98427
98855
|
});
|
|
98428
|
-
var contentCommand =
|
|
98856
|
+
var contentCommand = defineCommand269({
|
|
98429
98857
|
meta: {
|
|
98430
98858
|
name: "content",
|
|
98431
98859
|
description: "Read the transcript + on-screen text + copy of one winning ad; --full adds its build, persuasion and offer. Example: baker winning-ads content adg_123 --platform meta --full --output md"
|
|
@@ -98474,7 +98902,7 @@ var contentCommand = defineCommand268({
|
|
|
98474
98902
|
});
|
|
98475
98903
|
|
|
98476
98904
|
// src/commands/winning-ads/feed.ts
|
|
98477
|
-
import { defineCommand as
|
|
98905
|
+
import { defineCommand as defineCommand270 } from "citty";
|
|
98478
98906
|
function buildFeedParams(input) {
|
|
98479
98907
|
const params = {};
|
|
98480
98908
|
const advertiser = splitList4(input.advertiser);
|
|
@@ -98526,7 +98954,7 @@ registerSchema({
|
|
|
98526
98954
|
format: { type: "string", description: "Comma-separated formats to include (e.g. static,video)", required: false }
|
|
98527
98955
|
}
|
|
98528
98956
|
});
|
|
98529
|
-
var feedCommand2 =
|
|
98957
|
+
var feedCommand2 = defineCommand270({
|
|
98530
98958
|
meta: {
|
|
98531
98959
|
name: "feed",
|
|
98532
98960
|
description: "Winners across every brand you follow (browse, then trim per advertiser). Example: baker winning-ads feed --per-advertiser 5 --output md"
|
|
@@ -98611,7 +99039,7 @@ var feedCommand2 = defineCommand269({
|
|
|
98611
99039
|
});
|
|
98612
99040
|
|
|
98613
99041
|
// src/commands/winning-ads/follow.ts
|
|
98614
|
-
import { defineCommand as
|
|
99042
|
+
import { defineCommand as defineCommand271 } from "citty";
|
|
98615
99043
|
var PLATFORMS = adLibraryPlatformSchema.options;
|
|
98616
99044
|
registerSchema({
|
|
98617
99045
|
command: "winning-ads.follow",
|
|
@@ -98626,7 +99054,7 @@ registerSchema({
|
|
|
98626
99054
|
label: { type: "string", description: "Optional display label (defaults to the resolved name)", required: false }
|
|
98627
99055
|
}
|
|
98628
99056
|
});
|
|
98629
|
-
var followCommand =
|
|
99057
|
+
var followCommand = defineCommand271({
|
|
98630
99058
|
meta: {
|
|
98631
99059
|
name: "follow",
|
|
98632
99060
|
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 every platform we can resolve. Example: baker winning-ads follow "deel.com" --platform meta'
|
|
@@ -98673,7 +99101,7 @@ var followCommand = defineCommand270({
|
|
|
98673
99101
|
});
|
|
98674
99102
|
|
|
98675
99103
|
// src/commands/winning-ads/follow-competitors.ts
|
|
98676
|
-
import { defineCommand as
|
|
99104
|
+
import { defineCommand as defineCommand272 } from "citty";
|
|
98677
99105
|
var PLATFORMS2 = adLibraryPlatformSchema.options;
|
|
98678
99106
|
var BATCH_TIMEOUT_MS = 3e5;
|
|
98679
99107
|
function buildFollowBatchBody(input) {
|
|
@@ -98706,7 +99134,7 @@ registerSchema({
|
|
|
98706
99134
|
}
|
|
98707
99135
|
}
|
|
98708
99136
|
});
|
|
98709
|
-
var followCompetitorsCommand =
|
|
99137
|
+
var followCompetitorsCommand = defineCommand272({
|
|
98710
99138
|
meta: {
|
|
98711
99139
|
name: "follow-competitors",
|
|
98712
99140
|
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"'
|
|
@@ -98781,7 +99209,7 @@ var followCompetitorsCommand = defineCommand271({
|
|
|
98781
99209
|
});
|
|
98782
99210
|
|
|
98783
99211
|
// src/commands/winning-ads/following.ts
|
|
98784
|
-
import { defineCommand as
|
|
99212
|
+
import { defineCommand as defineCommand273 } from "citty";
|
|
98785
99213
|
registerSchema({
|
|
98786
99214
|
command: "winning-ads.following",
|
|
98787
99215
|
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.",
|
|
@@ -98835,7 +99263,7 @@ function followingNormalizer(record, full) {
|
|
|
98835
99263
|
platforms: Array.isArray(record.platforms) ? record.platforms : []
|
|
98836
99264
|
};
|
|
98837
99265
|
}
|
|
98838
|
-
var followingCommand =
|
|
99266
|
+
var followingCommand = defineCommand273({
|
|
98839
99267
|
meta: {
|
|
98840
99268
|
name: "following",
|
|
98841
99269
|
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"
|
|
@@ -98871,7 +99299,7 @@ var followingCommand = defineCommand272({
|
|
|
98871
99299
|
});
|
|
98872
99300
|
|
|
98873
99301
|
// src/commands/winning-ads/search.ts
|
|
98874
|
-
import { defineCommand as
|
|
99302
|
+
import { defineCommand as defineCommand274 } from "citty";
|
|
98875
99303
|
registerSchema({
|
|
98876
99304
|
command: "winning-ads.search",
|
|
98877
99305
|
description: "Search the ad-dna corpus of scored winning ads, the company's followed brands first. Returns a lean shortlist (advertiser, summary, scores, days_active/active/winner_category as proof, media_url, and visual/container/mechanism when known) to pick a reference to reproduce. Each search is a paid reranker + judge call: one strong search, at most one adjusted retry. A value outside a closed list (--platform, --format, --winner-category, --awareness, --format-pattern, --sort) is refused with error.fix.validValues.",
|
|
@@ -99012,7 +99440,7 @@ function buildSearchBody2(args8) {
|
|
|
99012
99440
|
}
|
|
99013
99441
|
return body;
|
|
99014
99442
|
}
|
|
99015
|
-
function
|
|
99443
|
+
function searchHints2(data) {
|
|
99016
99444
|
const hints2 = [];
|
|
99017
99445
|
if ((data.following_count ?? 0) === 0) {
|
|
99018
99446
|
hints2.push(
|
|
@@ -99127,7 +99555,7 @@ function searchRejection(args8, body) {
|
|
|
99127
99555
|
}
|
|
99128
99556
|
function writeSearchResult(data, opts) {
|
|
99129
99557
|
const rawResults = Array.isArray(data?.results) ? data.results : [];
|
|
99130
|
-
const hints2 =
|
|
99558
|
+
const hints2 = searchHints2(data ?? {});
|
|
99131
99559
|
const withHints2 = hints2.length > 0 ? { hints: hints2 } : {};
|
|
99132
99560
|
if (opts.output === "json") {
|
|
99133
99561
|
const results = rawResults.map((r) => winningAdNormalizer(r, opts.full));
|
|
@@ -99149,7 +99577,7 @@ function writeSearchResult(data, opts) {
|
|
|
99149
99577
|
writeOutput({ ok: true, data: rawResults, ...withHints2 }, opts.output, opts.fields, opts.full, winningAdNormalizer);
|
|
99150
99578
|
}
|
|
99151
99579
|
var SEARCH_TIMEOUT_MS = 12e4;
|
|
99152
|
-
var
|
|
99580
|
+
var searchCommand6 = defineCommand274({
|
|
99153
99581
|
meta: {
|
|
99154
99582
|
name: "search",
|
|
99155
99583
|
description: "Search winning reference ads, the company's followed brands first. Start here: baker winning-ads search 'B2B SaaS before/after AI automation' --platform meta --format static --exclude-advertiser adv_123 --output md. A set of references for N concepts in one call: add --diverse --limit N. The best proven ad in one container from any category: --format-pattern comparison_table (no query needed; add --sort longest_running to order by staying power). Each search is a paid reranker + judge call: one strong search, at most one adjusted retry."
|
|
@@ -99275,7 +99703,7 @@ var searchCommand5 = defineCommand273({
|
|
|
99275
99703
|
});
|
|
99276
99704
|
|
|
99277
99705
|
// src/commands/winning-ads/seeds.ts
|
|
99278
|
-
import { defineCommand as
|
|
99706
|
+
import { defineCommand as defineCommand275 } from "citty";
|
|
99279
99707
|
function leanRow(r) {
|
|
99280
99708
|
return {
|
|
99281
99709
|
key: r.key,
|
|
@@ -99303,7 +99731,7 @@ function makeSeedCommand(opts) {
|
|
|
99303
99731
|
limit: { type: "number", description: "Max keys 1-100 (default 20)", required: false, default: 20 }
|
|
99304
99732
|
}
|
|
99305
99733
|
});
|
|
99306
|
-
return
|
|
99734
|
+
return defineCommand275({
|
|
99307
99735
|
meta: { name: opts.name, description: opts.description },
|
|
99308
99736
|
args: {
|
|
99309
99737
|
platform: { type: "string", description: "Single platform to segment on", required: false },
|
|
@@ -99352,7 +99780,7 @@ var formatsCommand = makeSeedCommand({
|
|
|
99352
99780
|
});
|
|
99353
99781
|
|
|
99354
99782
|
// src/commands/winning-ads/unfollow.ts
|
|
99355
|
-
import { defineCommand as
|
|
99783
|
+
import { defineCommand as defineCommand276 } from "citty";
|
|
99356
99784
|
registerSchema({
|
|
99357
99785
|
command: "winning-ads.unfollow",
|
|
99358
99786
|
description: "Stop following a brand \u2014 removes it from your ad-dna library by advertiser id.",
|
|
@@ -99360,7 +99788,7 @@ registerSchema({
|
|
|
99360
99788
|
advertiser: { type: "string", description: "Advertiser id to unfollow", required: true }
|
|
99361
99789
|
}
|
|
99362
99790
|
});
|
|
99363
|
-
var unfollowCommand =
|
|
99791
|
+
var unfollowCommand = defineCommand276({
|
|
99364
99792
|
meta: {
|
|
99365
99793
|
name: "unfollow",
|
|
99366
99794
|
description: "Stop following a brand by advertiser id. Example: baker winning-ads unfollow adv_123"
|
|
@@ -99381,7 +99809,7 @@ var unfollowCommand = defineCommand275({
|
|
|
99381
99809
|
});
|
|
99382
99810
|
|
|
99383
99811
|
// src/commands/winning-ads/winners.ts
|
|
99384
|
-
import { defineCommand as
|
|
99812
|
+
import { defineCommand as defineCommand277 } from "citty";
|
|
99385
99813
|
registerSchema({
|
|
99386
99814
|
command: "winning-ads.winners",
|
|
99387
99815
|
description: "Top winning ads for one advertiser id (from `advertisers` or `following`). Returns lean winner cards; add --full for DNA + longevity.",
|
|
@@ -99391,7 +99819,7 @@ registerSchema({
|
|
|
99391
99819
|
platform: { type: "string", description: "Filter to a single platform: meta|linkedin|tiktok", required: false }
|
|
99392
99820
|
}
|
|
99393
99821
|
});
|
|
99394
|
-
var winnersCommand =
|
|
99822
|
+
var winnersCommand = defineCommand277({
|
|
99395
99823
|
meta: {
|
|
99396
99824
|
name: "winners",
|
|
99397
99825
|
description: "Top winning ads for a specific advertiser id. Example: baker winning-ads winners adv_123 --top 15 --output md"
|
|
@@ -99441,7 +99869,7 @@ var winnersCommand = defineCommand276({
|
|
|
99441
99869
|
});
|
|
99442
99870
|
|
|
99443
99871
|
// src/commands/winning-ads/index.ts
|
|
99444
|
-
var winningAdsCommand =
|
|
99872
|
+
var winningAdsCommand = defineCommand278({
|
|
99445
99873
|
meta: {
|
|
99446
99874
|
name: "winning-ads",
|
|
99447
99875
|
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.
|
|
@@ -99477,7 +99905,7 @@ Examples:
|
|
|
99477
99905
|
Full guide: __tooling__/docs/tools/baker/winning-ads.md`
|
|
99478
99906
|
},
|
|
99479
99907
|
subCommands: {
|
|
99480
|
-
search:
|
|
99908
|
+
search: searchCommand6,
|
|
99481
99909
|
advertisers: advertisersCommand2,
|
|
99482
99910
|
follow: followCommand,
|
|
99483
99911
|
"follow-competitors": followCompetitorsCommand,
|
|
@@ -99509,7 +99937,7 @@ function getCliVersion() {
|
|
|
99509
99937
|
}
|
|
99510
99938
|
|
|
99511
99939
|
// src/cli.ts
|
|
99512
|
-
var main =
|
|
99940
|
+
var main = defineCommand279({
|
|
99513
99941
|
meta: {
|
|
99514
99942
|
name: "baker",
|
|
99515
99943
|
version: getCliVersion(),
|