@koda-sl/baker-cli 0.346.0 → 0.347.0-dev.043fc924c

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.
Files changed (28) hide show
  1. package/README.md +3 -3
  2. package/dist/chunk-4VP5WWPR.js +376 -0
  3. package/dist/chunk-4VP5WWPR.js.map +1 -0
  4. package/dist/{chunk-YBD3W4M7.js → chunk-D5P4COPD.js} +8 -9
  5. package/dist/chunk-D5P4COPD.js.map +1 -0
  6. package/dist/{chunk-NA5CPMUA.js → chunk-JWMLQSGK.js} +4 -4
  7. package/dist/{chunk-2IC3CGQO.js → chunk-KGDL7F7M.js} +3 -3
  8. package/dist/{chunk-XWHHYHKQ.js → chunk-PWGY347J.js} +2 -2
  9. package/dist/{chunk-4QXKWIFC.js → chunk-XPUSSDLR.js} +3 -3
  10. package/dist/cli.js +519 -53
  11. package/dist/cli.js.map +1 -1
  12. package/dist/{client-ODCNYCP4.js → client-PWRZOA3Q.js} +4 -4
  13. package/dist/engine/index.js +3 -3
  14. package/dist/{env-BSG7TY5Y.js → env-TQTHWLBN.js} +2 -6
  15. package/dist/{output-2XBCYF7L.js → output-HD63GTWI.js} +5 -5
  16. package/dist/{shared-RYAF7Y7H.js → shared-5662SBDW.js} +6 -6
  17. package/package.json +1 -1
  18. package/dist/chunk-2OKSJNLA.js +0 -855
  19. package/dist/chunk-2OKSJNLA.js.map +0 -1
  20. package/dist/chunk-YBD3W4M7.js.map +0 -1
  21. /package/dist/{chunk-NA5CPMUA.js.map → chunk-JWMLQSGK.js.map} +0 -0
  22. /package/dist/{chunk-2IC3CGQO.js.map → chunk-KGDL7F7M.js.map} +0 -0
  23. /package/dist/{chunk-XWHHYHKQ.js.map → chunk-PWGY347J.js.map} +0 -0
  24. /package/dist/{chunk-4QXKWIFC.js.map → chunk-XPUSSDLR.js.map} +0 -0
  25. /package/dist/{client-ODCNYCP4.js.map → client-PWRZOA3Q.js.map} +0 -0
  26. /package/dist/{env-BSG7TY5Y.js.map → env-TQTHWLBN.js.map} +0 -0
  27. /package/dist/{output-2XBCYF7L.js.map → output-HD63GTWI.js.map} +0 -0
  28. /package/dist/{shared-RYAF7Y7H.js.map → shared-5662SBDW.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-YBD3W4M7.js";
70
+ } from "./chunk-D5P4COPD.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-NA5CPMUA.js";
79
+ } from "./chunk-JWMLQSGK.js";
80
80
  import {
81
81
  buildQueryCacheKey,
82
82
  cacheGet,
@@ -92,42 +92,33 @@ import {
92
92
  writeAdsJson,
93
93
  writeAdsOutput,
94
94
  writeJsonEnvelope
95
- } from "./chunk-2IC3CGQO.js";
95
+ } from "./chunk-KGDL7F7M.js";
96
96
  import {
97
97
  ApiError,
98
98
  apiGet,
99
99
  apiGetWithHeaders,
100
100
  apiPost,
101
101
  validateConvexId
102
- } from "./chunk-4QXKWIFC.js";
102
+ } from "./chunk-XPUSSDLR.js";
103
103
  import {
104
104
  installExitRecord,
105
105
  installStreamTaps,
106
106
  logInvocation
107
- } from "./chunk-XWHHYHKQ.js";
107
+ } from "./chunk-PWGY347J.js";
108
108
  import {
109
- adContentNormalizer,
110
109
  captureBudgetMs,
111
110
  captureProxyCredentials,
112
111
  captureVimeoCookie,
113
- compactImage,
114
- compactVideo,
115
112
  getEnv,
116
113
  hasOpenRouterKey,
117
114
  isProxyFailure,
118
115
  openRouterKey,
119
- optionalChatId,
120
116
  plannedRoutes,
121
117
  refuseNonPublicUrl,
122
118
  requireChatId,
123
119
  resolveChatId,
124
- shouldEscalate,
125
- testimonialNormalizer,
126
- videoNormalizer,
127
- winningAdNormalizer,
128
- writeJson,
129
- writeOutput
130
- } from "./chunk-2OKSJNLA.js";
120
+ shouldEscalate
121
+ } from "./chunk-4VP5WWPR.js";
131
122
 
132
123
  // src/cli.ts
133
124
  import { defineCommand as defineCommand245, runMain } from "citty";
@@ -168,6 +159,420 @@ import { defineCommand as defineCommand18 } from "citty";
168
159
  // src/commands/actions/claim.ts
169
160
  import { defineCommand } from "citty";
170
161
 
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
+
171
576
  // src/schemas.ts
172
577
  var registry = /* @__PURE__ */ new Map();
173
578
  function registerSchema(schema) {
@@ -384,6 +789,50 @@ var actionsUpdateRequestSchema = z.object({
384
789
  var actionsUpdateResponseSchema = okOnlySchema();
385
790
  var ACTION_COMPLETE_NOTE_MIN = 20;
386
791
  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
+ }
387
836
  var actionsCompleteRequestSchema = z.object({
388
837
  chatId: z.string(),
389
838
  actionRef: z.string().min(1, "actionRef is required"),
@@ -391,6 +840,11 @@ var actionsCompleteRequestSchema = z.object({
391
840
  }).transform((body) => ({ ...body, note: (body.note ?? "").trim() })).refine((body) => body.note.length >= ACTION_COMPLETE_NOTE_MIN, {
392
841
  message: actionsCompleteNoteMessage,
393
842
  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
+ }
394
848
  });
395
849
  var actionsCompleteResponseSchema = okOnlySchema();
396
850
  var actionsDiscardRequestSchema = z.object({
@@ -8055,12 +8509,12 @@ var claimCommand = defineCommand({
8055
8509
  import { defineCommand as defineCommand2 } from "citty";
8056
8510
  registerSchema({
8057
8511
  command: "actions.complete",
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`.",
8512
+ 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 shown on the Task in Tasks and surfaced by `baker actions log`, so write it for a marketer, in the client\'s language and product terms: a few lines, no file paths, account ids, error codes or `baker` commands ("Weekly review saved in your Knowledge; Google Ads and LinkedIn are not connected yet", not "written to src/content/audits/\u2026md; NO_GOOGLE_ADS_CONNECTION"). A note carrying those is refused. 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`.',
8059
8513
  args: {
8060
8514
  id: { type: "string", description: "Action ID or temp ID", required: true },
8061
8515
  note: {
8062
8516
  type: "string",
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`.",
8517
+ description: "REQUIRED. What you did to resolve this \u2014 what changed, where (in product terms: the page, the campaign, Knowledge), and the outcome \u2014 in a few lines. The client reads it on the Task: no file paths, account ids, error codes or `baker` commands.",
8064
8518
  required: true
8065
8519
  }
8066
8520
  }
@@ -8075,7 +8529,7 @@ var completeCommand = defineCommand2({
8075
8529
  "action-id": { type: "string", description: "Action ID or temp ID", required: false },
8076
8530
  note: {
8077
8531
  type: "string",
8078
- description: "REQUIRED. What you did to resolve this: what changed, where, and the outcome.",
8532
+ description: "REQUIRED. What you did, where (in product terms) and the outcome \u2014 read by the client, so no file paths, account ids or error codes.",
8079
8533
  required: false
8080
8534
  }
8081
8535
  },
@@ -8094,6 +8548,10 @@ var completeCommand = defineCommand2({
8094
8548
  `--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\`.`
8095
8549
  );
8096
8550
  }
8551
+ const internals = completionNoteInternals(note);
8552
+ if (internals.length > 0) {
8553
+ failValidation(`--note: ${completionNoteInternalsMessage(internals)} Then run the same command again.`);
8554
+ }
8097
8555
  const chatId = requireChatId();
8098
8556
  await apiPost("/api/actions/complete", { chatId, actionRef: id, note });
8099
8557
  writeOk();
@@ -12677,8 +13135,8 @@ var writeMdRows = (rows, fields, notices) => {
12677
13135
  };
12678
13136
  var ROW_WRITERS = { csv: writeCsvRows, jsonl: writeJsonlRows, md: writeMdRows };
12679
13137
  function writeRows(format, rows, columns, notices) {
12680
- const write = ROW_WRITERS[format] ?? writeMdRows;
12681
- write(rows, columns, notices);
13138
+ const write2 = ROW_WRITERS[format] ?? writeMdRows;
13139
+ write2(rows, columns, notices);
12682
13140
  if (rows.length > REPEAT_NOTICE_ABOVE_ROWS) {
12683
13141
  for (const line of notices) writeLine(line);
12684
13142
  }
@@ -21881,7 +22339,7 @@ Subcommands:
21881
22339
 
21882
22340
  // src/commands/ads/linkedin/creatives.ts
21883
22341
  import { defineCommand as defineCommand44 } from "citty";
21884
- function asRecord(value) {
22342
+ function asRecord2(value) {
21885
22343
  return typeof value === "object" && value !== null && !Array.isArray(value) ? value : void 0;
21886
22344
  }
21887
22345
  function asString(value) {
@@ -21891,12 +22349,12 @@ function creativeDestination(content) {
21891
22349
  if (!content) return { format: "unknown" };
21892
22350
  const reference = asString(content.reference);
21893
22351
  if (reference) return { format: "post", postUrn: reference };
21894
- const textAd = asRecord(content.textAd);
22352
+ const textAd = asRecord2(content.textAd);
21895
22353
  if (textAd) return { format: "text", landingUrl: asString(textAd.landingPage) };
21896
- const spotlight = asRecord(content.spotlight);
22354
+ const spotlight = asRecord2(content.spotlight);
21897
22355
  if (spotlight) return { format: "spotlight", landingUrl: asString(spotlight.landingPage) };
21898
- if (asRecord(content.follower)) return { format: "follower" };
21899
- if (asRecord(content.jobs)) return { format: "jobs" };
22356
+ if (asRecord2(content.follower)) return { format: "follower" };
22357
+ if (asRecord2(content.jobs)) return { format: "jobs" };
21900
22358
  return { format: "unknown" };
21901
22359
  }
21902
22360
  var COMPACT_COLUMNS = [
@@ -21927,7 +22385,7 @@ function compactRow(row) {
21927
22385
  function readPath(row, path48) {
21928
22386
  let current = row;
21929
22387
  for (const segment of path48.split(".")) {
21930
- const record = asRecord(current);
22388
+ const record = asRecord2(current);
21931
22389
  if (!record) return void 0;
21932
22390
  current = record[segment];
21933
22391
  }
@@ -25300,10 +25758,10 @@ Example: baker ads meta ads retag 120252158038400247 --url-tags "utm_source={{si
25300
25758
  }
25301
25759
  },
25302
25760
  run: async ({ args: args5 }) => {
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");
25761
+ const { apiPost: apiPost2 } = await import("./client-PWRZOA3Q.js");
25762
+ const { requireChatId: requireChatId2 } = await import("./env-TQTHWLBN.js");
25763
+ const { writeJsonEnvelope: writeJsonEnvelope2 } = await import("./output-HD63GTWI.js");
25764
+ const { handleMetaError: handleMetaError2 } = await import("./shared-5662SBDW.js");
25307
25765
  try {
25308
25766
  const accountId = bareAccountId2(args5);
25309
25767
  const urlTags = typeof args5["url-tags"] === "string" ? args5["url-tags"] : void 0;
@@ -25448,10 +25906,10 @@ function duplicateCommand2(entity, label) {
25448
25906
  replace: { type: "boolean", description: "Pause the original once the copy publishes" }
25449
25907
  },
25450
25908
  run: async ({ args: args5 }) => {
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");
25909
+ const { apiPost: apiPost2 } = await import("./client-PWRZOA3Q.js");
25910
+ const { requireChatId: requireChatId2 } = await import("./env-TQTHWLBN.js");
25911
+ const { writeJsonEnvelope: writeJsonEnvelope2 } = await import("./output-HD63GTWI.js");
25912
+ const { handleMetaError: handleMetaError2 } = await import("./shared-5662SBDW.js");
25455
25913
  try {
25456
25914
  const accountId = bareAccountId2(args5);
25457
25915
  const chatId = requireChatId2();
@@ -33068,8 +33526,8 @@ var conversionsCommand3 = (() => {
33068
33526
  const args6 = parseConversionsArgs(raw, process.argv);
33069
33527
  for (const eventKey of args6.eventKeys) refuseUnmatchableKey(eventKey);
33070
33528
  const before = await apiPost("/api/analytics/conversions", {});
33071
- const write = conversionsWrite(args6, before.data.definitions);
33072
- const stored = write ? (await apiPost("/api/analytics/conversions", write)).data.definitions : before.data.definitions;
33529
+ const write2 = conversionsWrite(args6, before.data.definitions);
33530
+ const stored = write2 ? (await apiPost("/api/analytics/conversions", write2)).data.definitions : before.data.definitions;
33073
33531
  const report = await apiPost("/api/analytics/query", {
33074
33532
  preset: "conversions",
33075
33533
  days: args6.days
@@ -33445,7 +33903,11 @@ function rosterRow(avatar) {
33445
33903
  };
33446
33904
  }
33447
33905
  function chatIdFromEnv() {
33448
- return optionalChatId();
33906
+ try {
33907
+ return getEnv().BAKER_CHAT_ID || void 0;
33908
+ } catch {
33909
+ return void 0;
33910
+ }
33449
33911
  }
33450
33912
  function rosterHints(roster, statusFilter) {
33451
33913
  if (roster.length === 0) {
@@ -38974,7 +39436,7 @@ function sceneSpokenText(scene) {
38974
39436
  return (scene.dialogue ?? []).map((d) => d.line?.trim()).filter((l) => Boolean(l)).join(" ") || null;
38975
39437
  }
38976
39438
  function buildMotionBoard(blueprint) {
38977
- const round4 = (n) => Math.round(n * 100) / 100;
39439
+ const round5 = (n) => Math.round(n * 100) / 100;
38978
39440
  let cursor = 0;
38979
39441
  return blueprint.scenes.map((scene, i) => {
38980
39442
  const start_s = scene.start_s ?? cursor;
@@ -38986,15 +39448,15 @@ function buildMotionBoard(blueprint) {
38986
39448
  const graphics = [
38987
39449
  ...(overlays.success ? overlays.data : []).filter((ov) => ov.text?.trim()).map((ov) => ({
38988
39450
  kind: "text",
38989
- at_s: round4(ov.appears_at_s ?? start_s),
38990
- dur_s: round4(ov.duration_s ?? 2.5),
39451
+ at_s: round5(ov.appears_at_s ?? start_s),
39452
+ dur_s: round5(ov.duration_s ?? 2.5),
38991
39453
  position: ov.position ?? "bottom_center",
38992
39454
  text: ov.text?.trim()
38993
39455
  })),
38994
39456
  ...(floats.success ? floats.data : []).map((fe) => ({
38995
39457
  kind: "graphic",
38996
- at_s: round4(fe.appears_at_s ?? start_s),
38997
- dur_s: round4(fe.duration_s ?? 2.5),
39458
+ at_s: round5(fe.appears_at_s ?? start_s),
39459
+ dur_s: round5(fe.duration_s ?? 2.5),
38998
39460
  position: fe.position ?? "bottom_center",
38999
39461
  label: fe.brand_name || fe.what_it_represents || fe.description || fe.kind || "element"
39000
39462
  }))
@@ -39002,7 +39464,7 @@ function buildMotionBoard(blueprint) {
39002
39464
  return {
39003
39465
  scene: i,
39004
39466
  role: resolveSceneRole(scene, i, blueprint.scenes.length),
39005
- window_s: [round4(start_s), round4(end_s)],
39467
+ window_s: [round5(start_s), round5(end_s)],
39006
39468
  // A continuation b-roll scene shares the previous scene's end frame as its start
39007
39469
  // (no own `s<i>_start` node), so point the storyboard at that shared keyframe.
39008
39470
  storyboard_frames: [scene.continues_previous && i > 0 ? `s${i - 1}_end` : `s${i}_start`],
@@ -40765,7 +41227,7 @@ ${describeRewrites(healed.rewrites)}
40765
41227
  // "edited since last render". Computed from the on-disk canvas.json +
40766
41228
  // prompt.json — the same helper the edit-sync uses, so the two are comparable.
40767
41229
  sourceSha: await computeSourceSha(filePath),
40768
- chatId: optionalChatId(),
41230
+ chatId: getEnv().BAKER_CHAT_ID || void 0,
40769
41231
  canvasSnapshotUrl
40770
41232
  };
40771
41233
  if (client) {
@@ -44756,7 +45218,11 @@ function detectCreativeContentType(filePath) {
44756
45218
  });
44757
45219
  }
44758
45220
  function chatIdFromEnv2() {
44759
- return optionalChatId();
45221
+ try {
45222
+ return getEnv().BAKER_CHAT_ID || void 0;
45223
+ } catch {
45224
+ return void 0;
45225
+ }
44760
45226
  }
44761
45227
  function parseOptionalUrl(value) {
44762
45228
  if (value === void 0 || value.trim() === "") {
@@ -52673,7 +53139,7 @@ var extractCommand = defineCommand149({
52673
53139
  import { defineCommand as defineCommand150 } from "citty";
52674
53140
 
52675
53141
  // src/commands/images/providerHits.ts
52676
- function asRecord2(value) {
53142
+ function asRecord3(value) {
52677
53143
  return value && typeof value === "object" ? value : {};
52678
53144
  }
52679
53145
  function str(value) {
@@ -52698,7 +53164,7 @@ function providerHitNormalizer(record, full) {
52698
53164
  if (!full) {
52699
53165
  return compact3;
52700
53166
  }
52701
- const group = asRecord2(record.group);
53167
+ const group = asRecord3(record.group);
52702
53168
  return {
52703
53169
  ...compact3,
52704
53170
  externalUrl: str(record.externalUrl),
@@ -56603,7 +57069,7 @@ function dedupe(findings) {
56603
57069
 
56604
57070
  // src/engine/landing/lib/critique.ts
56605
57071
  var FAMILIES = ["typography", "color", "borders_depth", "motion", "spacing", "copy", "integrity"];
56606
- function round2(n) {
57072
+ function round4(n) {
56607
57073
  return Math.round(n * 100) / 100;
56608
57074
  }
56609
57075
  function clamp012(n) {
@@ -56640,11 +57106,11 @@ function critiqueLanding(input) {
56640
57106
  const dimensions = FAMILIES.map((family) => {
56641
57107
  const fam = findings.filter((f) => f.family === family);
56642
57108
  const penalty = fam.reduce((s, f) => s + SEVERITY_WEIGHT[f.severity], 0);
56643
- const score = round2(clamp012(1 - penalty));
57109
+ const score = round4(clamp012(1 - penalty));
56644
57110
  const note = fam.length === 0 ? "clean" : `${fam.length} finding(s): ${describeCounts(fam)}`;
56645
57111
  return { dimension: family, score, note };
56646
57112
  });
56647
- const overall = round2(dimensions.reduce((s, d) => s + d.score, 0) / dimensions.length);
57113
+ const overall = round4(dimensions.reduce((s, d) => s + d.score, 0) / dimensions.length);
56648
57114
  const counts = {
56649
57115
  block: findings.filter((f) => f.severity === "block").length,
56650
57116
  warn: findings.filter((f) => f.severity === "warn").length,
@@ -60803,7 +61269,7 @@ function writeJsonl(data) {
60803
61269
  `);
60804
61270
  }
60805
61271
  }
60806
- function writeMd(data, fields) {
61272
+ function writeMd2(data, fields) {
60807
61273
  if (data.length === 0) return;
60808
61274
  const cols = fields ?? Object.keys(data[0] ?? {});
60809
61275
  process.stdout.write(`| ${cols.join(" | ")} |
@@ -60825,7 +61291,7 @@ function writeResearchOutput(data, format, fields) {
60825
61291
  writeJsonl(data);
60826
61292
  break;
60827
61293
  case "md":
60828
- writeMd(data, fields);
61294
+ writeMd2(data, fields);
60829
61295
  break;
60830
61296
  default:
60831
61297
  writeResearchJson({ ok: true, data });