@koda-sl/baker-cli 0.345.0-dev.9f4314fa9 → 0.345.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/dist/cli.js CHANGED
@@ -67,7 +67,7 @@ import {
67
67
  validateCanvasDeep,
68
68
  withoutCastName,
69
69
  ytDlpBlockSignal
70
- } from "./chunk-D5P4COPD.js";
70
+ } from "./chunk-FFOURYP5.js";
71
71
  import {
72
72
  csvOrJson,
73
73
  daysAgoIso,
@@ -31032,278 +31032,6 @@ function mergeStoredWithCounts(stored, reported) {
31032
31032
  }).sort((a, b) => a.name.localeCompare(b.name));
31033
31033
  }
31034
31034
 
31035
- // src/commands/analytics/render.ts
31036
- var SPARKLINE_POINTS = 30;
31037
- var DASHBOARD_ONLY_FIELDS = /* @__PURE__ */ new Set([
31038
- // The Convex row id. It exists so a dashboard can link to the row; an agent
31039
- // addresses a landing by `landingId`, which is the id in its `_definition.md`.
31040
- "landingRef"
31041
- ]);
31042
- function isAbsent(value) {
31043
- if (value === "") return true;
31044
- if (Array.isArray(value)) return value.length === 0;
31045
- if (typeof value === "object" && value !== null) return Object.keys(value).length === 0;
31046
- return false;
31047
- }
31048
- function resample(series, points) {
31049
- if (series.length <= points || points < 1) return [...series];
31050
- const out = [];
31051
- for (let i = 0; i < points; i += 1) {
31052
- const from = Math.floor(i * series.length / points);
31053
- const to = Math.floor((i + 1) * series.length / points);
31054
- let sum = 0;
31055
- for (let j = from; j < to; j += 1) sum += series[j] ?? 0;
31056
- out.push(sum);
31057
- }
31058
- return out;
31059
- }
31060
- function pruneValue(value, full) {
31061
- if (Array.isArray(value)) return value.map((entry) => pruneValue(entry, full));
31062
- if (typeof value === "object" && value !== null) {
31063
- return pruneRow(value, full);
31064
- }
31065
- return value;
31066
- }
31067
- function pruneRow(row, full) {
31068
- const out = {};
31069
- for (const [key, value] of Object.entries(row)) {
31070
- if (DASHBOARD_ONLY_FIELDS.has(key)) continue;
31071
- if (key === "sparkline" && Array.isArray(value)) {
31072
- if (!full) continue;
31073
- out[key] = resample(value, SPARKLINE_POINTS);
31074
- continue;
31075
- }
31076
- if (isAbsent(value)) continue;
31077
- out[key] = pruneValue(value, full);
31078
- }
31079
- return out;
31080
- }
31081
- function pruneForAgent(data, full) {
31082
- return pruneRow(data, full);
31083
- }
31084
- function isTabular(rows) {
31085
- return rows.every(
31086
- (row) => typeof row === "object" && row !== null && !Array.isArray(row) && Object.values(row).every(
31087
- (value) => value === null || typeof value !== "object" || Array.isArray(value) && value.every((e) => typeof e !== "object")
31088
- )
31089
- );
31090
- }
31091
- function cell2(value, key) {
31092
- if (value === null || value === void 0) return "";
31093
- if (Array.isArray(value)) return value.join(" ");
31094
- if (typeof value === "number" && !Number.isInteger(value)) {
31095
- if (key?.endsWith("Ms")) return String(Math.round(value));
31096
- return value.toFixed(4).replace(/0+$/, "").replace(/\.$/, "");
31097
- }
31098
- return String(value);
31099
- }
31100
- var IDENTITY_COLUMNS = [
31101
- "landingId",
31102
- "name",
31103
- "slug",
31104
- "path",
31105
- "flowSlug",
31106
- "stepId",
31107
- "value",
31108
- "key",
31109
- "bucket",
31110
- "tag",
31111
- "eventName",
31112
- "release",
31113
- "place",
31114
- "bot",
31115
- "source",
31116
- "medium",
31117
- "campaign",
31118
- "platform",
31119
- "sessionId",
31120
- "eventId"
31121
- ];
31122
- function byIdentityFirst(a, b) {
31123
- const ia = IDENTITY_COLUMNS.indexOf(a);
31124
- const ib = IDENTITY_COLUMNS.indexOf(b);
31125
- if (ia !== -1 || ib !== -1)
31126
- return (ia === -1 ? Number.MAX_SAFE_INTEGER : ia) - (ib === -1 ? Number.MAX_SAFE_INTEGER : ib);
31127
- return 0;
31128
- }
31129
- var BLOCK_ORDER = ["window", "totals", "previous", "pageInfo"];
31130
- function byBlockOrder(a, b) {
31131
- const rank = (key) => {
31132
- const at = BLOCK_ORDER.indexOf(key);
31133
- if (at !== -1) return at;
31134
- return key === "preset" ? BLOCK_ORDER.length + 1 : BLOCK_ORDER.length;
31135
- };
31136
- return rank(a) - rank(b);
31137
- }
31138
- function columnsOf(rows) {
31139
- const seen = [];
31140
- for (const row of rows) {
31141
- for (const key of Object.keys(row)) {
31142
- if (!seen.includes(key)) seen.push(key);
31143
- }
31144
- }
31145
- return seen.filter((key) => rows.some((row) => !isAbsent(row[key]) && row[key] !== null && row[key] !== void 0)).sort(byIdentityFirst);
31146
- }
31147
- function table2(rows) {
31148
- const cols = columnsOf(rows);
31149
- if (cols.length === 0) return "";
31150
- const head = `| ${cols.join(" | ")} |`;
31151
- const rule = `| ${cols.map(() => "---").join(" | ")} |`;
31152
- const body = rows.map((row) => `| ${cols.map((col) => cell2(row[col], col)).join(" | ")} |`);
31153
- return [head, rule, ...body].join("\n");
31154
- }
31155
- function isRowList(value) {
31156
- return Array.isArray(value) && value.length > 0 && value.every((entry) => typeof entry === "object" && entry !== null && !Array.isArray(entry));
31157
- }
31158
- function labelOf(row, index) {
31159
- for (const key of IDENTITY_COLUMNS) {
31160
- const value = row[key];
31161
- if (typeof value === "string" && value !== "") return value;
31162
- }
31163
- return `#${index + 1}`;
31164
- }
31165
- function nestedBlock(name, rows) {
31166
- const parents = rows.map(
31167
- (row) => Object.fromEntries(Object.entries(row).filter(([, value]) => !isRowList(value) && !isPlainRow(value)))
31168
- );
31169
- const parts = [`### ${name}`, table2(parents)];
31170
- rows.forEach((row, index) => {
31171
- for (const [key, value] of Object.entries(row)) {
31172
- if (isRowList(value)) parts.push(`#### ${name}[${labelOf(row, index)}].${key}`, table2(value));
31173
- else if (isPlainRow(value)) parts.push(`#### ${name}[${labelOf(row, index)}].${key}`, table2([value]));
31174
- }
31175
- });
31176
- return parts.filter((part) => part !== "").join("\n");
31177
- }
31178
- function isPlainRow(value) {
31179
- return typeof value === "object" && value !== null && !Array.isArray(value);
31180
- }
31181
- function block(name, value) {
31182
- if (Array.isArray(value)) {
31183
- if (value.length === 0) return "";
31184
- if (isTabular(value)) return `### ${name}
31185
- ${table2(value)}`;
31186
- if (isRowList(value)) return nestedBlock(name, value);
31187
- return `### ${name}
31188
- ${JSON.stringify(value)}`;
31189
- }
31190
- if (typeof value === "object" && value !== null) {
31191
- const entries = Object.entries(value);
31192
- if (entries.length === 0) return "";
31193
- if (entries.every(([, v]) => v === null || typeof v !== "object")) {
31194
- return `### ${name}
31195
- ${entries.map(([k, v]) => `- ${k}: ${v === null ? "null" : cell2(v, k)}`).join("\n")}`;
31196
- }
31197
- return `### ${name}
31198
- ${JSON.stringify(value)}`;
31199
- }
31200
- return `### ${name}
31201
- ${cell2(value)}`;
31202
- }
31203
- function renderMarkdown3(envelope) {
31204
- const parts = [];
31205
- for (const warning of envelope.warnings ?? []) parts.push(`> **${warning.code}** \u2014 ${warning.message}`);
31206
- for (const hint of envelope.hints ?? []) parts.push(`> ${hint}`);
31207
- for (const [name, value] of Object.entries(envelope.data).sort(([a], [b]) => byBlockOrder(a, b))) {
31208
- const rendered = block(name, value);
31209
- if (rendered !== "") parts.push(rendered);
31210
- }
31211
- return `${parts.join("\n\n")}
31212
- `;
31213
- }
31214
- function missingBreakdownHint(data, asked) {
31215
- if (asked.eventName === void 0) return [];
31216
- const breakdown = data.eventBreakdown;
31217
- if (Array.isArray(breakdown) && breakdown.length > 0) return [];
31218
- const known = Array.isArray(data.customEvents) ? data.customEvents.flatMap((row) => isPlainRow(row) && typeof row.eventName === "string" ? [row.eventName] : []) : [];
31219
- return [
31220
- `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" : ""}` : ""}.`
31221
- ];
31222
- }
31223
- var ANALYTICS_OUTPUT_FORMATS = ["json", "md"];
31224
- function isAnalyticsOutputFormat(value) {
31225
- return ANALYTICS_OUTPUT_FORMATS.includes(value);
31226
- }
31227
- function writeAnalyticsReport(envelope, format) {
31228
- if (format === "md") {
31229
- process.stdout.write(renderMarkdown3(envelope));
31230
- return;
31231
- }
31232
- process.stdout.write(`${JSON.stringify(envelope)}
31233
- `);
31234
- }
31235
- var ROWS_BEFORE_FORMAT_HINT = 25;
31236
- function rowCount(data) {
31237
- let total = 0;
31238
- for (const value of Object.values(data)) {
31239
- if (Array.isArray(value)) total += value.length;
31240
- }
31241
- return total;
31242
- }
31243
- function formatHint(data, format) {
31244
- if (format === "md") return [];
31245
- const rows = rowCount(data);
31246
- if (rows < ROWS_BEFORE_FORMAT_HINT) return [];
31247
- return [
31248
- `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.`
31249
- ];
31250
- }
31251
-
31252
- // src/commands/analytics/conversionsMarkdown.ts
31253
- function doorsCell(doors) {
31254
- return doors.map((door) => `${door.door}=${door.events}/${door.sessions}`).join(" ");
31255
- }
31256
- function eventKeysCell(eventKeys) {
31257
- const formKeys = eventKeys.filter((key) => key.startsWith("form:")).length;
31258
- const others = eventKeys.filter((key) => !key.startsWith("form:"));
31259
- return [...others, ...formKeys > 0 ? [`${formKeys} Form ending(s)`] : []].join(" + ");
31260
- }
31261
- function trafficByForm(candidates) {
31262
- const byForm = /* @__PURE__ */ new Map();
31263
- for (const row of candidates) {
31264
- const form = byForm.get(row.flowSlug) ?? { "endings seen": 0, "endings counted": 0, events: 0, lastSeen: "" };
31265
- form["endings seen"] += 1;
31266
- if (row.isCounted) form["endings counted"] += 1;
31267
- form.events += row.events;
31268
- if (row.lastSeen && row.lastSeen.slice(0, 10) > form.lastSeen) form.lastSeen = row.lastSeen.slice(0, 10);
31269
- byForm.set(row.flowSlug, form);
31270
- }
31271
- return byForm;
31272
- }
31273
- var NO_TRAFFIC = { "endings seen": 0, "endings counted": 0, events: 0, lastSeen: "" };
31274
- 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.";
31275
- function renderConversionsMarkdown(envelope) {
31276
- const { definitions, flow, flows, candidates } = envelope.data;
31277
- const data = {
31278
- definitions: definitions.map(({ name, eventKeys, ...row }) => ({ name, eventKeys: eventKeysCell(eventKeys), ...row }))
31279
- };
31280
- if (flow) {
31281
- data.flow = { slug: flow.slug, noConversionReason: flow.noConversionReason };
31282
- data.flowEndings = flow.endings;
31283
- }
31284
- const traffic = candidates ? trafficByForm(candidates.filter((row) => row.flowSlug !== "")) : /* @__PURE__ */ new Map();
31285
- if (flows) {
31286
- data.flows = flows.map((row) => ({
31287
- slug: row.slug,
31288
- counted: row.counted.map((entry) => `${entry.name} @ ${entry.step}`).join("; "),
31289
- noConversion: row.noConversion,
31290
- ...candidates ? traffic.get(row.slug) ?? NO_TRAFFIC : {}
31291
- }));
31292
- }
31293
- const hints2 = [...envelope.hints ?? []];
31294
- if (candidates) {
31295
- const listed2 = new Set(flows?.map((row) => row.slug));
31296
- const unlisted = [...traffic].filter(([slug]) => !listed2.has(slug));
31297
- if (unlisted.length > 0) data.formCandidates = unlisted.map(([form, row]) => ({ form, ...row }));
31298
- data.candidates = candidates.filter((row) => row.flowSlug === "").map(({ doors, flowSlug: _flowSlug, nodeType: _nodeType, ...row }) => ({
31299
- ...row,
31300
- "doors (events/sessions)": doorsCell(doors)
31301
- }));
31302
- if (traffic.size > 0) hints2.push(FORM_KEYS_HINT);
31303
- }
31304
- return renderMarkdown3({ data, ...hints2.length > 0 ? { hints: hints2 } : {} });
31305
- }
31306
-
31307
31035
  // src/commands/analytics/errorEnvelope.ts
31308
31036
  function analyticsErrorEnvelope(err) {
31309
31037
  if (err instanceof ApiError) {
@@ -31795,6 +31523,223 @@ var ANALYTICS_PRESET_INFO = [
31795
31523
  }
31796
31524
  ];
31797
31525
 
31526
+ // src/commands/analytics/render.ts
31527
+ var SPARKLINE_POINTS = 30;
31528
+ var DASHBOARD_ONLY_FIELDS = /* @__PURE__ */ new Set([
31529
+ // The Convex row id. It exists so a dashboard can link to the row; an agent
31530
+ // addresses a landing by `landingId`, which is the id in its `_definition.md`.
31531
+ "landingRef"
31532
+ ]);
31533
+ function isAbsent(value) {
31534
+ if (value === "") return true;
31535
+ if (Array.isArray(value)) return value.length === 0;
31536
+ if (typeof value === "object" && value !== null) return Object.keys(value).length === 0;
31537
+ return false;
31538
+ }
31539
+ function resample(series, points) {
31540
+ if (series.length <= points || points < 1) return [...series];
31541
+ const out = [];
31542
+ for (let i = 0; i < points; i += 1) {
31543
+ const from = Math.floor(i * series.length / points);
31544
+ const to = Math.floor((i + 1) * series.length / points);
31545
+ let sum = 0;
31546
+ for (let j = from; j < to; j += 1) sum += series[j] ?? 0;
31547
+ out.push(sum);
31548
+ }
31549
+ return out;
31550
+ }
31551
+ function pruneValue(value, full) {
31552
+ if (Array.isArray(value)) return value.map((entry) => pruneValue(entry, full));
31553
+ if (typeof value === "object" && value !== null) {
31554
+ return pruneRow(value, full);
31555
+ }
31556
+ return value;
31557
+ }
31558
+ function pruneRow(row, full) {
31559
+ const out = {};
31560
+ for (const [key, value] of Object.entries(row)) {
31561
+ if (DASHBOARD_ONLY_FIELDS.has(key)) continue;
31562
+ if (key === "sparkline" && Array.isArray(value)) {
31563
+ if (!full) continue;
31564
+ out[key] = resample(value, SPARKLINE_POINTS);
31565
+ continue;
31566
+ }
31567
+ if (isAbsent(value)) continue;
31568
+ out[key] = pruneValue(value, full);
31569
+ }
31570
+ return out;
31571
+ }
31572
+ function pruneForAgent(data, full) {
31573
+ return pruneRow(data, full);
31574
+ }
31575
+ function isTabular(rows) {
31576
+ return rows.every(
31577
+ (row) => typeof row === "object" && row !== null && !Array.isArray(row) && Object.values(row).every(
31578
+ (value) => value === null || typeof value !== "object" || Array.isArray(value) && value.every((e) => typeof e !== "object")
31579
+ )
31580
+ );
31581
+ }
31582
+ function cell2(value, key) {
31583
+ if (value === null || value === void 0) return "";
31584
+ if (Array.isArray(value)) return value.join(" ");
31585
+ if (typeof value === "number" && !Number.isInteger(value)) {
31586
+ if (key?.endsWith("Ms")) return String(Math.round(value));
31587
+ return value.toFixed(4).replace(/0+$/, "").replace(/\.$/, "");
31588
+ }
31589
+ return String(value);
31590
+ }
31591
+ var IDENTITY_COLUMNS = [
31592
+ "landingId",
31593
+ "name",
31594
+ "slug",
31595
+ "path",
31596
+ "flowSlug",
31597
+ "stepId",
31598
+ "value",
31599
+ "key",
31600
+ "bucket",
31601
+ "tag",
31602
+ "eventName",
31603
+ "release",
31604
+ "place",
31605
+ "bot",
31606
+ "source",
31607
+ "medium",
31608
+ "campaign",
31609
+ "platform",
31610
+ "sessionId",
31611
+ "eventId"
31612
+ ];
31613
+ function byIdentityFirst(a, b) {
31614
+ const ia = IDENTITY_COLUMNS.indexOf(a);
31615
+ const ib = IDENTITY_COLUMNS.indexOf(b);
31616
+ if (ia !== -1 || ib !== -1)
31617
+ return (ia === -1 ? Number.MAX_SAFE_INTEGER : ia) - (ib === -1 ? Number.MAX_SAFE_INTEGER : ib);
31618
+ return 0;
31619
+ }
31620
+ var BLOCK_ORDER = ["window", "totals", "previous", "pageInfo"];
31621
+ function byBlockOrder(a, b) {
31622
+ const rank = (key) => {
31623
+ const at = BLOCK_ORDER.indexOf(key);
31624
+ if (at !== -1) return at;
31625
+ return key === "preset" ? BLOCK_ORDER.length + 1 : BLOCK_ORDER.length;
31626
+ };
31627
+ return rank(a) - rank(b);
31628
+ }
31629
+ function columnsOf(rows) {
31630
+ const seen = [];
31631
+ for (const row of rows) {
31632
+ for (const key of Object.keys(row)) {
31633
+ if (!seen.includes(key)) seen.push(key);
31634
+ }
31635
+ }
31636
+ return seen.filter((key) => rows.some((row) => !isAbsent(row[key]) && row[key] !== null && row[key] !== void 0)).sort(byIdentityFirst);
31637
+ }
31638
+ function table2(rows) {
31639
+ const cols = columnsOf(rows);
31640
+ if (cols.length === 0) return "";
31641
+ const head = `| ${cols.join(" | ")} |`;
31642
+ const rule = `| ${cols.map(() => "---").join(" | ")} |`;
31643
+ const body = rows.map((row) => `| ${cols.map((col) => cell2(row[col], col)).join(" | ")} |`);
31644
+ return [head, rule, ...body].join("\n");
31645
+ }
31646
+ function isRowList(value) {
31647
+ return Array.isArray(value) && value.length > 0 && value.every((entry) => typeof entry === "object" && entry !== null && !Array.isArray(entry));
31648
+ }
31649
+ function labelOf(row, index) {
31650
+ for (const key of IDENTITY_COLUMNS) {
31651
+ const value = row[key];
31652
+ if (typeof value === "string" && value !== "") return value;
31653
+ }
31654
+ return `#${index + 1}`;
31655
+ }
31656
+ function nestedBlock(name, rows) {
31657
+ const parents = rows.map(
31658
+ (row) => Object.fromEntries(Object.entries(row).filter(([, value]) => !isRowList(value) && !isPlainRow(value)))
31659
+ );
31660
+ const parts = [`### ${name}`, table2(parents)];
31661
+ rows.forEach((row, index) => {
31662
+ for (const [key, value] of Object.entries(row)) {
31663
+ if (isRowList(value)) parts.push(`#### ${name}[${labelOf(row, index)}].${key}`, table2(value));
31664
+ else if (isPlainRow(value)) parts.push(`#### ${name}[${labelOf(row, index)}].${key}`, table2([value]));
31665
+ }
31666
+ });
31667
+ return parts.filter((part) => part !== "").join("\n");
31668
+ }
31669
+ function isPlainRow(value) {
31670
+ return typeof value === "object" && value !== null && !Array.isArray(value);
31671
+ }
31672
+ function block(name, value) {
31673
+ if (Array.isArray(value)) {
31674
+ if (value.length === 0) return "";
31675
+ if (isTabular(value)) return `### ${name}
31676
+ ${table2(value)}`;
31677
+ if (isRowList(value)) return nestedBlock(name, value);
31678
+ return `### ${name}
31679
+ ${JSON.stringify(value)}`;
31680
+ }
31681
+ if (typeof value === "object" && value !== null) {
31682
+ const entries = Object.entries(value);
31683
+ if (entries.length === 0) return "";
31684
+ if (entries.every(([, v]) => v === null || typeof v !== "object")) {
31685
+ return `### ${name}
31686
+ ${entries.map(([k, v]) => `- ${k}: ${v === null ? "null" : cell2(v, k)}`).join("\n")}`;
31687
+ }
31688
+ return `### ${name}
31689
+ ${JSON.stringify(value)}`;
31690
+ }
31691
+ return `### ${name}
31692
+ ${cell2(value)}`;
31693
+ }
31694
+ function renderMarkdown3(envelope) {
31695
+ const parts = [];
31696
+ for (const warning of envelope.warnings ?? []) parts.push(`> **${warning.code}** \u2014 ${warning.message}`);
31697
+ for (const hint of envelope.hints ?? []) parts.push(`> ${hint}`);
31698
+ for (const [name, value] of Object.entries(envelope.data).sort(([a], [b]) => byBlockOrder(a, b))) {
31699
+ const rendered = block(name, value);
31700
+ if (rendered !== "") parts.push(rendered);
31701
+ }
31702
+ return `${parts.join("\n\n")}
31703
+ `;
31704
+ }
31705
+ function missingBreakdownHint(data, asked) {
31706
+ if (asked.eventName === void 0) return [];
31707
+ const breakdown = data.eventBreakdown;
31708
+ if (Array.isArray(breakdown) && breakdown.length > 0) return [];
31709
+ const known = Array.isArray(data.customEvents) ? data.customEvents.flatMap((row) => isPlainRow(row) && typeof row.eventName === "string" ? [row.eventName] : []) : [];
31710
+ return [
31711
+ `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" : ""}` : ""}.`
31712
+ ];
31713
+ }
31714
+ var ANALYTICS_OUTPUT_FORMATS = ["json", "md"];
31715
+ function isAnalyticsOutputFormat(value) {
31716
+ return ANALYTICS_OUTPUT_FORMATS.includes(value);
31717
+ }
31718
+ function writeAnalyticsReport(envelope, format) {
31719
+ if (format === "md") {
31720
+ process.stdout.write(renderMarkdown3(envelope));
31721
+ return;
31722
+ }
31723
+ process.stdout.write(`${JSON.stringify(envelope)}
31724
+ `);
31725
+ }
31726
+ var ROWS_BEFORE_FORMAT_HINT = 25;
31727
+ function rowCount(data) {
31728
+ let total = 0;
31729
+ for (const value of Object.values(data)) {
31730
+ if (Array.isArray(value)) total += value.length;
31731
+ }
31732
+ return total;
31733
+ }
31734
+ function formatHint(data, format) {
31735
+ if (format === "md") return [];
31736
+ const rows = rowCount(data);
31737
+ if (rows < ROWS_BEFORE_FORMAT_HINT) return [];
31738
+ return [
31739
+ `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.`
31740
+ ];
31741
+ }
31742
+
31798
31743
  // src/commands/analytics/sends.ts
31799
31744
  import { defineCommand as defineCommand97 } from "citty";
31800
31745
  var SET_FLAGS = ["--source-event", "--platform", "--tag", "--event"];
@@ -32969,7 +32914,17 @@ async function runPreset(args5, options) {
32969
32914
  const response = await apiPost("/api/analytics/query", requestBody(args5, options));
32970
32915
  const requestedPlatform = args5.platform === void 0 ? "" : String(args5.platform);
32971
32916
  const adPlatformScope = isAdPlatform(requestedPlatform) ? requestedPlatform : void 0;
32972
- const format = outputFormatOrExit(args5.output);
32917
+ const format = args5.output === void 0 ? "json" : String(args5.output);
32918
+ if (!isAnalyticsOutputFormat(format)) {
32919
+ writeJsonEnvelope({
32920
+ ok: false,
32921
+ error: {
32922
+ code: "VALIDATION_ERROR",
32923
+ message: `Unknown --output "${format}". Use one of: ${ANALYTICS_OUTPUT_FORMATS.join(", ")}.`
32924
+ }
32925
+ });
32926
+ process.exit(1);
32927
+ }
32973
32928
  const data = pruneForAgent(response.data, args5.full === true);
32974
32929
  const feed = "stream" in data ? shapeFeed(data.stream, args5.everything === true) : void 0;
32975
32930
  if (feed !== void 0) data.stream = feed.rows;
@@ -32999,20 +32954,6 @@ async function runPreset(args5, options) {
32999
32954
  handleError3(err);
33000
32955
  }
33001
32956
  }
33002
- function outputFormatOrExit(raw) {
33003
- const format = raw === void 0 ? "json" : String(raw);
33004
- if (!isAnalyticsOutputFormat(format)) {
33005
- writeJsonEnvelope({
33006
- ok: false,
33007
- error: {
33008
- code: "VALIDATION_ERROR",
33009
- message: `Unknown --output "${format}". Use one of: ${ANALYTICS_OUTPUT_FORMATS.join(", ")}.`
33010
- }
33011
- });
33012
- process.exit(1);
33013
- }
33014
- return format;
33015
- }
33016
32957
  function presetCommand(options) {
33017
32958
  registerSchema({
33018
32959
  command: `analytics.${options.name}`,
@@ -33514,8 +33455,7 @@ var conversionsCommand3 = (() => {
33514
33455
  type: "string",
33515
33456
  description: "Lookback for the counts and for --candidates. Default 30",
33516
33457
  required: false
33517
- },
33518
- output: SHARED_ARGS.output
33458
+ }
33519
33459
  };
33520
33460
  registerSchema({
33521
33461
  command: "analytics.conversions",
@@ -33530,7 +33470,6 @@ var conversionsCommand3 = (() => {
33530
33470
  args: args5,
33531
33471
  run: async ({ args: raw }) => {
33532
33472
  try {
33533
- const format = outputFormatOrExit(raw.output);
33534
33473
  const args6 = parseConversionsArgs(raw, process.argv);
33535
33474
  for (const eventKey of args6.eventKeys) refuseUnmatchableKey(eventKey);
33536
33475
  const before = await apiPost("/api/analytics/conversions", {});
@@ -33540,13 +33479,13 @@ var conversionsCommand3 = (() => {
33540
33479
  preset: "conversions",
33541
33480
  days: args6.days
33542
33481
  });
33543
- const envelope = conversionsEnvelope(
33544
- args6,
33545
- mergeStoredWithCounts(stored, report.data.conversions ?? []),
33546
- report.data.eventCatalog ?? []
33482
+ writeJsonEnvelope(
33483
+ conversionsEnvelope(
33484
+ args6,
33485
+ mergeStoredWithCounts(stored, report.data.conversions ?? []),
33486
+ report.data.eventCatalog ?? []
33487
+ )
33547
33488
  );
33548
- if (format === "md") process.stdout.write(renderConversionsMarkdown(envelope));
33549
- else writeJsonEnvelope(envelope);
33550
33489
  } catch (err) {
33551
33490
  if (err instanceof ConversionArgsError) {
33552
33491
  handleError3(new ApiError("VALIDATION_ERROR", err.message));
@@ -67754,6 +67693,7 @@ function commandFor(root, argv) {
67754
67693
  const { command, resolved } = resolveCommand2(root, argv);
67755
67694
  return resolved ? command : null;
67756
67695
  }
67696
+ var OUTPUT_EXPLANATION = "This command has no --output option: `--output json` is accepted by every command that prints the JSON envelope, and md or files only where `baker schema` lists `output`. Drop the option and read the default output. ";
67757
67697
  function unknownFlagEnvelope(unknown, commandPath, suggestion, hasSchema) {
67758
67698
  const list = unknown.join(", ");
67759
67699
  return {
@@ -67763,7 +67703,7 @@ function unknownFlagEnvelope(unknown, commandPath, suggestion, hasSchema) {
67763
67703
  message: `${list} ${unknown.length > 1 ? "are not options" : "is not an option"} of \`baker ${commandPath}\`.`,
67764
67704
  fix: {
67765
67705
  action: hasSchema ? "check_schema" : "check_help",
67766
- explanation: (suggestion ? `Did you mean ${suggestion}? ` : "") + `Run \`${hasSchema ? `baker schema ${commandPath}` : `baker ${commandPath} --help`}\` to see every option this command takes. Do not re-run the same call: until this version an unrecognised option was accepted and ignored, so a command that looked like it had filtered or narrowed the result was in fact answering the unfiltered question.`
67706
+ explanation: (unknown.some((flag) => flag === "--output" || flag.startsWith("--output=")) ? OUTPUT_EXPLANATION : "") + (suggestion ? `Did you mean ${suggestion}? ` : "") + `Run \`${hasSchema ? `baker schema ${commandPath}` : `baker ${commandPath} --help`}\` to see every option this command takes. Do not re-run the same call: until this version an unrecognised option was accepted and ignored, so a command that looked like it had filtered or narrowed the result was in fact answering the unfiltered question.`
67767
67707
  },
67768
67708
  retryable: false
67769
67709
  }
@@ -67802,6 +67742,58 @@ function refuseUnknownFlags(root, argv) {
67802
67742
  process.exit(1);
67803
67743
  }
67804
67744
 
67745
+ // src/output-flag.ts
67746
+ var FLAG = "--output";
67747
+ var ENVELOPE = "json";
67748
+ var PRINTS_NO_ENVELOPE = /* @__PURE__ */ new Set([
67749
+ "analytics sending-events",
67750
+ "canvas run",
67751
+ "canvas rerun",
67752
+ "canvas sync-definition"
67753
+ ]);
67754
+ function declaredArg(command, name) {
67755
+ const args5 = command.args;
67756
+ if (!args5 || typeof args5 !== "object" || !(name in args5)) {
67757
+ return null;
67758
+ }
67759
+ const def = args5[name];
67760
+ return def && typeof def === "object" ? def : {};
67761
+ }
67762
+ function envelopeRequests(argv) {
67763
+ const end = argv.indexOf("--");
67764
+ const limit = end === -1 ? argv.length : end;
67765
+ const found = [];
67766
+ for (let index = 0; index < limit; index++) {
67767
+ const token = argv[index];
67768
+ if (token === `${FLAG}=${ENVELOPE}`) {
67769
+ found.push({ index, length: 1 });
67770
+ } else if (token === FLAG && argv[index + 1] === ENVELOPE && index + 1 < limit) {
67771
+ found.push({ index, length: 2 });
67772
+ index++;
67773
+ }
67774
+ }
67775
+ return found;
67776
+ }
67777
+ function outputFlagForCommand(root, argv) {
67778
+ const requests = envelopeRequests(argv);
67779
+ if (requests.length === 0) {
67780
+ return argv;
67781
+ }
67782
+ const command = commandFor(root, argv);
67783
+ if (!command || declaredArg(command, "output") || PRINTS_NO_ENVELOPE.has(commandPathOf(root, argv))) {
67784
+ return argv;
67785
+ }
67786
+ const jsonSwitch = declaredArg(command, "json")?.type === "boolean";
67787
+ const dropped = new Set(requests.flatMap(({ index, length }) => length === 2 ? [index, index + 1] : [index]));
67788
+ const first = requests[0]?.index;
67789
+ return argv.flatMap((token, index) => {
67790
+ if (!dropped.has(index)) {
67791
+ return [token];
67792
+ }
67793
+ return jsonSwitch && index === first ? ["--json"] : [];
67794
+ });
67795
+ }
67796
+
67805
67797
  // src/version.ts
67806
67798
  import { readFileSync as readFileSync21 } from "fs";
67807
67799
  function packageJsonUrl() {
@@ -67828,7 +67820,7 @@ var main = defineCommand245({
67828
67820
  Auth: Set BAKER_API_KEY (starts with bk_) and BAKER_API_URL environment variables.
67829
67821
  Chat: Set BAKER_CHAT_ID for action and scheduled-action commands that stage changes against a chat.
67830
67822
  Output: All commands return JSON envelopes: { ok: true, data: ... } or { ok: false, error: { code, message } }.
67831
- Formats: Use --output json|files|md to control output format. Default: json. (The research commands additionally accept csv and jsonl.)
67823
+ Formats: --output json works on every command that prints the envelope. --output md|files only where 'baker schema <command>' lists output. (The research commands additionally accept csv and jsonl.)
67832
67824
  Introspection: Run 'baker schema <command>' to inspect argument schemas.`
67833
67825
  },
67834
67826
  subCommands: {
@@ -67866,6 +67858,7 @@ process.argv = [...process.argv.slice(0, 2), ...normalizeCacheFlag(process.argv.
67866
67858
  installStreamTaps();
67867
67859
  logInvocation(process.argv.slice(2));
67868
67860
  installExitRecord();
67861
+ process.argv = [...process.argv.slice(0, 2), ...outputFlagForCommand(main, process.argv.slice(2))];
67869
67862
  refuseUnknownFlags(main, process.argv.slice(2));
67870
67863
  process.argv = [...process.argv.slice(0, 2), ...cacheFlagForParser(process.argv.slice(2))];
67871
67864
  runMain(main);