@koda-sl/baker-cli 0.347.0-dev.043fc924c → 0.347.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 +4 -4
- package/dist/{chunk-KGDL7F7M.js → chunk-2IC3CGQO.js} +3 -3
- package/dist/chunk-2OKSJNLA.js +855 -0
- package/dist/chunk-2OKSJNLA.js.map +1 -0
- package/dist/{chunk-XPUSSDLR.js → chunk-4QXKWIFC.js} +3 -3
- package/dist/{chunk-JWMLQSGK.js → chunk-NA5CPMUA.js} +4 -4
- package/dist/{chunk-PWGY347J.js → chunk-XWHHYHKQ.js} +2 -2
- package/dist/{chunk-D5P4COPD.js → chunk-YBD3W4M7.js} +9 -8
- package/dist/chunk-YBD3W4M7.js.map +1 -0
- package/dist/cli.js +357 -754
- package/dist/cli.js.map +1 -1
- package/dist/{client-PWRZOA3Q.js → client-ODCNYCP4.js} +4 -4
- package/dist/engine/index.js +3 -3
- package/dist/{env-TQTHWLBN.js → env-BSG7TY5Y.js} +6 -2
- package/dist/{output-HD63GTWI.js → output-2XBCYF7L.js} +5 -5
- package/dist/{shared-5662SBDW.js → shared-RYAF7Y7H.js} +6 -6
- package/package.json +1 -1
- package/dist/chunk-4VP5WWPR.js +0 -376
- package/dist/chunk-4VP5WWPR.js.map +0 -1
- package/dist/chunk-D5P4COPD.js.map +0 -1
- /package/dist/{chunk-KGDL7F7M.js.map → chunk-2IC3CGQO.js.map} +0 -0
- /package/dist/{chunk-XPUSSDLR.js.map → chunk-4QXKWIFC.js.map} +0 -0
- /package/dist/{chunk-JWMLQSGK.js.map → chunk-NA5CPMUA.js.map} +0 -0
- /package/dist/{chunk-PWGY347J.js.map → chunk-XWHHYHKQ.js.map} +0 -0
- /package/dist/{client-PWRZOA3Q.js.map → client-ODCNYCP4.js.map} +0 -0
- /package/dist/{env-TQTHWLBN.js.map → env-BSG7TY5Y.js.map} +0 -0
- /package/dist/{output-HD63GTWI.js.map → output-2XBCYF7L.js.map} +0 -0
- /package/dist/{shared-5662SBDW.js.map → shared-RYAF7Y7H.js.map} +0 -0
package/dist/cli.js
CHANGED
|
@@ -67,7 +67,7 @@ import {
|
|
|
67
67
|
validateCanvasDeep,
|
|
68
68
|
withoutCastName,
|
|
69
69
|
ytDlpBlockSignal
|
|
70
|
-
} from "./chunk-
|
|
70
|
+
} from "./chunk-YBD3W4M7.js";
|
|
71
71
|
import {
|
|
72
72
|
csvOrJson,
|
|
73
73
|
daysAgoIso,
|
|
@@ -76,7 +76,7 @@ import {
|
|
|
76
76
|
resolveAccountIdArg,
|
|
77
77
|
resolveEffectiveStatus,
|
|
78
78
|
todayIso
|
|
79
|
-
} from "./chunk-
|
|
79
|
+
} from "./chunk-NA5CPMUA.js";
|
|
80
80
|
import {
|
|
81
81
|
buildQueryCacheKey,
|
|
82
82
|
cacheGet,
|
|
@@ -92,33 +92,42 @@ import {
|
|
|
92
92
|
writeAdsJson,
|
|
93
93
|
writeAdsOutput,
|
|
94
94
|
writeJsonEnvelope
|
|
95
|
-
} from "./chunk-
|
|
95
|
+
} from "./chunk-2IC3CGQO.js";
|
|
96
96
|
import {
|
|
97
97
|
ApiError,
|
|
98
98
|
apiGet,
|
|
99
99
|
apiGetWithHeaders,
|
|
100
100
|
apiPost,
|
|
101
101
|
validateConvexId
|
|
102
|
-
} from "./chunk-
|
|
102
|
+
} from "./chunk-4QXKWIFC.js";
|
|
103
103
|
import {
|
|
104
104
|
installExitRecord,
|
|
105
105
|
installStreamTaps,
|
|
106
106
|
logInvocation
|
|
107
|
-
} from "./chunk-
|
|
107
|
+
} from "./chunk-XWHHYHKQ.js";
|
|
108
108
|
import {
|
|
109
|
+
adContentNormalizer,
|
|
109
110
|
captureBudgetMs,
|
|
110
111
|
captureProxyCredentials,
|
|
111
112
|
captureVimeoCookie,
|
|
113
|
+
compactImage,
|
|
114
|
+
compactVideo,
|
|
112
115
|
getEnv,
|
|
113
116
|
hasOpenRouterKey,
|
|
114
117
|
isProxyFailure,
|
|
115
118
|
openRouterKey,
|
|
119
|
+
optionalChatId,
|
|
116
120
|
plannedRoutes,
|
|
117
121
|
refuseNonPublicUrl,
|
|
118
122
|
requireChatId,
|
|
119
123
|
resolveChatId,
|
|
120
|
-
shouldEscalate
|
|
121
|
-
|
|
124
|
+
shouldEscalate,
|
|
125
|
+
testimonialNormalizer,
|
|
126
|
+
videoNormalizer,
|
|
127
|
+
winningAdNormalizer,
|
|
128
|
+
writeJson,
|
|
129
|
+
writeOutput
|
|
130
|
+
} from "./chunk-2OKSJNLA.js";
|
|
122
131
|
|
|
123
132
|
// src/cli.ts
|
|
124
133
|
import { defineCommand as defineCommand245, runMain } from "citty";
|
|
@@ -159,420 +168,6 @@ import { defineCommand as defineCommand18 } from "citty";
|
|
|
159
168
|
// src/commands/actions/claim.ts
|
|
160
169
|
import { defineCommand } from "citty";
|
|
161
170
|
|
|
162
|
-
// src/output.ts
|
|
163
|
-
var ASPECT_RATIO_MAP = {
|
|
164
|
-
"1:1": 1,
|
|
165
|
-
"16:9": 16 / 9,
|
|
166
|
-
"9:16": 9 / 16,
|
|
167
|
-
"2:3": 2 / 3,
|
|
168
|
-
"3:4": 3 / 4,
|
|
169
|
-
"1:2": 1 / 2,
|
|
170
|
-
"2:1": 2,
|
|
171
|
-
"4:5": 4 / 5,
|
|
172
|
-
"3:2": 3 / 2,
|
|
173
|
-
"4:3": 4 / 3
|
|
174
|
-
};
|
|
175
|
-
var ASPECT_RATIO_TOLERANCE = 0.08;
|
|
176
|
-
function formatAspectRatio(ratio) {
|
|
177
|
-
if (ratio === void 0 || ratio === null) {
|
|
178
|
-
return null;
|
|
179
|
-
}
|
|
180
|
-
for (const [label, value] of Object.entries(ASPECT_RATIO_MAP)) {
|
|
181
|
-
if (Math.abs(ratio - value) / value < ASPECT_RATIO_TOLERANCE) {
|
|
182
|
-
return label;
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
return null;
|
|
186
|
-
}
|
|
187
|
-
function groupSummary(record) {
|
|
188
|
-
const key = record.groupKey;
|
|
189
|
-
if (typeof key !== "string" || !key) {
|
|
190
|
-
return null;
|
|
191
|
-
}
|
|
192
|
-
const index = typeof record.groupIndex === "number" ? record.groupIndex : null;
|
|
193
|
-
const size = typeof record.groupSize === "number" ? record.groupSize : null;
|
|
194
|
-
return {
|
|
195
|
-
key,
|
|
196
|
-
kind: typeof record.groupKind === "string" ? record.groupKind : null,
|
|
197
|
-
position: index === null ? null : size === null ? `${index + 1}` : `${index + 1} of ${size}`,
|
|
198
|
-
title: typeof record.groupTitle === "string" ? record.groupTitle : null,
|
|
199
|
-
url: typeof record.groupUrl === "string" ? record.groupUrl : null
|
|
200
|
-
};
|
|
201
|
-
}
|
|
202
|
-
function peopleLines(value) {
|
|
203
|
-
if (!Array.isArray(value)) {
|
|
204
|
-
return [];
|
|
205
|
-
}
|
|
206
|
-
return value.flatMap((entry) => {
|
|
207
|
-
const person = asRecord(entry);
|
|
208
|
-
const role = typeof person.role === "string" ? person.role : "";
|
|
209
|
-
if (!role) {
|
|
210
|
-
return [];
|
|
211
|
-
}
|
|
212
|
-
const identity = typeof person.identity === "string" && person.identity ? ` \u2014 ${person.identity}` : "";
|
|
213
|
-
const appearance = typeof person.appearance === "string" && person.appearance ? ` (${person.appearance})` : "";
|
|
214
|
-
const speaking = person.speaking === true ? " [speaking]" : "";
|
|
215
|
-
return [`${role}${identity}${appearance}${speaking}`];
|
|
216
|
-
});
|
|
217
|
-
}
|
|
218
|
-
function compactImage(image) {
|
|
219
|
-
const analysis = asRecord(image.analysis);
|
|
220
|
-
return {
|
|
221
|
-
_id: String(image._id ?? ""),
|
|
222
|
-
name: String(image.name ?? ""),
|
|
223
|
-
imageUrl: String(image.imageUrl ?? ""),
|
|
224
|
-
description: String(image.description ?? ""),
|
|
225
|
-
tags: Array.isArray(image.tags) ? image.tags : [],
|
|
226
|
-
// Two numbers that are not about choosing the image but about placing it.
|
|
227
|
-
// A remote <BakerImage> with no width/height makes Astro DOWNLOAD the file
|
|
228
|
-
// at build time just to measure it — one request per image per build, on a
|
|
229
|
-
// build that is otherwise offline, and a single dropped connection there
|
|
230
|
-
// fails a client's whole verify. They are cheap enough to always carry, and
|
|
231
|
-
// burying them behind --full meant the agent placing the image never had
|
|
232
|
-
// them.
|
|
233
|
-
width: typeof image.width === "number" ? image.width : null,
|
|
234
|
-
height: typeof image.height === "number" ? image.height : null,
|
|
235
|
-
// The facts that decide a pick, so choosing does not need a second call:
|
|
236
|
-
// whose brand it is, who is in it, and what text is burned in.
|
|
237
|
-
subject: typeof analysis.subject === "string" ? analysis.subject : null,
|
|
238
|
-
brandOwnership: typeof analysis.brandOwnership === "string" ? analysis.brandOwnership : null,
|
|
239
|
-
people: peopleLines(analysis.people),
|
|
240
|
-
textInImage: Array.isArray(analysis.textInImage) ? analysis.textInImage : [],
|
|
241
|
-
group: groupSummary(image)
|
|
242
|
-
};
|
|
243
|
-
}
|
|
244
|
-
function fullImage(image) {
|
|
245
|
-
const compact3 = compactImage(image);
|
|
246
|
-
return {
|
|
247
|
-
...compact3,
|
|
248
|
-
aspectRatio: formatAspectRatio(image.aspectRatio),
|
|
249
|
-
dominantColor: image.dominantColor ?? null,
|
|
250
|
-
imagePalette: Array.isArray(image.imagePalette) ? image.imagePalette : [],
|
|
251
|
-
source: String(image.source ?? ""),
|
|
252
|
-
externalUrl: image.externalUrl ?? null,
|
|
253
|
-
originalFilename: image.originalFilename ?? null,
|
|
254
|
-
descriptionContext: image.descriptionContext ?? null,
|
|
255
|
-
style: typeof asRecord(image.analysis).style === "string" ? asRecord(image.analysis).style : null,
|
|
256
|
-
composition: typeof asRecord(image.analysis).composition === "string" ? asRecord(image.analysis).composition : null,
|
|
257
|
-
usageNotes: typeof asRecord(image.analysis).usageNotes === "string" ? asRecord(image.analysis).usageNotes : null,
|
|
258
|
-
createdAt: image.createdAt ?? null
|
|
259
|
-
};
|
|
260
|
-
}
|
|
261
|
-
function imageNormalizer(record, full) {
|
|
262
|
-
if (full) {
|
|
263
|
-
return fullImage(record);
|
|
264
|
-
}
|
|
265
|
-
return compactImage(record);
|
|
266
|
-
}
|
|
267
|
-
function compactVideo(video) {
|
|
268
|
-
const analysis = asRecord(video.analysis);
|
|
269
|
-
const sceneCount = typeof video.sceneCount === "number" ? video.sceneCount : Array.isArray(video.scenes) ? video.scenes.length : 0;
|
|
270
|
-
return {
|
|
271
|
-
_id: String(video._id ?? ""),
|
|
272
|
-
name: String(video.name ?? ""),
|
|
273
|
-
thumbnailUrl: String(video.thumbnailUrl ?? ""),
|
|
274
|
-
description: String(video.description ?? ""),
|
|
275
|
-
tags: Array.isArray(video.tags) ? video.tags : [],
|
|
276
|
-
status: String(video.status ?? ""),
|
|
277
|
-
// What decides whether this clip is usable, without a second call: who is
|
|
278
|
-
// on camera and in what role, what language they speak, how it opens, and
|
|
279
|
-
// how many beats there are to cut from.
|
|
280
|
-
subject: typeof analysis.subject === "string" ? analysis.subject : null,
|
|
281
|
-
brandOwnership: typeof analysis.brandOwnership === "string" ? analysis.brandOwnership : null,
|
|
282
|
-
people: peopleLines(analysis.people),
|
|
283
|
-
spokenLanguages: Array.isArray(analysis.spokenLanguages) ? analysis.spokenLanguages : [],
|
|
284
|
-
hook: typeof analysis.hook === "string" ? analysis.hook : null,
|
|
285
|
-
sceneCount,
|
|
286
|
-
group: groupSummary(video)
|
|
287
|
-
};
|
|
288
|
-
}
|
|
289
|
-
function sceneDecoration(scene) {
|
|
290
|
-
const shot = typeof scene.shot === "string" && scene.shot ? ` [${scene.shot}]` : "";
|
|
291
|
-
const change = typeof scene.visualChange === "string" && scene.visualChange ? ` <${scene.visualChange}>` : "";
|
|
292
|
-
const overlayText = Array.isArray(scene.onScreenText) ? scene.onScreenText.filter(Boolean) : [];
|
|
293
|
-
let overlay = "";
|
|
294
|
-
if (scene.hasOverlay === true) {
|
|
295
|
-
overlay = overlayText.length > 0 ? ` \u2014 banner: "${overlayText.join('" / "')}"` : " \u2014 banner";
|
|
296
|
-
} else if (scene.hasOverlay === false) {
|
|
297
|
-
overlay = " \u2014 clean frame";
|
|
298
|
-
}
|
|
299
|
-
const spoken = typeof scene.spoken === "string" && scene.spoken ? ` \u2014 says: "${scene.spoken}"` : "";
|
|
300
|
-
return `${shot}${change}${overlay}${spoken}`;
|
|
301
|
-
}
|
|
302
|
-
function sceneLines(value) {
|
|
303
|
-
if (!Array.isArray(value)) {
|
|
304
|
-
return [];
|
|
305
|
-
}
|
|
306
|
-
return value.flatMap((s) => {
|
|
307
|
-
const scene = asRecord(s);
|
|
308
|
-
const title = typeof scene.title === "string" ? scene.title : "";
|
|
309
|
-
if (!title) {
|
|
310
|
-
return [];
|
|
311
|
-
}
|
|
312
|
-
const start = round2(scene.startSecond);
|
|
313
|
-
const end = round2(scene.endSecond);
|
|
314
|
-
const range = start !== null && end !== null ? ` (${start}-${end}s)` : "";
|
|
315
|
-
return [`${title}${range}${sceneDecoration(scene)}`];
|
|
316
|
-
});
|
|
317
|
-
}
|
|
318
|
-
function fullVideo(video) {
|
|
319
|
-
const compact3 = compactVideo(video);
|
|
320
|
-
return {
|
|
321
|
-
...compact3,
|
|
322
|
-
duration: video.duration ?? null,
|
|
323
|
-
muxPlaybackId: String(video.muxPlaybackId ?? ""),
|
|
324
|
-
source: String(video.source ?? ""),
|
|
325
|
-
// The spoken transcript + AI scene breakdown of the client's own clip — the
|
|
326
|
-
// "understand what's in this video" payload. Kept out of the compact/search
|
|
327
|
-
// projection (too large for a list) and surfaced here on --full.
|
|
328
|
-
transcript: video.transcript ?? null,
|
|
329
|
-
transcript_segment_count: Array.isArray(video.transcriptSegments) ? video.transcriptSegments.length : 0,
|
|
330
|
-
scenes: sceneLines(video.scenes),
|
|
331
|
-
originalFilename: video.originalFilename ?? null,
|
|
332
|
-
descriptionContext: video.descriptionContext ?? null,
|
|
333
|
-
shotStyle: typeof asRecord(video.analysis).shotStyle === "string" ? asRecord(video.analysis).shotStyle : null,
|
|
334
|
-
audioStyle: typeof asRecord(video.analysis).audioStyle === "string" ? asRecord(video.analysis).audioStyle : null,
|
|
335
|
-
onScreenText: Array.isArray(asRecord(video.analysis).onScreenText) ? asRecord(video.analysis).onScreenText : [],
|
|
336
|
-
usageNotes: typeof asRecord(video.analysis).usageNotes === "string" ? asRecord(video.analysis).usageNotes : null,
|
|
337
|
-
createdAt: video.createdAt ?? null
|
|
338
|
-
};
|
|
339
|
-
}
|
|
340
|
-
function videoNormalizer(record, full) {
|
|
341
|
-
if (full) {
|
|
342
|
-
return fullVideo(record);
|
|
343
|
-
}
|
|
344
|
-
return compactVideo(record);
|
|
345
|
-
}
|
|
346
|
-
function truncate(text2, maxLength) {
|
|
347
|
-
if (text2.length <= maxLength) return text2;
|
|
348
|
-
return `${text2.slice(0, maxLength)}...`;
|
|
349
|
-
}
|
|
350
|
-
function compactTestimonial(record) {
|
|
351
|
-
return {
|
|
352
|
-
_id: String(record._id ?? ""),
|
|
353
|
-
reviewerName: String(record.reviewerName ?? ""),
|
|
354
|
-
reviewText: truncate(String(record.reviewText ?? ""), 200),
|
|
355
|
-
rating: record.rating ?? null,
|
|
356
|
-
sentiment: record.sentiment ?? null,
|
|
357
|
-
tags: Array.isArray(record.tags) ? record.tags : [],
|
|
358
|
-
sourceType: String(record.sourceType ?? "")
|
|
359
|
-
};
|
|
360
|
-
}
|
|
361
|
-
function fullTestimonial(record) {
|
|
362
|
-
const compact3 = compactTestimonial(record);
|
|
363
|
-
return {
|
|
364
|
-
...compact3,
|
|
365
|
-
reviewText: String(record.reviewText ?? ""),
|
|
366
|
-
highlight: record.highlight ?? null,
|
|
367
|
-
summary: record.summary ?? null,
|
|
368
|
-
language: record.language ?? null,
|
|
369
|
-
reviewerImageUrl: record.reviewerImageUrl ?? null,
|
|
370
|
-
sourceUrl: record.sourceUrl ?? null,
|
|
371
|
-
reviewDate: record.reviewDate ?? null,
|
|
372
|
-
createdAt: record.createdAt ?? null,
|
|
373
|
-
status: String(record.status ?? "")
|
|
374
|
-
};
|
|
375
|
-
}
|
|
376
|
-
function testimonialNormalizer(record, full) {
|
|
377
|
-
if (full) {
|
|
378
|
-
return fullTestimonial(record);
|
|
379
|
-
}
|
|
380
|
-
return compactTestimonial(record);
|
|
381
|
-
}
|
|
382
|
-
function round2(value) {
|
|
383
|
-
if (typeof value !== "number" || Number.isNaN(value)) {
|
|
384
|
-
return null;
|
|
385
|
-
}
|
|
386
|
-
return Math.round(value * 100) / 100;
|
|
387
|
-
}
|
|
388
|
-
function asRecord(value) {
|
|
389
|
-
return value && typeof value === "object" ? value : {};
|
|
390
|
-
}
|
|
391
|
-
function compactWinningAd(record) {
|
|
392
|
-
const dna = asRecord(record.dna);
|
|
393
|
-
return {
|
|
394
|
-
advertiser: String(record.advertiser ?? ""),
|
|
395
|
-
platform: String(record.platform ?? ""),
|
|
396
|
-
format: String(record.format ?? ""),
|
|
397
|
-
relevance: round2(record.relevance),
|
|
398
|
-
winner_score: round2(record.winner_score),
|
|
399
|
-
summary: String(dna.creative_concept ?? ""),
|
|
400
|
-
advertiser_id: String(record.advertiser_id ?? ""),
|
|
401
|
-
ad_id: String(record.ad_id ?? ""),
|
|
402
|
-
media_url: String(record.media_url ?? "")
|
|
403
|
-
};
|
|
404
|
-
}
|
|
405
|
-
function fullWinningAd(record) {
|
|
406
|
-
const compact3 = compactWinningAd(record);
|
|
407
|
-
const dna = asRecord(record.dna);
|
|
408
|
-
return {
|
|
409
|
-
...compact3,
|
|
410
|
-
winner_category: String(record.winner_category ?? ""),
|
|
411
|
-
media_kind: record.media_kind ?? null,
|
|
412
|
-
days_active: record.days_active ?? null,
|
|
413
|
-
reach: record.reach ?? null,
|
|
414
|
-
active: typeof record.active === "boolean" ? record.active : null,
|
|
415
|
-
angle: dna.angle ?? null,
|
|
416
|
-
awareness_stage: dna.awareness_stage ?? null,
|
|
417
|
-
target_persona: dna.target_persona ?? null,
|
|
418
|
-
hook_archetype: dna.hook_archetype ?? null,
|
|
419
|
-
industry: dna.industry ?? null
|
|
420
|
-
};
|
|
421
|
-
}
|
|
422
|
-
function winningAdNormalizer(record, full) {
|
|
423
|
-
if (full) {
|
|
424
|
-
return fullWinningAd(record);
|
|
425
|
-
}
|
|
426
|
-
return compactWinningAd(record);
|
|
427
|
-
}
|
|
428
|
-
function overlayLines(value, detailed = false) {
|
|
429
|
-
if (!Array.isArray(value)) {
|
|
430
|
-
return [];
|
|
431
|
-
}
|
|
432
|
-
return value.flatMap((o) => {
|
|
433
|
-
const item = asRecord(o);
|
|
434
|
-
const text2 = typeof item.text === "string" ? item.text : "";
|
|
435
|
-
if (!text2) {
|
|
436
|
-
return [];
|
|
437
|
-
}
|
|
438
|
-
const at = round2(item.appears_at_s);
|
|
439
|
-
let line = at !== null ? `${text2} @${at}s` : text2;
|
|
440
|
-
if (detailed) {
|
|
441
|
-
const tags = [item.role, item.position].filter((t) => typeof t === "string" && t.length > 0);
|
|
442
|
-
if (tags.length) {
|
|
443
|
-
line += ` [${tags.join(", ")}]`;
|
|
444
|
-
}
|
|
445
|
-
}
|
|
446
|
-
return [line];
|
|
447
|
-
});
|
|
448
|
-
}
|
|
449
|
-
function compactAdContent(record) {
|
|
450
|
-
return {
|
|
451
|
-
ad_id: record.ad_id ?? null,
|
|
452
|
-
advertiser: record.advertiser ?? null,
|
|
453
|
-
format: record.format ?? null,
|
|
454
|
-
media_kind: record.media_kind ?? null,
|
|
455
|
-
media_url: record.media_url ?? null,
|
|
456
|
-
summary: record.summary ?? null,
|
|
457
|
-
transcript: record.transcript ?? null,
|
|
458
|
-
on_screen_text: overlayLines(record.on_screen_text),
|
|
459
|
-
has_captions: typeof record.has_captions === "boolean" ? record.has_captions : null,
|
|
460
|
-
primary_text: record.primary_text ?? null,
|
|
461
|
-
headline: record.headline ?? null,
|
|
462
|
-
cta: record.cta ?? null
|
|
463
|
-
};
|
|
464
|
-
}
|
|
465
|
-
function fullAdContent(record) {
|
|
466
|
-
const speech = asRecord(record.speech);
|
|
467
|
-
const pacing = asRecord(record.pacing);
|
|
468
|
-
const music = asRecord(record.music);
|
|
469
|
-
return {
|
|
470
|
-
...compactAdContent(record),
|
|
471
|
-
platform: record.platform ?? null,
|
|
472
|
-
// Re-derive with role/position tags — the lean compact version dropped them.
|
|
473
|
-
on_screen_text: overlayLines(record.on_screen_text, true),
|
|
474
|
-
winner_score: round2(record.winner_score),
|
|
475
|
-
winner_category: record.winner_category ?? null,
|
|
476
|
-
angle: record.angle ?? null,
|
|
477
|
-
hook_archetype: record.hook_archetype ?? null,
|
|
478
|
-
caption_style: record.caption_style ?? null,
|
|
479
|
-
has_speech: typeof record.has_speech === "boolean" ? record.has_speech : null,
|
|
480
|
-
speech_pct_of_runtime: round2(speech.speech_pct_of_runtime),
|
|
481
|
-
speaker_count: speech.speaker_count ?? null,
|
|
482
|
-
voiceover_vs_sync: speech.voiceover_vs_sync ?? null,
|
|
483
|
-
is_direct_address: typeof speech.is_direct_address === "boolean" ? speech.is_direct_address : null,
|
|
484
|
-
speech_emotion_dominant: speech.speech_emotion_dominant ?? null,
|
|
485
|
-
scene_count: pacing.scene_count ?? null,
|
|
486
|
-
avg_shot_length_s: round2(pacing.avg_shot_length_s),
|
|
487
|
-
pacing_shape: pacing.pacing_shape ?? null,
|
|
488
|
-
hook_ends_at_s: round2(pacing.hook_ends_at_s),
|
|
489
|
-
cta_first_shown_at_s: round2(pacing.cta_first_shown_at_s),
|
|
490
|
-
product_first_appears_at_s: round2(pacing.product_first_appears_at_s),
|
|
491
|
-
music_track_title: music.track_title ?? null,
|
|
492
|
-
music_track_artist: music.track_artist ?? null
|
|
493
|
-
};
|
|
494
|
-
}
|
|
495
|
-
function adContentNormalizer(record, full) {
|
|
496
|
-
return full ? fullAdContent(record) : compactAdContent(record);
|
|
497
|
-
}
|
|
498
|
-
function applyFieldMask(data, fields) {
|
|
499
|
-
const result = {};
|
|
500
|
-
for (const field of fields) {
|
|
501
|
-
if (field in data) {
|
|
502
|
-
result[field] = data[field];
|
|
503
|
-
}
|
|
504
|
-
}
|
|
505
|
-
return result;
|
|
506
|
-
}
|
|
507
|
-
function write(text2) {
|
|
508
|
-
process.stdout.write(text2);
|
|
509
|
-
}
|
|
510
|
-
function writeJson(envelope) {
|
|
511
|
-
write(`${JSON.stringify(envelope, null, 2)}
|
|
512
|
-
`);
|
|
513
|
-
}
|
|
514
|
-
function writeFiles(data, fields) {
|
|
515
|
-
write(`${fields.join(" ")}
|
|
516
|
-
`);
|
|
517
|
-
for (const item of data) {
|
|
518
|
-
const values = fields.map((f) => String(item[f] ?? ""));
|
|
519
|
-
write(`${values.join(" ")}
|
|
520
|
-
`);
|
|
521
|
-
}
|
|
522
|
-
}
|
|
523
|
-
function writeMd(data, fields) {
|
|
524
|
-
write(`| ${fields.join(" | ")} |
|
|
525
|
-
`);
|
|
526
|
-
write(`| ${fields.map(() => "---").join(" | ")} |
|
|
527
|
-
`);
|
|
528
|
-
for (const item of data) {
|
|
529
|
-
const values = fields.map((f) => String(item[f] ?? ""));
|
|
530
|
-
write(`| ${values.join(" | ")} |
|
|
531
|
-
`);
|
|
532
|
-
}
|
|
533
|
-
}
|
|
534
|
-
function normalizeData(envelope, fields, full, normalizer) {
|
|
535
|
-
const raw = Array.isArray(envelope.data) ? envelope.data : [envelope.data];
|
|
536
|
-
const items = raw.map((item) => {
|
|
537
|
-
const record = item;
|
|
538
|
-
return normalizer(record, full);
|
|
539
|
-
});
|
|
540
|
-
if (fields) {
|
|
541
|
-
return items.map((item) => applyFieldMask(item, fields));
|
|
542
|
-
}
|
|
543
|
-
return items;
|
|
544
|
-
}
|
|
545
|
-
function writeOutput(envelope, format, fields, full, normalizer) {
|
|
546
|
-
if (!envelope.ok || "dryRun" in envelope) {
|
|
547
|
-
writeJson(envelope);
|
|
548
|
-
return;
|
|
549
|
-
}
|
|
550
|
-
if (format === "json") {
|
|
551
|
-
writeJson(envelope);
|
|
552
|
-
return;
|
|
553
|
-
}
|
|
554
|
-
if (format !== "files" && format !== "md") {
|
|
555
|
-
process.stderr.write(`Unknown --output "${String(format)}". Valid formats: json, files, md. Using json.
|
|
556
|
-
`);
|
|
557
|
-
writeJson(envelope);
|
|
558
|
-
return;
|
|
559
|
-
}
|
|
560
|
-
const items = normalizeData(envelope, fields, full ?? false, normalizer ?? imageNormalizer);
|
|
561
|
-
const displayFields = fields ?? Object.keys(items[0] ?? {});
|
|
562
|
-
if (format === "files") {
|
|
563
|
-
writeFiles(items, displayFields);
|
|
564
|
-
} else {
|
|
565
|
-
writeMd(items, displayFields);
|
|
566
|
-
}
|
|
567
|
-
writeHints(envelope.hints);
|
|
568
|
-
}
|
|
569
|
-
function writeHints(hints2) {
|
|
570
|
-
for (const hint of hints2 ?? []) {
|
|
571
|
-
process.stderr.write(`${hint}
|
|
572
|
-
`);
|
|
573
|
-
}
|
|
574
|
-
}
|
|
575
|
-
|
|
576
171
|
// src/schemas.ts
|
|
577
172
|
var registry = /* @__PURE__ */ new Map();
|
|
578
173
|
function registerSchema(schema) {
|
|
@@ -789,50 +384,6 @@ var actionsUpdateRequestSchema = z.object({
|
|
|
789
384
|
var actionsUpdateResponseSchema = okOnlySchema();
|
|
790
385
|
var ACTION_COMPLETE_NOTE_MIN = 20;
|
|
791
386
|
var actionsCompleteNoteMessage = `A completion note (\u2265${ACTION_COMPLETE_NOTE_MIN} chars) describing what was done is required: what changed, where, and the outcome.`;
|
|
792
|
-
var ACCOUNT_CONTEXT = "(?:account|accounts|cuenta|cuentas|customer|cliente|property|propiedad|meta|facebook|google|ads|linkedin|ga4|analytics|gtm|tag manager|id)";
|
|
793
|
-
var COMPLETION_NOTE_INTERNALS = [
|
|
794
|
-
// Repo paths: rooted in a workspace directory, or a path or lowercase file name
|
|
795
|
-
// ending in a source extension (a product name like "Next.js" is not a file).
|
|
796
|
-
/(?:\.{0,2}\/)?(?:src|public|__tooling__|\.claude)\/[^\s,;:)`'"]*[^\s,;:)`'".]/g,
|
|
797
|
-
/(?:[\w.-]*\/[\w./-]*|\b[a-z_][\w-]*)\.(?:mdx?|astro|tsx?|jsx?|mjs|json|ya?ml)\b/g,
|
|
798
|
-
// Meta ad-account ids, Tag Manager containers and GA4 measurement ids.
|
|
799
|
-
/\bact_\d+\b/g,
|
|
800
|
-
/\bGTM-[A-Z0-9]{4,}\b/g,
|
|
801
|
-
/\bG-[A-Z0-9]{6,}\b/g,
|
|
802
|
-
// Google Ads customer ids (386-508-3115), LinkedIn, GA4 and bare Google Ads ids:
|
|
803
|
-
// a long number named next to a platform or an account, so a phone number or
|
|
804
|
-
// a figure elsewhere in the note is not one.
|
|
805
|
-
new RegExp(
|
|
806
|
-
String.raw`(?<=\b${ACCOUNT_CONTEXT}\b[^.\n\d]{0,20})(?<![\w-])(?:\d{3}-\d{3}-\d{4}|\d{7,})(?![\w-])`,
|
|
807
|
-
"gi"
|
|
808
|
-
),
|
|
809
|
-
// Error codes: SCREAMING_SNAKE in the shapes platforms and Baker return them
|
|
810
|
-
// (NO_GOOGLE_ADS_CONNECTION, PERMISSION_DENIED, INVALID_ACCOUNT_ID).
|
|
811
|
-
/\b(?:(?:ERR|INVALID|MISSING)(?:_[A-Z0-9]+)+|[A-Z][A-Z0-9]*(?:_[A-Z0-9]+)*_(?:ERROR|CONNECTION|FAILED|NOT_FOUND|DENIED|REQUIRED|INVALID|EXPIRED|UNAVAILABLE|EXCEEDED|UNREACHABLE|UNAUTHORIZED|FORBIDDEN|TIMEOUT|TOKEN)|BAD_REQUEST|NOT_FOUND|RATE_LIMITED)\b/g,
|
|
812
|
-
// CLI invocations (`baker analytics flow`).
|
|
813
|
-
/\bbaker [a-z][a-z-]*/g
|
|
814
|
-
];
|
|
815
|
-
function completionNoteInternals(note) {
|
|
816
|
-
const hits = [];
|
|
817
|
-
for (const pattern of COMPLETION_NOTE_INTERNALS) {
|
|
818
|
-
for (const match of note.matchAll(pattern)) {
|
|
819
|
-
const index = match.index ?? 0;
|
|
820
|
-
hits.push({ index, end: index + match[0].length, text: match[0] });
|
|
821
|
-
}
|
|
822
|
-
}
|
|
823
|
-
hits.sort((a, b) => a.index - b.index || b.end - a.end);
|
|
824
|
-
const found = [];
|
|
825
|
-
let coveredUntil = -1;
|
|
826
|
-
for (const hit of hits) {
|
|
827
|
-
if (hit.index < coveredUntil) continue;
|
|
828
|
-
found.push(hit.text);
|
|
829
|
-
coveredUntil = hit.end;
|
|
830
|
-
}
|
|
831
|
-
return found;
|
|
832
|
-
}
|
|
833
|
-
function completionNoteInternalsMessage(internals) {
|
|
834
|
-
return `The completion note is read by the client on the Task, and it carries internal details they cannot use: ${internals.join(", ")}. Rewrite it in product terms \u2014 name the page, campaign or Knowledge entry instead of a file, the platform instead of an account id, and say what is missing instead of an error code.`;
|
|
835
|
-
}
|
|
836
387
|
var actionsCompleteRequestSchema = z.object({
|
|
837
388
|
chatId: z.string(),
|
|
838
389
|
actionRef: z.string().min(1, "actionRef is required"),
|
|
@@ -840,11 +391,6 @@ var actionsCompleteRequestSchema = z.object({
|
|
|
840
391
|
}).transform((body) => ({ ...body, note: (body.note ?? "").trim() })).refine((body) => body.note.length >= ACTION_COMPLETE_NOTE_MIN, {
|
|
841
392
|
message: actionsCompleteNoteMessage,
|
|
842
393
|
path: ["note"]
|
|
843
|
-
}).superRefine((body, ctx) => {
|
|
844
|
-
const internals = completionNoteInternals(body.note);
|
|
845
|
-
if (internals.length > 0) {
|
|
846
|
-
ctx.addIssue({ code: "custom", message: completionNoteInternalsMessage(internals), path: ["note"] });
|
|
847
|
-
}
|
|
848
394
|
});
|
|
849
395
|
var actionsCompleteResponseSchema = okOnlySchema();
|
|
850
396
|
var actionsDiscardRequestSchema = z.object({
|
|
@@ -8509,12 +8055,12 @@ var claimCommand = defineCommand({
|
|
|
8509
8055
|
import { defineCommand as defineCommand2 } from "citty";
|
|
8510
8056
|
registerSchema({
|
|
8511
8057
|
command: "actions.complete",
|
|
8512
|
-
description:
|
|
8058
|
+
description: "Stage completion of an action (it was DONE). Accepts a real action ID (must be claimed) or a temp ID from the same draft. The action becomes completed when the chat is published. --note is REQUIRED and must describe what you actually did to resolve it (what changed, where, and the outcome) \u2014 it is the client-facing record surfaced by `baker actions log`. Do NOT use this to drop an action you no longer want \u2014 to remove a staged op use `actions draft remove`, to close an unwanted published action use `actions discard`.",
|
|
8513
8059
|
args: {
|
|
8514
8060
|
id: { type: "string", description: "Action ID or temp ID", required: true },
|
|
8515
8061
|
note: {
|
|
8516
8062
|
type: "string",
|
|
8517
|
-
description: "REQUIRED.
|
|
8063
|
+
description: "REQUIRED. Detailed description of what you did to resolve this: what changed, where, and the outcome. This is the durable, client-facing record shown by `baker actions log`.",
|
|
8518
8064
|
required: true
|
|
8519
8065
|
}
|
|
8520
8066
|
}
|
|
@@ -8529,7 +8075,7 @@ var completeCommand = defineCommand2({
|
|
|
8529
8075
|
"action-id": { type: "string", description: "Action ID or temp ID", required: false },
|
|
8530
8076
|
note: {
|
|
8531
8077
|
type: "string",
|
|
8532
|
-
description: "REQUIRED. What you did
|
|
8078
|
+
description: "REQUIRED. What you did to resolve this: what changed, where, and the outcome.",
|
|
8533
8079
|
required: false
|
|
8534
8080
|
}
|
|
8535
8081
|
},
|
|
@@ -8548,10 +8094,6 @@ var completeCommand = defineCommand2({
|
|
|
8548
8094
|
`--note is required and must describe what you did (\u2265${ACTION_COMPLETE_NOTE_MIN} chars): what changed, where, and the outcome. This becomes the client-facing record surfaced by \`baker actions log\`.`
|
|
8549
8095
|
);
|
|
8550
8096
|
}
|
|
8551
|
-
const internals = completionNoteInternals(note);
|
|
8552
|
-
if (internals.length > 0) {
|
|
8553
|
-
failValidation(`--note: ${completionNoteInternalsMessage(internals)} Then run the same command again.`);
|
|
8554
|
-
}
|
|
8555
8097
|
const chatId = requireChatId();
|
|
8556
8098
|
await apiPost("/api/actions/complete", { chatId, actionRef: id, note });
|
|
8557
8099
|
writeOk();
|
|
@@ -13135,8 +12677,8 @@ var writeMdRows = (rows, fields, notices) => {
|
|
|
13135
12677
|
};
|
|
13136
12678
|
var ROW_WRITERS = { csv: writeCsvRows, jsonl: writeJsonlRows, md: writeMdRows };
|
|
13137
12679
|
function writeRows(format, rows, columns, notices) {
|
|
13138
|
-
const
|
|
13139
|
-
|
|
12680
|
+
const write = ROW_WRITERS[format] ?? writeMdRows;
|
|
12681
|
+
write(rows, columns, notices);
|
|
13140
12682
|
if (rows.length > REPEAT_NOTICE_ABOVE_ROWS) {
|
|
13141
12683
|
for (const line of notices) writeLine(line);
|
|
13142
12684
|
}
|
|
@@ -22339,7 +21881,7 @@ Subcommands:
|
|
|
22339
21881
|
|
|
22340
21882
|
// src/commands/ads/linkedin/creatives.ts
|
|
22341
21883
|
import { defineCommand as defineCommand44 } from "citty";
|
|
22342
|
-
function
|
|
21884
|
+
function asRecord(value) {
|
|
22343
21885
|
return typeof value === "object" && value !== null && !Array.isArray(value) ? value : void 0;
|
|
22344
21886
|
}
|
|
22345
21887
|
function asString(value) {
|
|
@@ -22349,12 +21891,12 @@ function creativeDestination(content) {
|
|
|
22349
21891
|
if (!content) return { format: "unknown" };
|
|
22350
21892
|
const reference = asString(content.reference);
|
|
22351
21893
|
if (reference) return { format: "post", postUrn: reference };
|
|
22352
|
-
const textAd =
|
|
21894
|
+
const textAd = asRecord(content.textAd);
|
|
22353
21895
|
if (textAd) return { format: "text", landingUrl: asString(textAd.landingPage) };
|
|
22354
|
-
const spotlight =
|
|
21896
|
+
const spotlight = asRecord(content.spotlight);
|
|
22355
21897
|
if (spotlight) return { format: "spotlight", landingUrl: asString(spotlight.landingPage) };
|
|
22356
|
-
if (
|
|
22357
|
-
if (
|
|
21898
|
+
if (asRecord(content.follower)) return { format: "follower" };
|
|
21899
|
+
if (asRecord(content.jobs)) return { format: "jobs" };
|
|
22358
21900
|
return { format: "unknown" };
|
|
22359
21901
|
}
|
|
22360
21902
|
var COMPACT_COLUMNS = [
|
|
@@ -22385,7 +21927,7 @@ function compactRow(row) {
|
|
|
22385
21927
|
function readPath(row, path48) {
|
|
22386
21928
|
let current = row;
|
|
22387
21929
|
for (const segment of path48.split(".")) {
|
|
22388
|
-
const record =
|
|
21930
|
+
const record = asRecord(current);
|
|
22389
21931
|
if (!record) return void 0;
|
|
22390
21932
|
current = record[segment];
|
|
22391
21933
|
}
|
|
@@ -25758,10 +25300,10 @@ Example: baker ads meta ads retag 120252158038400247 --url-tags "utm_source={{si
|
|
|
25758
25300
|
}
|
|
25759
25301
|
},
|
|
25760
25302
|
run: async ({ args: args5 }) => {
|
|
25761
|
-
const { apiPost: apiPost2 } = await import("./client-
|
|
25762
|
-
const { requireChatId: requireChatId2 } = await import("./env-
|
|
25763
|
-
const { writeJsonEnvelope: writeJsonEnvelope2 } = await import("./output-
|
|
25764
|
-
const { handleMetaError: handleMetaError2 } = await import("./shared-
|
|
25303
|
+
const { apiPost: apiPost2 } = await import("./client-ODCNYCP4.js");
|
|
25304
|
+
const { requireChatId: requireChatId2 } = await import("./env-BSG7TY5Y.js");
|
|
25305
|
+
const { writeJsonEnvelope: writeJsonEnvelope2 } = await import("./output-2XBCYF7L.js");
|
|
25306
|
+
const { handleMetaError: handleMetaError2 } = await import("./shared-RYAF7Y7H.js");
|
|
25765
25307
|
try {
|
|
25766
25308
|
const accountId = bareAccountId2(args5);
|
|
25767
25309
|
const urlTags = typeof args5["url-tags"] === "string" ? args5["url-tags"] : void 0;
|
|
@@ -25906,10 +25448,10 @@ function duplicateCommand2(entity, label) {
|
|
|
25906
25448
|
replace: { type: "boolean", description: "Pause the original once the copy publishes" }
|
|
25907
25449
|
},
|
|
25908
25450
|
run: async ({ args: args5 }) => {
|
|
25909
|
-
const { apiPost: apiPost2 } = await import("./client-
|
|
25910
|
-
const { requireChatId: requireChatId2 } = await import("./env-
|
|
25911
|
-
const { writeJsonEnvelope: writeJsonEnvelope2 } = await import("./output-
|
|
25912
|
-
const { handleMetaError: handleMetaError2 } = await import("./shared-
|
|
25451
|
+
const { apiPost: apiPost2 } = await import("./client-ODCNYCP4.js");
|
|
25452
|
+
const { requireChatId: requireChatId2 } = await import("./env-BSG7TY5Y.js");
|
|
25453
|
+
const { writeJsonEnvelope: writeJsonEnvelope2 } = await import("./output-2XBCYF7L.js");
|
|
25454
|
+
const { handleMetaError: handleMetaError2 } = await import("./shared-RYAF7Y7H.js");
|
|
25913
25455
|
try {
|
|
25914
25456
|
const accountId = bareAccountId2(args5);
|
|
25915
25457
|
const chatId = requireChatId2();
|
|
@@ -31085,6 +30627,286 @@ function mergeStoredWithCounts(stored, reported) {
|
|
|
31085
30627
|
}).sort((a, b) => a.name.localeCompare(b.name));
|
|
31086
30628
|
}
|
|
31087
30629
|
|
|
30630
|
+
// src/commands/analytics/render.ts
|
|
30631
|
+
var SPARKLINE_POINTS = 30;
|
|
30632
|
+
var DASHBOARD_ONLY_FIELDS = /* @__PURE__ */ new Set([
|
|
30633
|
+
// The Convex row id. It exists so a dashboard can link to the row; an agent
|
|
30634
|
+
// addresses a landing by `landingId`, which is the id in its `_definition.md`.
|
|
30635
|
+
"landingRef"
|
|
30636
|
+
]);
|
|
30637
|
+
function isAbsent(value) {
|
|
30638
|
+
if (value === "") return true;
|
|
30639
|
+
if (Array.isArray(value)) return value.length === 0;
|
|
30640
|
+
if (typeof value === "object" && value !== null) return Object.keys(value).length === 0;
|
|
30641
|
+
return false;
|
|
30642
|
+
}
|
|
30643
|
+
function resample(series, points) {
|
|
30644
|
+
if (series.length <= points || points < 1) return [...series];
|
|
30645
|
+
const out = [];
|
|
30646
|
+
for (let i = 0; i < points; i += 1) {
|
|
30647
|
+
const from = Math.floor(i * series.length / points);
|
|
30648
|
+
const to = Math.floor((i + 1) * series.length / points);
|
|
30649
|
+
let sum = 0;
|
|
30650
|
+
for (let j = from; j < to; j += 1) sum += series[j] ?? 0;
|
|
30651
|
+
out.push(sum);
|
|
30652
|
+
}
|
|
30653
|
+
return out;
|
|
30654
|
+
}
|
|
30655
|
+
function pruneValue(value, full) {
|
|
30656
|
+
if (Array.isArray(value)) return value.map((entry) => pruneValue(entry, full));
|
|
30657
|
+
if (typeof value === "object" && value !== null) {
|
|
30658
|
+
return pruneRow(value, full);
|
|
30659
|
+
}
|
|
30660
|
+
return value;
|
|
30661
|
+
}
|
|
30662
|
+
function pruneRow(row, full) {
|
|
30663
|
+
const out = {};
|
|
30664
|
+
for (const [key, value] of Object.entries(row)) {
|
|
30665
|
+
if (DASHBOARD_ONLY_FIELDS.has(key)) continue;
|
|
30666
|
+
if (key === "sparkline" && Array.isArray(value)) {
|
|
30667
|
+
if (!full) continue;
|
|
30668
|
+
out[key] = resample(value, SPARKLINE_POINTS);
|
|
30669
|
+
continue;
|
|
30670
|
+
}
|
|
30671
|
+
if (isAbsent(value)) continue;
|
|
30672
|
+
out[key] = pruneValue(value, full);
|
|
30673
|
+
}
|
|
30674
|
+
return out;
|
|
30675
|
+
}
|
|
30676
|
+
function pruneForAgent(data, full) {
|
|
30677
|
+
return pruneRow(data, full);
|
|
30678
|
+
}
|
|
30679
|
+
function isTabular(rows) {
|
|
30680
|
+
return rows.every(
|
|
30681
|
+
(row) => typeof row === "object" && row !== null && !Array.isArray(row) && Object.values(row).every(
|
|
30682
|
+
(value) => value === null || typeof value !== "object" || Array.isArray(value) && value.every((e) => typeof e !== "object")
|
|
30683
|
+
)
|
|
30684
|
+
);
|
|
30685
|
+
}
|
|
30686
|
+
function cell2(value, key) {
|
|
30687
|
+
if (value === null || value === void 0) return "";
|
|
30688
|
+
if (Array.isArray(value)) return value.join(" ");
|
|
30689
|
+
if (typeof value === "number" && !Number.isInteger(value)) {
|
|
30690
|
+
if (key?.endsWith("Ms")) return String(Math.round(value));
|
|
30691
|
+
return value.toFixed(4).replace(/0+$/, "").replace(/\.$/, "");
|
|
30692
|
+
}
|
|
30693
|
+
return String(value);
|
|
30694
|
+
}
|
|
30695
|
+
var IDENTITY_COLUMNS = [
|
|
30696
|
+
"landingId",
|
|
30697
|
+
"name",
|
|
30698
|
+
"slug",
|
|
30699
|
+
"path",
|
|
30700
|
+
"flowSlug",
|
|
30701
|
+
"stepId",
|
|
30702
|
+
"value",
|
|
30703
|
+
"key",
|
|
30704
|
+
"bucket",
|
|
30705
|
+
"tag",
|
|
30706
|
+
"eventName",
|
|
30707
|
+
"release",
|
|
30708
|
+
"place",
|
|
30709
|
+
"bot",
|
|
30710
|
+
"source",
|
|
30711
|
+
"medium",
|
|
30712
|
+
"campaign",
|
|
30713
|
+
"platform",
|
|
30714
|
+
"sessionId",
|
|
30715
|
+
"eventId"
|
|
30716
|
+
];
|
|
30717
|
+
function byIdentityFirst(a, b) {
|
|
30718
|
+
const ia = IDENTITY_COLUMNS.indexOf(a);
|
|
30719
|
+
const ib = IDENTITY_COLUMNS.indexOf(b);
|
|
30720
|
+
if (ia !== -1 || ib !== -1)
|
|
30721
|
+
return (ia === -1 ? Number.MAX_SAFE_INTEGER : ia) - (ib === -1 ? Number.MAX_SAFE_INTEGER : ib);
|
|
30722
|
+
return 0;
|
|
30723
|
+
}
|
|
30724
|
+
var BLOCK_ORDER = ["window", "totals", "previous", "pageInfo"];
|
|
30725
|
+
function byBlockOrder(a, b) {
|
|
30726
|
+
const rank = (key) => {
|
|
30727
|
+
const at = BLOCK_ORDER.indexOf(key);
|
|
30728
|
+
if (at !== -1) return at;
|
|
30729
|
+
return key === "preset" ? BLOCK_ORDER.length + 1 : BLOCK_ORDER.length;
|
|
30730
|
+
};
|
|
30731
|
+
return rank(a) - rank(b);
|
|
30732
|
+
}
|
|
30733
|
+
function columnsOf(rows) {
|
|
30734
|
+
const seen = [];
|
|
30735
|
+
for (const row of rows) {
|
|
30736
|
+
for (const key of Object.keys(row)) {
|
|
30737
|
+
if (!seen.includes(key)) seen.push(key);
|
|
30738
|
+
}
|
|
30739
|
+
}
|
|
30740
|
+
return seen.filter((key) => rows.some((row) => !isAbsent(row[key]) && row[key] !== null && row[key] !== void 0)).sort(byIdentityFirst);
|
|
30741
|
+
}
|
|
30742
|
+
function table2(rows) {
|
|
30743
|
+
const cols = columnsOf(rows);
|
|
30744
|
+
if (cols.length === 0) return "";
|
|
30745
|
+
const head = `| ${cols.join(" | ")} |`;
|
|
30746
|
+
const rule = `| ${cols.map(() => "---").join(" | ")} |`;
|
|
30747
|
+
const body = rows.map((row) => `| ${cols.map((col) => cell2(row[col], col)).join(" | ")} |`);
|
|
30748
|
+
return [head, rule, ...body].join("\n");
|
|
30749
|
+
}
|
|
30750
|
+
function isRowList(value) {
|
|
30751
|
+
return Array.isArray(value) && value.length > 0 && value.every((entry) => typeof entry === "object" && entry !== null && !Array.isArray(entry));
|
|
30752
|
+
}
|
|
30753
|
+
function labelOf(row, index) {
|
|
30754
|
+
for (const key of IDENTITY_COLUMNS) {
|
|
30755
|
+
const value = row[key];
|
|
30756
|
+
if (typeof value === "string" && value !== "") return value;
|
|
30757
|
+
}
|
|
30758
|
+
return `#${index + 1}`;
|
|
30759
|
+
}
|
|
30760
|
+
function nestedBlock(name, rows) {
|
|
30761
|
+
const parents = rows.map(
|
|
30762
|
+
(row) => Object.fromEntries(Object.entries(row).filter(([, value]) => !isRowList(value) && !isPlainRow(value)))
|
|
30763
|
+
);
|
|
30764
|
+
const parts = [`### ${name}`, table2(parents)];
|
|
30765
|
+
rows.forEach((row, index) => {
|
|
30766
|
+
for (const [key, value] of Object.entries(row)) {
|
|
30767
|
+
if (isRowList(value)) parts.push(`#### ${name}[${labelOf(row, index)}].${key}`, table2(value));
|
|
30768
|
+
else if (isPlainRow(value)) parts.push(`#### ${name}[${labelOf(row, index)}].${key}`, table2([value]));
|
|
30769
|
+
}
|
|
30770
|
+
});
|
|
30771
|
+
return parts.filter((part) => part !== "").join("\n");
|
|
30772
|
+
}
|
|
30773
|
+
function isPlainRow(value) {
|
|
30774
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
30775
|
+
}
|
|
30776
|
+
function block(name, value) {
|
|
30777
|
+
if (Array.isArray(value)) {
|
|
30778
|
+
if (value.length === 0) return "";
|
|
30779
|
+
if (isTabular(value)) return `### ${name}
|
|
30780
|
+
${table2(value)}`;
|
|
30781
|
+
if (isRowList(value)) return nestedBlock(name, value);
|
|
30782
|
+
return `### ${name}
|
|
30783
|
+
${JSON.stringify(value)}`;
|
|
30784
|
+
}
|
|
30785
|
+
if (typeof value === "object" && value !== null) {
|
|
30786
|
+
const entries = Object.entries(value);
|
|
30787
|
+
if (entries.length === 0) return "";
|
|
30788
|
+
if (entries.every(([, v]) => v === null || typeof v !== "object")) {
|
|
30789
|
+
return `### ${name}
|
|
30790
|
+
${entries.map(([k, v]) => `- ${k}: ${v === null ? "null" : cell2(v, k)}`).join("\n")}`;
|
|
30791
|
+
}
|
|
30792
|
+
return `### ${name}
|
|
30793
|
+
${JSON.stringify(value)}`;
|
|
30794
|
+
}
|
|
30795
|
+
return `### ${name}
|
|
30796
|
+
${cell2(value)}`;
|
|
30797
|
+
}
|
|
30798
|
+
function renderMarkdown3(envelope) {
|
|
30799
|
+
const parts = [];
|
|
30800
|
+
for (const warning of envelope.warnings ?? []) parts.push(`> **${warning.code}** \u2014 ${warning.message}`);
|
|
30801
|
+
for (const hint of envelope.hints ?? []) parts.push(`> ${hint}`);
|
|
30802
|
+
for (const [name, value] of Object.entries(envelope.data).sort(([a], [b]) => byBlockOrder(a, b))) {
|
|
30803
|
+
const rendered = block(name, value);
|
|
30804
|
+
if (rendered !== "") parts.push(rendered);
|
|
30805
|
+
}
|
|
30806
|
+
return `${parts.join("\n\n")}
|
|
30807
|
+
`;
|
|
30808
|
+
}
|
|
30809
|
+
function missingBreakdownHint(data, asked) {
|
|
30810
|
+
if (asked.eventName === void 0) return [];
|
|
30811
|
+
const breakdown = data.eventBreakdown;
|
|
30812
|
+
if (Array.isArray(breakdown) && breakdown.length > 0) return [];
|
|
30813
|
+
const known = Array.isArray(data.customEvents) ? data.customEvents.flatMap((row) => isPlainRow(row) && typeof row.eventName === "string" ? [row.eventName] : []) : [];
|
|
30814
|
+
return [
|
|
30815
|
+
`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" : ""}` : ""}.`
|
|
30816
|
+
];
|
|
30817
|
+
}
|
|
30818
|
+
var ANALYTICS_OUTPUT_FORMATS = ["json", "md"];
|
|
30819
|
+
function isAnalyticsOutputFormat(value) {
|
|
30820
|
+
return ANALYTICS_OUTPUT_FORMATS.includes(value);
|
|
30821
|
+
}
|
|
30822
|
+
function writeAnalyticsReport(envelope, format) {
|
|
30823
|
+
if (format === "md") {
|
|
30824
|
+
process.stdout.write(renderMarkdown3(envelope));
|
|
30825
|
+
return;
|
|
30826
|
+
}
|
|
30827
|
+
process.stdout.write(`${JSON.stringify(envelope)}
|
|
30828
|
+
`);
|
|
30829
|
+
}
|
|
30830
|
+
var ROWS_BEFORE_FORMAT_HINT = 25;
|
|
30831
|
+
function rowCount(data) {
|
|
30832
|
+
let total = 0;
|
|
30833
|
+
for (const value of Object.values(data)) {
|
|
30834
|
+
if (Array.isArray(value)) total += value.length;
|
|
30835
|
+
}
|
|
30836
|
+
return total;
|
|
30837
|
+
}
|
|
30838
|
+
function formatHint(data, format) {
|
|
30839
|
+
if (format === "md") return [];
|
|
30840
|
+
const rows = rowCount(data);
|
|
30841
|
+
if (rows < ROWS_BEFORE_FORMAT_HINT) return [];
|
|
30842
|
+
return [
|
|
30843
|
+
`This report is ${rows} rows. If you are going to read the numbers rather than pick one field out of them, --output md returns the same answer as tables, typically a third to a half smaller.`
|
|
30844
|
+
];
|
|
30845
|
+
}
|
|
30846
|
+
|
|
30847
|
+
// src/commands/analytics/conversionsMarkdown.ts
|
|
30848
|
+
function doorsCell(doors) {
|
|
30849
|
+
return doors.map((door) => `${door.door}=${door.events}/${door.sessions}`).join(" ");
|
|
30850
|
+
}
|
|
30851
|
+
function eventKeysCell(eventKeys) {
|
|
30852
|
+
const formKeys = eventKeys.filter((key) => key.startsWith("form:")).length;
|
|
30853
|
+
const others = eventKeys.filter((key) => !key.startsWith("form:"));
|
|
30854
|
+
return [...others, ...formKeys > 0 ? [`${formKeys} Form ending(s)`] : []].join(" + ");
|
|
30855
|
+
}
|
|
30856
|
+
function trafficByForm(candidates) {
|
|
30857
|
+
const byForm = /* @__PURE__ */ new Map();
|
|
30858
|
+
for (const row of candidates) {
|
|
30859
|
+
const form = byForm.get(row.flowSlug) ?? { "endings seen": 0, "endings counted": 0, events: 0, lastSeen: "" };
|
|
30860
|
+
if (row.events > 0) form["endings seen"] += 1;
|
|
30861
|
+
if (row.isCounted) form["endings counted"] += 1;
|
|
30862
|
+
form.events += row.events;
|
|
30863
|
+
if (row.lastSeen && row.lastSeen.slice(0, 10) > form.lastSeen) form.lastSeen = row.lastSeen.slice(0, 10);
|
|
30864
|
+
byForm.set(row.flowSlug, form);
|
|
30865
|
+
}
|
|
30866
|
+
return byForm;
|
|
30867
|
+
}
|
|
30868
|
+
var NO_TRAFFIC = { "endings seen": 0, "endings counted": 0, events: 0, lastSeen: "" };
|
|
30869
|
+
var FORM_KEYS_HINT = "A Form's candidates are one row per Form: `baker analytics conversions --flow <slug>` lists that Form's event keys, and `--candidates --output json` lists every key.";
|
|
30870
|
+
function renderConversionsMarkdown(envelope) {
|
|
30871
|
+
const { definitions, flow, flows, candidates } = envelope.data;
|
|
30872
|
+
const data = {
|
|
30873
|
+
definitions: definitions.map(({ name, eventKeys, ...row }) => ({
|
|
30874
|
+
name,
|
|
30875
|
+
eventKeys: eventKeysCell(eventKeys),
|
|
30876
|
+
...row
|
|
30877
|
+
}))
|
|
30878
|
+
};
|
|
30879
|
+
if (flow) {
|
|
30880
|
+
data.flow = { slug: flow.slug, noConversionReason: flow.noConversionReason };
|
|
30881
|
+
data.flowEndings = flow.endings;
|
|
30882
|
+
}
|
|
30883
|
+
const traffic = candidates ? trafficByForm(candidates.filter((row) => row.flowSlug !== "")) : /* @__PURE__ */ new Map();
|
|
30884
|
+
if (flows) {
|
|
30885
|
+
data.flows = flows.map((row) => ({
|
|
30886
|
+
slug: row.slug,
|
|
30887
|
+
counted: row.counted.map((entry) => `${entry.name} @ ${entry.step}`).join("; "),
|
|
30888
|
+
noConversion: row.noConversion,
|
|
30889
|
+
...candidates ? traffic.get(row.slug) ?? NO_TRAFFIC : {}
|
|
30890
|
+
}));
|
|
30891
|
+
}
|
|
30892
|
+
const hints2 = [...envelope.hints ?? []];
|
|
30893
|
+
if (candidates) {
|
|
30894
|
+
const listed2 = new Set(flows?.map((row) => row.slug));
|
|
30895
|
+
const unlisted = [...traffic].filter(([slug]) => !listed2.has(slug));
|
|
30896
|
+
if (unlisted.length > 0) data.formCandidates = unlisted.map(([form, row]) => ({ form, ...row }));
|
|
30897
|
+
data.candidates = candidates.filter((row) => row.flowSlug === "").map(({ doors, flowSlug: _flowSlug, nodeType: _nodeType, ...row }) => ({
|
|
30898
|
+
...row,
|
|
30899
|
+
"doors (events/sessions)": doorsCell(doors)
|
|
30900
|
+
}));
|
|
30901
|
+
if (traffic.size > 0) hints2.push(FORM_KEYS_HINT);
|
|
30902
|
+
}
|
|
30903
|
+
return renderMarkdown3({ data, ...hints2.length > 0 ? { hints: hints2 } : {} });
|
|
30904
|
+
}
|
|
30905
|
+
function withFormatHint(envelope, format) {
|
|
30906
|
+
const hints2 = [...envelope.hints ?? [], ...formatHint(envelope.data, format)];
|
|
30907
|
+
return { ...envelope, ...hints2.length > 0 ? { hints: hints2 } : {} };
|
|
30908
|
+
}
|
|
30909
|
+
|
|
31088
30910
|
// src/commands/analytics/errorEnvelope.ts
|
|
31089
30911
|
function analyticsErrorEnvelope(err) {
|
|
31090
30912
|
if (err instanceof ApiError) {
|
|
@@ -31576,223 +31398,6 @@ var ANALYTICS_PRESET_INFO = [
|
|
|
31576
31398
|
}
|
|
31577
31399
|
];
|
|
31578
31400
|
|
|
31579
|
-
// src/commands/analytics/render.ts
|
|
31580
|
-
var SPARKLINE_POINTS = 30;
|
|
31581
|
-
var DASHBOARD_ONLY_FIELDS = /* @__PURE__ */ new Set([
|
|
31582
|
-
// The Convex row id. It exists so a dashboard can link to the row; an agent
|
|
31583
|
-
// addresses a landing by `landingId`, which is the id in its `_definition.md`.
|
|
31584
|
-
"landingRef"
|
|
31585
|
-
]);
|
|
31586
|
-
function isAbsent(value) {
|
|
31587
|
-
if (value === "") return true;
|
|
31588
|
-
if (Array.isArray(value)) return value.length === 0;
|
|
31589
|
-
if (typeof value === "object" && value !== null) return Object.keys(value).length === 0;
|
|
31590
|
-
return false;
|
|
31591
|
-
}
|
|
31592
|
-
function resample(series, points) {
|
|
31593
|
-
if (series.length <= points || points < 1) return [...series];
|
|
31594
|
-
const out = [];
|
|
31595
|
-
for (let i = 0; i < points; i += 1) {
|
|
31596
|
-
const from = Math.floor(i * series.length / points);
|
|
31597
|
-
const to = Math.floor((i + 1) * series.length / points);
|
|
31598
|
-
let sum = 0;
|
|
31599
|
-
for (let j = from; j < to; j += 1) sum += series[j] ?? 0;
|
|
31600
|
-
out.push(sum);
|
|
31601
|
-
}
|
|
31602
|
-
return out;
|
|
31603
|
-
}
|
|
31604
|
-
function pruneValue(value, full) {
|
|
31605
|
-
if (Array.isArray(value)) return value.map((entry) => pruneValue(entry, full));
|
|
31606
|
-
if (typeof value === "object" && value !== null) {
|
|
31607
|
-
return pruneRow(value, full);
|
|
31608
|
-
}
|
|
31609
|
-
return value;
|
|
31610
|
-
}
|
|
31611
|
-
function pruneRow(row, full) {
|
|
31612
|
-
const out = {};
|
|
31613
|
-
for (const [key, value] of Object.entries(row)) {
|
|
31614
|
-
if (DASHBOARD_ONLY_FIELDS.has(key)) continue;
|
|
31615
|
-
if (key === "sparkline" && Array.isArray(value)) {
|
|
31616
|
-
if (!full) continue;
|
|
31617
|
-
out[key] = resample(value, SPARKLINE_POINTS);
|
|
31618
|
-
continue;
|
|
31619
|
-
}
|
|
31620
|
-
if (isAbsent(value)) continue;
|
|
31621
|
-
out[key] = pruneValue(value, full);
|
|
31622
|
-
}
|
|
31623
|
-
return out;
|
|
31624
|
-
}
|
|
31625
|
-
function pruneForAgent(data, full) {
|
|
31626
|
-
return pruneRow(data, full);
|
|
31627
|
-
}
|
|
31628
|
-
function isTabular(rows) {
|
|
31629
|
-
return rows.every(
|
|
31630
|
-
(row) => typeof row === "object" && row !== null && !Array.isArray(row) && Object.values(row).every(
|
|
31631
|
-
(value) => value === null || typeof value !== "object" || Array.isArray(value) && value.every((e) => typeof e !== "object")
|
|
31632
|
-
)
|
|
31633
|
-
);
|
|
31634
|
-
}
|
|
31635
|
-
function cell2(value, key) {
|
|
31636
|
-
if (value === null || value === void 0) return "";
|
|
31637
|
-
if (Array.isArray(value)) return value.join(" ");
|
|
31638
|
-
if (typeof value === "number" && !Number.isInteger(value)) {
|
|
31639
|
-
if (key?.endsWith("Ms")) return String(Math.round(value));
|
|
31640
|
-
return value.toFixed(4).replace(/0+$/, "").replace(/\.$/, "");
|
|
31641
|
-
}
|
|
31642
|
-
return String(value);
|
|
31643
|
-
}
|
|
31644
|
-
var IDENTITY_COLUMNS = [
|
|
31645
|
-
"landingId",
|
|
31646
|
-
"name",
|
|
31647
|
-
"slug",
|
|
31648
|
-
"path",
|
|
31649
|
-
"flowSlug",
|
|
31650
|
-
"stepId",
|
|
31651
|
-
"value",
|
|
31652
|
-
"key",
|
|
31653
|
-
"bucket",
|
|
31654
|
-
"tag",
|
|
31655
|
-
"eventName",
|
|
31656
|
-
"release",
|
|
31657
|
-
"place",
|
|
31658
|
-
"bot",
|
|
31659
|
-
"source",
|
|
31660
|
-
"medium",
|
|
31661
|
-
"campaign",
|
|
31662
|
-
"platform",
|
|
31663
|
-
"sessionId",
|
|
31664
|
-
"eventId"
|
|
31665
|
-
];
|
|
31666
|
-
function byIdentityFirst(a, b) {
|
|
31667
|
-
const ia = IDENTITY_COLUMNS.indexOf(a);
|
|
31668
|
-
const ib = IDENTITY_COLUMNS.indexOf(b);
|
|
31669
|
-
if (ia !== -1 || ib !== -1)
|
|
31670
|
-
return (ia === -1 ? Number.MAX_SAFE_INTEGER : ia) - (ib === -1 ? Number.MAX_SAFE_INTEGER : ib);
|
|
31671
|
-
return 0;
|
|
31672
|
-
}
|
|
31673
|
-
var BLOCK_ORDER = ["window", "totals", "previous", "pageInfo"];
|
|
31674
|
-
function byBlockOrder(a, b) {
|
|
31675
|
-
const rank = (key) => {
|
|
31676
|
-
const at = BLOCK_ORDER.indexOf(key);
|
|
31677
|
-
if (at !== -1) return at;
|
|
31678
|
-
return key === "preset" ? BLOCK_ORDER.length + 1 : BLOCK_ORDER.length;
|
|
31679
|
-
};
|
|
31680
|
-
return rank(a) - rank(b);
|
|
31681
|
-
}
|
|
31682
|
-
function columnsOf(rows) {
|
|
31683
|
-
const seen = [];
|
|
31684
|
-
for (const row of rows) {
|
|
31685
|
-
for (const key of Object.keys(row)) {
|
|
31686
|
-
if (!seen.includes(key)) seen.push(key);
|
|
31687
|
-
}
|
|
31688
|
-
}
|
|
31689
|
-
return seen.filter((key) => rows.some((row) => !isAbsent(row[key]) && row[key] !== null && row[key] !== void 0)).sort(byIdentityFirst);
|
|
31690
|
-
}
|
|
31691
|
-
function table2(rows) {
|
|
31692
|
-
const cols = columnsOf(rows);
|
|
31693
|
-
if (cols.length === 0) return "";
|
|
31694
|
-
const head = `| ${cols.join(" | ")} |`;
|
|
31695
|
-
const rule = `| ${cols.map(() => "---").join(" | ")} |`;
|
|
31696
|
-
const body = rows.map((row) => `| ${cols.map((col) => cell2(row[col], col)).join(" | ")} |`);
|
|
31697
|
-
return [head, rule, ...body].join("\n");
|
|
31698
|
-
}
|
|
31699
|
-
function isRowList(value) {
|
|
31700
|
-
return Array.isArray(value) && value.length > 0 && value.every((entry) => typeof entry === "object" && entry !== null && !Array.isArray(entry));
|
|
31701
|
-
}
|
|
31702
|
-
function labelOf(row, index) {
|
|
31703
|
-
for (const key of IDENTITY_COLUMNS) {
|
|
31704
|
-
const value = row[key];
|
|
31705
|
-
if (typeof value === "string" && value !== "") return value;
|
|
31706
|
-
}
|
|
31707
|
-
return `#${index + 1}`;
|
|
31708
|
-
}
|
|
31709
|
-
function nestedBlock(name, rows) {
|
|
31710
|
-
const parents = rows.map(
|
|
31711
|
-
(row) => Object.fromEntries(Object.entries(row).filter(([, value]) => !isRowList(value) && !isPlainRow(value)))
|
|
31712
|
-
);
|
|
31713
|
-
const parts = [`### ${name}`, table2(parents)];
|
|
31714
|
-
rows.forEach((row, index) => {
|
|
31715
|
-
for (const [key, value] of Object.entries(row)) {
|
|
31716
|
-
if (isRowList(value)) parts.push(`#### ${name}[${labelOf(row, index)}].${key}`, table2(value));
|
|
31717
|
-
else if (isPlainRow(value)) parts.push(`#### ${name}[${labelOf(row, index)}].${key}`, table2([value]));
|
|
31718
|
-
}
|
|
31719
|
-
});
|
|
31720
|
-
return parts.filter((part) => part !== "").join("\n");
|
|
31721
|
-
}
|
|
31722
|
-
function isPlainRow(value) {
|
|
31723
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
31724
|
-
}
|
|
31725
|
-
function block(name, value) {
|
|
31726
|
-
if (Array.isArray(value)) {
|
|
31727
|
-
if (value.length === 0) return "";
|
|
31728
|
-
if (isTabular(value)) return `### ${name}
|
|
31729
|
-
${table2(value)}`;
|
|
31730
|
-
if (isRowList(value)) return nestedBlock(name, value);
|
|
31731
|
-
return `### ${name}
|
|
31732
|
-
${JSON.stringify(value)}`;
|
|
31733
|
-
}
|
|
31734
|
-
if (typeof value === "object" && value !== null) {
|
|
31735
|
-
const entries = Object.entries(value);
|
|
31736
|
-
if (entries.length === 0) return "";
|
|
31737
|
-
if (entries.every(([, v]) => v === null || typeof v !== "object")) {
|
|
31738
|
-
return `### ${name}
|
|
31739
|
-
${entries.map(([k, v]) => `- ${k}: ${v === null ? "null" : cell2(v, k)}`).join("\n")}`;
|
|
31740
|
-
}
|
|
31741
|
-
return `### ${name}
|
|
31742
|
-
${JSON.stringify(value)}`;
|
|
31743
|
-
}
|
|
31744
|
-
return `### ${name}
|
|
31745
|
-
${cell2(value)}`;
|
|
31746
|
-
}
|
|
31747
|
-
function renderMarkdown3(envelope) {
|
|
31748
|
-
const parts = [];
|
|
31749
|
-
for (const warning of envelope.warnings ?? []) parts.push(`> **${warning.code}** \u2014 ${warning.message}`);
|
|
31750
|
-
for (const hint of envelope.hints ?? []) parts.push(`> ${hint}`);
|
|
31751
|
-
for (const [name, value] of Object.entries(envelope.data).sort(([a], [b]) => byBlockOrder(a, b))) {
|
|
31752
|
-
const rendered = block(name, value);
|
|
31753
|
-
if (rendered !== "") parts.push(rendered);
|
|
31754
|
-
}
|
|
31755
|
-
return `${parts.join("\n\n")}
|
|
31756
|
-
`;
|
|
31757
|
-
}
|
|
31758
|
-
function missingBreakdownHint(data, asked) {
|
|
31759
|
-
if (asked.eventName === void 0) return [];
|
|
31760
|
-
const breakdown = data.eventBreakdown;
|
|
31761
|
-
if (Array.isArray(breakdown) && breakdown.length > 0) return [];
|
|
31762
|
-
const known = Array.isArray(data.customEvents) ? data.customEvents.flatMap((row) => isPlainRow(row) && typeof row.eventName === "string" ? [row.eventName] : []) : [];
|
|
31763
|
-
return [
|
|
31764
|
-
`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" : ""}` : ""}.`
|
|
31765
|
-
];
|
|
31766
|
-
}
|
|
31767
|
-
var ANALYTICS_OUTPUT_FORMATS = ["json", "md"];
|
|
31768
|
-
function isAnalyticsOutputFormat(value) {
|
|
31769
|
-
return ANALYTICS_OUTPUT_FORMATS.includes(value);
|
|
31770
|
-
}
|
|
31771
|
-
function writeAnalyticsReport(envelope, format) {
|
|
31772
|
-
if (format === "md") {
|
|
31773
|
-
process.stdout.write(renderMarkdown3(envelope));
|
|
31774
|
-
return;
|
|
31775
|
-
}
|
|
31776
|
-
process.stdout.write(`${JSON.stringify(envelope)}
|
|
31777
|
-
`);
|
|
31778
|
-
}
|
|
31779
|
-
var ROWS_BEFORE_FORMAT_HINT = 25;
|
|
31780
|
-
function rowCount(data) {
|
|
31781
|
-
let total = 0;
|
|
31782
|
-
for (const value of Object.values(data)) {
|
|
31783
|
-
if (Array.isArray(value)) total += value.length;
|
|
31784
|
-
}
|
|
31785
|
-
return total;
|
|
31786
|
-
}
|
|
31787
|
-
function formatHint(data, format) {
|
|
31788
|
-
if (format === "md") return [];
|
|
31789
|
-
const rows = rowCount(data);
|
|
31790
|
-
if (rows < ROWS_BEFORE_FORMAT_HINT) return [];
|
|
31791
|
-
return [
|
|
31792
|
-
`This report is ${rows} rows. If you are going to read the numbers rather than pick one field out of them, --output md returns the same answer as tables, typically a third to a half smaller.`
|
|
31793
|
-
];
|
|
31794
|
-
}
|
|
31795
|
-
|
|
31796
31401
|
// src/commands/analytics/sends.ts
|
|
31797
31402
|
import { defineCommand as defineCommand97 } from "citty";
|
|
31798
31403
|
var SET_FLAGS = ["--source-event", "--platform", "--tag", "--event"];
|
|
@@ -32967,17 +32572,7 @@ async function runPreset(args5, options) {
|
|
|
32967
32572
|
const response = await apiPost("/api/analytics/query", requestBody(args5, options));
|
|
32968
32573
|
const requestedPlatform = args5.platform === void 0 ? "" : String(args5.platform);
|
|
32969
32574
|
const adPlatformScope = isAdPlatform(requestedPlatform) ? requestedPlatform : void 0;
|
|
32970
|
-
const format =
|
|
32971
|
-
if (!isAnalyticsOutputFormat(format)) {
|
|
32972
|
-
writeJsonEnvelope({
|
|
32973
|
-
ok: false,
|
|
32974
|
-
error: {
|
|
32975
|
-
code: "VALIDATION_ERROR",
|
|
32976
|
-
message: `Unknown --output "${format}". Use one of: ${ANALYTICS_OUTPUT_FORMATS.join(", ")}.`
|
|
32977
|
-
}
|
|
32978
|
-
});
|
|
32979
|
-
process.exit(1);
|
|
32980
|
-
}
|
|
32575
|
+
const format = outputFormatOrExit(args5.output);
|
|
32981
32576
|
const data = pruneForAgent(response.data, args5.full === true);
|
|
32982
32577
|
const feed = "stream" in data ? shapeFeed(data.stream, args5.everything === true) : void 0;
|
|
32983
32578
|
if (feed !== void 0) data.stream = feed.rows;
|
|
@@ -33007,6 +32602,20 @@ async function runPreset(args5, options) {
|
|
|
33007
32602
|
handleError3(err);
|
|
33008
32603
|
}
|
|
33009
32604
|
}
|
|
32605
|
+
function outputFormatOrExit(raw) {
|
|
32606
|
+
const format = raw === void 0 ? "json" : String(raw);
|
|
32607
|
+
if (!isAnalyticsOutputFormat(format)) {
|
|
32608
|
+
writeJsonEnvelope({
|
|
32609
|
+
ok: false,
|
|
32610
|
+
error: {
|
|
32611
|
+
code: "VALIDATION_ERROR",
|
|
32612
|
+
message: `Unknown --output "${format}". Use one of: ${ANALYTICS_OUTPUT_FORMATS.join(", ")}.`
|
|
32613
|
+
}
|
|
32614
|
+
});
|
|
32615
|
+
process.exit(1);
|
|
32616
|
+
}
|
|
32617
|
+
return format;
|
|
32618
|
+
}
|
|
33010
32619
|
function presetCommand(options) {
|
|
33011
32620
|
registerSchema({
|
|
33012
32621
|
command: `analytics.${options.name}`,
|
|
@@ -33508,7 +33117,8 @@ var conversionsCommand3 = (() => {
|
|
|
33508
33117
|
type: "string",
|
|
33509
33118
|
description: "Lookback for the counts and for --candidates. Default 30",
|
|
33510
33119
|
required: false
|
|
33511
|
-
}
|
|
33120
|
+
},
|
|
33121
|
+
output: SHARED_ARGS.output
|
|
33512
33122
|
};
|
|
33513
33123
|
registerSchema({
|
|
33514
33124
|
command: "analytics.conversions",
|
|
@@ -33523,22 +33133,23 @@ var conversionsCommand3 = (() => {
|
|
|
33523
33133
|
args: args5,
|
|
33524
33134
|
run: async ({ args: raw }) => {
|
|
33525
33135
|
try {
|
|
33136
|
+
const format = outputFormatOrExit(raw.output);
|
|
33526
33137
|
const args6 = parseConversionsArgs(raw, process.argv);
|
|
33527
33138
|
for (const eventKey of args6.eventKeys) refuseUnmatchableKey(eventKey);
|
|
33528
33139
|
const before = await apiPost("/api/analytics/conversions", {});
|
|
33529
|
-
const
|
|
33530
|
-
const stored =
|
|
33140
|
+
const write = conversionsWrite(args6, before.data.definitions);
|
|
33141
|
+
const stored = write ? (await apiPost("/api/analytics/conversions", write)).data.definitions : before.data.definitions;
|
|
33531
33142
|
const report = await apiPost("/api/analytics/query", {
|
|
33532
33143
|
preset: "conversions",
|
|
33533
33144
|
days: args6.days
|
|
33534
33145
|
});
|
|
33535
|
-
|
|
33536
|
-
|
|
33537
|
-
|
|
33538
|
-
|
|
33539
|
-
report.data.eventCatalog ?? []
|
|
33540
|
-
)
|
|
33146
|
+
const envelope = conversionsEnvelope(
|
|
33147
|
+
args6,
|
|
33148
|
+
mergeStoredWithCounts(stored, report.data.conversions ?? []),
|
|
33149
|
+
report.data.eventCatalog ?? []
|
|
33541
33150
|
);
|
|
33151
|
+
if (format === "md") process.stdout.write(renderConversionsMarkdown(envelope));
|
|
33152
|
+
else writeJsonEnvelope(withFormatHint(envelope, format));
|
|
33542
33153
|
} catch (err) {
|
|
33543
33154
|
if (err instanceof ConversionArgsError) {
|
|
33544
33155
|
handleError3(new ApiError("VALIDATION_ERROR", err.message));
|
|
@@ -33903,11 +33514,7 @@ function rosterRow(avatar) {
|
|
|
33903
33514
|
};
|
|
33904
33515
|
}
|
|
33905
33516
|
function chatIdFromEnv() {
|
|
33906
|
-
|
|
33907
|
-
return getEnv().BAKER_CHAT_ID || void 0;
|
|
33908
|
-
} catch {
|
|
33909
|
-
return void 0;
|
|
33910
|
-
}
|
|
33517
|
+
return optionalChatId();
|
|
33911
33518
|
}
|
|
33912
33519
|
function rosterHints(roster, statusFilter) {
|
|
33913
33520
|
if (roster.length === 0) {
|
|
@@ -39436,7 +39043,7 @@ function sceneSpokenText(scene) {
|
|
|
39436
39043
|
return (scene.dialogue ?? []).map((d) => d.line?.trim()).filter((l) => Boolean(l)).join(" ") || null;
|
|
39437
39044
|
}
|
|
39438
39045
|
function buildMotionBoard(blueprint) {
|
|
39439
|
-
const
|
|
39046
|
+
const round4 = (n) => Math.round(n * 100) / 100;
|
|
39440
39047
|
let cursor = 0;
|
|
39441
39048
|
return blueprint.scenes.map((scene, i) => {
|
|
39442
39049
|
const start_s = scene.start_s ?? cursor;
|
|
@@ -39448,15 +39055,15 @@ function buildMotionBoard(blueprint) {
|
|
|
39448
39055
|
const graphics = [
|
|
39449
39056
|
...(overlays.success ? overlays.data : []).filter((ov) => ov.text?.trim()).map((ov) => ({
|
|
39450
39057
|
kind: "text",
|
|
39451
|
-
at_s:
|
|
39452
|
-
dur_s:
|
|
39058
|
+
at_s: round4(ov.appears_at_s ?? start_s),
|
|
39059
|
+
dur_s: round4(ov.duration_s ?? 2.5),
|
|
39453
39060
|
position: ov.position ?? "bottom_center",
|
|
39454
39061
|
text: ov.text?.trim()
|
|
39455
39062
|
})),
|
|
39456
39063
|
...(floats.success ? floats.data : []).map((fe) => ({
|
|
39457
39064
|
kind: "graphic",
|
|
39458
|
-
at_s:
|
|
39459
|
-
dur_s:
|
|
39065
|
+
at_s: round4(fe.appears_at_s ?? start_s),
|
|
39066
|
+
dur_s: round4(fe.duration_s ?? 2.5),
|
|
39460
39067
|
position: fe.position ?? "bottom_center",
|
|
39461
39068
|
label: fe.brand_name || fe.what_it_represents || fe.description || fe.kind || "element"
|
|
39462
39069
|
}))
|
|
@@ -39464,7 +39071,7 @@ function buildMotionBoard(blueprint) {
|
|
|
39464
39071
|
return {
|
|
39465
39072
|
scene: i,
|
|
39466
39073
|
role: resolveSceneRole(scene, i, blueprint.scenes.length),
|
|
39467
|
-
window_s: [
|
|
39074
|
+
window_s: [round4(start_s), round4(end_s)],
|
|
39468
39075
|
// A continuation b-roll scene shares the previous scene's end frame as its start
|
|
39469
39076
|
// (no own `s<i>_start` node), so point the storyboard at that shared keyframe.
|
|
39470
39077
|
storyboard_frames: [scene.continues_previous && i > 0 ? `s${i - 1}_end` : `s${i}_start`],
|
|
@@ -41227,7 +40834,7 @@ ${describeRewrites(healed.rewrites)}
|
|
|
41227
40834
|
// "edited since last render". Computed from the on-disk canvas.json +
|
|
41228
40835
|
// prompt.json — the same helper the edit-sync uses, so the two are comparable.
|
|
41229
40836
|
sourceSha: await computeSourceSha(filePath),
|
|
41230
|
-
chatId:
|
|
40837
|
+
chatId: optionalChatId(),
|
|
41231
40838
|
canvasSnapshotUrl
|
|
41232
40839
|
};
|
|
41233
40840
|
if (client) {
|
|
@@ -45218,11 +44825,7 @@ function detectCreativeContentType(filePath) {
|
|
|
45218
44825
|
});
|
|
45219
44826
|
}
|
|
45220
44827
|
function chatIdFromEnv2() {
|
|
45221
|
-
|
|
45222
|
-
return getEnv().BAKER_CHAT_ID || void 0;
|
|
45223
|
-
} catch {
|
|
45224
|
-
return void 0;
|
|
45225
|
-
}
|
|
44828
|
+
return optionalChatId();
|
|
45226
44829
|
}
|
|
45227
44830
|
function parseOptionalUrl(value) {
|
|
45228
44831
|
if (value === void 0 || value.trim() === "") {
|
|
@@ -53139,7 +52742,7 @@ var extractCommand = defineCommand149({
|
|
|
53139
52742
|
import { defineCommand as defineCommand150 } from "citty";
|
|
53140
52743
|
|
|
53141
52744
|
// src/commands/images/providerHits.ts
|
|
53142
|
-
function
|
|
52745
|
+
function asRecord2(value) {
|
|
53143
52746
|
return value && typeof value === "object" ? value : {};
|
|
53144
52747
|
}
|
|
53145
52748
|
function str(value) {
|
|
@@ -53164,7 +52767,7 @@ function providerHitNormalizer(record, full) {
|
|
|
53164
52767
|
if (!full) {
|
|
53165
52768
|
return compact3;
|
|
53166
52769
|
}
|
|
53167
|
-
const group =
|
|
52770
|
+
const group = asRecord2(record.group);
|
|
53168
52771
|
return {
|
|
53169
52772
|
...compact3,
|
|
53170
52773
|
externalUrl: str(record.externalUrl),
|
|
@@ -57069,7 +56672,7 @@ function dedupe(findings) {
|
|
|
57069
56672
|
|
|
57070
56673
|
// src/engine/landing/lib/critique.ts
|
|
57071
56674
|
var FAMILIES = ["typography", "color", "borders_depth", "motion", "spacing", "copy", "integrity"];
|
|
57072
|
-
function
|
|
56675
|
+
function round2(n) {
|
|
57073
56676
|
return Math.round(n * 100) / 100;
|
|
57074
56677
|
}
|
|
57075
56678
|
function clamp012(n) {
|
|
@@ -57106,11 +56709,11 @@ function critiqueLanding(input) {
|
|
|
57106
56709
|
const dimensions = FAMILIES.map((family) => {
|
|
57107
56710
|
const fam = findings.filter((f) => f.family === family);
|
|
57108
56711
|
const penalty = fam.reduce((s, f) => s + SEVERITY_WEIGHT[f.severity], 0);
|
|
57109
|
-
const score =
|
|
56712
|
+
const score = round2(clamp012(1 - penalty));
|
|
57110
56713
|
const note = fam.length === 0 ? "clean" : `${fam.length} finding(s): ${describeCounts(fam)}`;
|
|
57111
56714
|
return { dimension: family, score, note };
|
|
57112
56715
|
});
|
|
57113
|
-
const overall =
|
|
56716
|
+
const overall = round2(dimensions.reduce((s, d) => s + d.score, 0) / dimensions.length);
|
|
57114
56717
|
const counts = {
|
|
57115
56718
|
block: findings.filter((f) => f.severity === "block").length,
|
|
57116
56719
|
warn: findings.filter((f) => f.severity === "warn").length,
|
|
@@ -61269,7 +60872,7 @@ function writeJsonl(data) {
|
|
|
61269
60872
|
`);
|
|
61270
60873
|
}
|
|
61271
60874
|
}
|
|
61272
|
-
function
|
|
60875
|
+
function writeMd(data, fields) {
|
|
61273
60876
|
if (data.length === 0) return;
|
|
61274
60877
|
const cols = fields ?? Object.keys(data[0] ?? {});
|
|
61275
60878
|
process.stdout.write(`| ${cols.join(" | ")} |
|
|
@@ -61291,7 +60894,7 @@ function writeResearchOutput(data, format, fields) {
|
|
|
61291
60894
|
writeJsonl(data);
|
|
61292
60895
|
break;
|
|
61293
60896
|
case "md":
|
|
61294
|
-
|
|
60897
|
+
writeMd(data, fields);
|
|
61295
60898
|
break;
|
|
61296
60899
|
default:
|
|
61297
60900
|
writeResearchJson({ ok: true, data });
|