@ainyc/canonry 4.64.1 → 4.67.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
@@ -27,7 +27,7 @@ import {
27
27
  setTelemetrySource,
28
28
  showFirstRunNotice,
29
29
  trackEvent
30
- } from "./chunk-MDNDIBUM.js";
30
+ } from "./chunk-4V3V4MFF.js";
31
31
  import {
32
32
  CliError,
33
33
  EXIT_SYSTEM_ERROR,
@@ -37,13 +37,14 @@ import {
37
37
  getConfigDir,
38
38
  getConfigPath,
39
39
  isEndpointMissing,
40
+ isMachineFormat,
40
41
  loadConfig,
41
42
  loadConfigRaw,
42
43
  printCliError,
43
44
  saveConfig,
44
45
  saveConfigPatch,
45
46
  usageError
46
- } from "./chunk-64IDABSF.js";
47
+ } from "./chunk-RQCVITY4.js";
47
48
  import {
48
49
  apiKeys,
49
50
  createClient,
@@ -126,7 +127,9 @@ function withGlobalOptions(options) {
126
127
  return base;
127
128
  }
128
129
  function toFormat(value, fallbackFormat) {
129
- return value === "json" ? "json" : fallbackFormat;
130
+ if (value === "json") return "json";
131
+ if (value === "jsonl") return "jsonl";
132
+ return fallbackFormat;
130
133
  }
131
134
  function printGroupHelp(group, specs) {
132
135
  const parentSpec = specs.find((s) => s.path.length === 1 && s.path[0] === group);
@@ -423,6 +426,16 @@ var BACKFILL_CLI_COMMANDS = [
423
426
  }
424
427
  ];
425
428
 
429
+ // src/cli-output.ts
430
+ function emitJsonl(records) {
431
+ let out = "";
432
+ for (const record of records) {
433
+ out += `${JSON.stringify(record)}
434
+ `;
435
+ }
436
+ if (out) process.stdout.write(out);
437
+ }
438
+
426
439
  // src/commands/backlinks.ts
427
440
  function getClient() {
428
441
  return createApiClient();
@@ -530,7 +543,7 @@ async function pollRun(runId, format) {
530
543
  }
531
544
  async function backlinksInstall(opts = {}) {
532
545
  const result = await getClient().backlinksInstall();
533
- if (opts.format === "json") {
546
+ if (isMachineFormat(opts.format)) {
534
547
  printJson(result);
535
548
  return;
536
549
  }
@@ -538,7 +551,7 @@ async function backlinksInstall(opts = {}) {
538
551
  }
539
552
  async function backlinksDoctor(opts = {}) {
540
553
  const status = await getClient().backlinksStatus();
541
- if (opts.format === "json") {
554
+ if (isMachineFormat(opts.format)) {
542
555
  printJson(status);
543
556
  return;
544
557
  }
@@ -548,7 +561,7 @@ async function backlinksSync(opts) {
548
561
  const client = getClient();
549
562
  const sync = await client.backlinksTriggerSync(opts.release);
550
563
  const final = opts.wait ? await pollSync(sync.id, opts.format) : sync;
551
- if (opts.format === "json") {
564
+ if (isMachineFormat(opts.format)) {
552
565
  printJson(final);
553
566
  return;
554
567
  }
@@ -579,7 +592,7 @@ function formatLatestRelease(result) {
579
592
  }
580
593
  async function backlinksLatestRelease(opts = {}) {
581
594
  const result = await getClient().backlinksLatestRelease();
582
- if (opts.format === "json") {
595
+ if (isMachineFormat(opts.format)) {
583
596
  printJson(result);
584
597
  return;
585
598
  }
@@ -587,7 +600,7 @@ async function backlinksLatestRelease(opts = {}) {
587
600
  }
588
601
  async function backlinksStatus(opts = {}) {
589
602
  const sync = await getClient().backlinksLatestSync();
590
- if (opts.format === "json") {
603
+ if (isMachineFormat(opts.format)) {
591
604
  printJson(sync);
592
605
  return;
593
606
  }
@@ -607,6 +620,11 @@ async function backlinksList(opts) {
607
620
  if (opts.format === "json") {
608
621
  printJson(response);
609
622
  return;
623
+ } else if (opts.format === "jsonl") {
624
+ const release = response.summary?.release ?? null;
625
+ const targetDomain = response.summary?.targetDomain ?? null;
626
+ emitJsonl(response.rows.map((row) => ({ project: opts.project, release, targetDomain, ...row })));
627
+ return;
610
628
  }
611
629
  console.log(formatSummaryAndDomains(opts.project, response));
612
630
  }
@@ -615,6 +633,9 @@ async function backlinksReleases(opts = {}) {
615
633
  if (opts.format === "json") {
616
634
  printJson(rows);
617
635
  return;
636
+ } else if (opts.format === "jsonl") {
637
+ emitJsonl(rows);
638
+ return;
618
639
  }
619
640
  console.log(formatCachedReleases(rows));
620
641
  }
@@ -622,7 +643,7 @@ async function backlinksExtract(opts) {
622
643
  const client = getClient();
623
644
  const run = await client.backlinksExtract(opts.project, opts.release);
624
645
  const final = opts.wait ? await pollRun(run.id, opts.format) : run;
625
- if (opts.format === "json") {
646
+ if (isMachineFormat(opts.format)) {
626
647
  printJson(final);
627
648
  return;
628
649
  }
@@ -634,7 +655,7 @@ async function backlinksCachePrune(opts) {
634
655
  throw new Error("Usage: canonry backlinks cache prune --release <id>");
635
656
  }
636
657
  const result = await getClient().backlinksPruneCache(opts.release);
637
- if (opts.format === "json") {
658
+ if (isMachineFormat(opts.format)) {
638
659
  printJson({ pruned: opts.release, ...result });
639
660
  return;
640
661
  }
@@ -814,7 +835,7 @@ async function bingConnect(project, opts) {
814
835
  }
815
836
  const client = getClient2();
816
837
  const result = await client.bingConnect(project, { apiKey });
817
- if (opts?.format === "json") {
838
+ if (isMachineFormat(opts?.format)) {
818
839
  console.log(JSON.stringify(result, null, 2));
819
840
  return;
820
841
  }
@@ -835,7 +856,7 @@ Set the active site with: canonry bing set-site ${project} <url>`);
835
856
  async function bingDisconnect(project, format) {
836
857
  const client = getClient2();
837
858
  await client.bingDisconnect(project);
838
- if (format === "json") {
859
+ if (isMachineFormat(format)) {
839
860
  console.log(JSON.stringify({ project, disconnected: true }, null, 2));
840
861
  return;
841
862
  }
@@ -844,7 +865,7 @@ async function bingDisconnect(project, format) {
844
865
  async function bingStatus(project, format) {
845
866
  const client = getClient2();
846
867
  const result = await client.bingStatus(project);
847
- if (format === "json") {
868
+ if (isMachineFormat(format)) {
848
869
  console.log(JSON.stringify(result, null, 2));
849
870
  return;
850
871
  }
@@ -865,6 +886,9 @@ async function bingSites(project, format) {
865
886
  if (format === "json") {
866
887
  console.log(JSON.stringify(result, null, 2));
867
888
  return;
889
+ } else if (format === "jsonl") {
890
+ emitJsonl(result.sites.map((site) => ({ project, ...site })));
891
+ return;
868
892
  }
869
893
  if (result.sites.length === 0) {
870
894
  console.log("No sites registered in Bing Webmaster Tools.");
@@ -884,7 +908,7 @@ Use "canonry bing set-site <project> <url>" to select a site.`);
884
908
  async function bingSetSite(project, siteUrl, format) {
885
909
  const client = getClient2();
886
910
  await client.bingSetSite(project, siteUrl);
887
- if (format === "json") {
911
+ if (isMachineFormat(format)) {
888
912
  console.log(JSON.stringify({ project, siteUrl }, null, 2));
889
913
  return;
890
914
  }
@@ -893,7 +917,7 @@ async function bingSetSite(project, siteUrl, format) {
893
917
  async function bingCoverage(project, format) {
894
918
  const client = getClient2();
895
919
  const result = await client.bingCoverage(project);
896
- if (format === "json") {
920
+ if (isMachineFormat(format)) {
897
921
  console.log(JSON.stringify(result, null, 2));
898
922
  return;
899
923
  }
@@ -944,6 +968,9 @@ async function bingCoverageHistory(project, opts) {
944
968
  if (opts.format === "json") {
945
969
  console.log(JSON.stringify(rows, null, 2));
946
970
  return;
971
+ } else if (opts.format === "jsonl") {
972
+ emitJsonl(rows.map((row) => ({ project, ...row })));
973
+ return;
947
974
  }
948
975
  if (rows.length === 0) {
949
976
  console.log('No coverage history found. Run "canonry bing coverage" or "canonry bing refresh" first to capture a snapshot.');
@@ -961,7 +988,7 @@ Bing Coverage History for "${project}" (${rows.length} snapshots):
961
988
  async function bingInspect(project, url, format) {
962
989
  const client = getClient2();
963
990
  const result = await client.bingInspectUrl(project, url);
964
- if (format === "json") {
991
+ if (isMachineFormat(format)) {
965
992
  console.log(JSON.stringify(result, null, 2));
966
993
  return;
967
994
  }
@@ -985,6 +1012,9 @@ async function bingInspections(project, opts) {
985
1012
  if (opts.format === "json") {
986
1013
  console.log(JSON.stringify(rows, null, 2));
987
1014
  return;
1015
+ } else if (opts.format === "jsonl") {
1016
+ emitJsonl(rows.map((row) => ({ project, ...row })));
1017
+ return;
988
1018
  }
989
1019
  if (rows.length === 0) {
990
1020
  console.log("No Bing URL inspections found.");
@@ -1008,14 +1038,14 @@ async function bingRefresh(project, format) {
1008
1038
  const rows = await client.bingInspections(project);
1009
1039
  const uniqueUrls = [...new Set(rows.map((r) => r.url))];
1010
1040
  if (uniqueUrls.length === 0) {
1011
- if (format === "json") {
1041
+ if (isMachineFormat(format)) {
1012
1042
  console.log(JSON.stringify({ refreshed: 0, message: "No previously inspected URLs to refresh." }, null, 2));
1013
1043
  return;
1014
1044
  }
1015
1045
  console.log('No previously inspected URLs to refresh. Run "canonry bing inspect <project> <url>" first.');
1016
1046
  return;
1017
1047
  }
1018
- if (format !== "json") {
1048
+ if (!isMachineFormat(format)) {
1019
1049
  process.stderr.write(`Re-inspecting ${uniqueUrls.length} URL(s) via Bing`);
1020
1050
  }
1021
1051
  const CONCURRENCY = 10;
@@ -1030,11 +1060,11 @@ async function bingRefresh(project, format) {
1030
1060
  errors.push(r.reason instanceof Error ? r.reason.message : String(r.reason));
1031
1061
  }
1032
1062
  }
1033
- if (format !== "json") {
1063
+ if (!isMachineFormat(format)) {
1034
1064
  process.stderr.write(".");
1035
1065
  }
1036
1066
  }
1037
- if (format !== "json") {
1067
+ if (!isMachineFormat(format)) {
1038
1068
  process.stderr.write("\n");
1039
1069
  }
1040
1070
  if (errors.length > 0) {
@@ -1059,7 +1089,7 @@ async function bingRequestIndexing(project, opts) {
1059
1089
  });
1060
1090
  }
1061
1091
  const result = await client.bingRequestIndexing(project, body);
1062
- if (opts.format === "json") {
1092
+ if (isMachineFormat(opts.format)) {
1063
1093
  console.log(JSON.stringify(result, null, 2));
1064
1094
  return;
1065
1095
  }
@@ -1083,11 +1113,11 @@ async function bingInspectSitemap(project, opts) {
1083
1113
  const run = await client.bingInspectSitemap(project, {
1084
1114
  sitemapUrl: opts.sitemapUrl
1085
1115
  });
1086
- if (!opts.wait && opts.format === "json") {
1116
+ if (!opts.wait && isMachineFormat(opts.format)) {
1087
1117
  console.log(JSON.stringify(run, null, 2));
1088
1118
  return;
1089
1119
  }
1090
- if (opts.format !== "json") {
1120
+ if (!isMachineFormat(opts.format)) {
1091
1121
  console.log(`Bing sitemap inspection started (run ${run.id})`);
1092
1122
  }
1093
1123
  if (opts.wait) {
@@ -1103,7 +1133,7 @@ async function bingInspectSitemap(project, opts) {
1103
1133
  failureMessage: "Bing sitemap inspection failed.",
1104
1134
  details: { project }
1105
1135
  });
1106
- if (opts.format === "json") {
1136
+ if (isMachineFormat(opts.format)) {
1107
1137
  console.log(JSON.stringify(current, null, 2));
1108
1138
  return;
1109
1139
  }
@@ -1120,6 +1150,9 @@ async function bingPerformance(project, format) {
1120
1150
  if (format === "json") {
1121
1151
  console.log(JSON.stringify(rows, null, 2));
1122
1152
  return;
1153
+ } else if (format === "jsonl") {
1154
+ emitJsonl(rows.map((row) => ({ project, ...row })));
1155
+ return;
1123
1156
  }
1124
1157
  if (rows.length === 0) {
1125
1158
  console.log("No Bing performance data found.");
@@ -1330,7 +1363,7 @@ async function cdpConnect(opts) {
1330
1363
  port
1331
1364
  };
1332
1365
  saveConfigPatch(config);
1333
- if (opts.format === "json") {
1366
+ if (isMachineFormat(opts.format)) {
1334
1367
  console.log(JSON.stringify({
1335
1368
  host,
1336
1369
  port,
@@ -1346,7 +1379,7 @@ async function cdpStatus(format) {
1346
1379
  const client = getClient3();
1347
1380
  try {
1348
1381
  const status = await client.getCdpStatus();
1349
- if (format === "json") {
1382
+ if (isMachineFormat(format)) {
1350
1383
  console.log(JSON.stringify(status, null, 2));
1351
1384
  return;
1352
1385
  }
@@ -1368,7 +1401,7 @@ async function cdpStatus(format) {
1368
1401
  } catch (err) {
1369
1402
  const msg = err instanceof Error ? err.message : String(err);
1370
1403
  if (msg.includes("501") || msg.includes("not configured")) {
1371
- if (format === "json") {
1404
+ if (isMachineFormat(format)) {
1372
1405
  console.log(JSON.stringify({
1373
1406
  connected: false,
1374
1407
  endpoint: "",
@@ -1408,7 +1441,7 @@ async function cdpScreenshot(query, opts) {
1408
1441
  }
1409
1442
  try {
1410
1443
  const response = await client.cdpScreenshot(query, body.targets);
1411
- if (opts?.format === "json") {
1444
+ if (isMachineFormat(opts?.format)) {
1412
1445
  console.log(JSON.stringify(response, null, 2));
1413
1446
  return;
1414
1447
  }
@@ -1563,7 +1596,7 @@ Sessions already started (recover with \`canonry discover show ${project} <id>\`
1563
1596
  }
1564
1597
  }
1565
1598
  if (!opts.wait) {
1566
- if (opts.format === "json") {
1599
+ if (isMachineFormat(opts.format)) {
1567
1600
  console.log(JSON.stringify(multiAngle ? runs.map((r) => r.start) : runs[0].start, null, 2));
1568
1601
  return;
1569
1602
  }
@@ -1601,7 +1634,7 @@ Sessions already started (recover with \`canonry discover show ${project} <id>\`
1601
1634
  }
1602
1635
  });
1603
1636
  if (results.length > 0) {
1604
- if (opts.format === "json") {
1637
+ if (isMachineFormat(opts.format)) {
1605
1638
  console.log(JSON.stringify(multiAngle ? results.map((r) => r.session) : results[0].session, null, 2));
1606
1639
  } else {
1607
1640
  for (const { angle, session } of results) {
@@ -1648,6 +1681,11 @@ async function discoverProbe(project, sessionId, opts) {
1648
1681
  console.log(JSON.stringify(session, null, 2));
1649
1682
  return;
1650
1683
  }
1684
+ if (opts.format === "jsonl") {
1685
+ const context = { project, sessionId };
1686
+ emitJsonl(session.probes.map((probe) => ({ ...context, ...probe })));
1687
+ return;
1688
+ }
1651
1689
  printSessionDetail(session);
1652
1690
  }
1653
1691
  async function discoverList(project, opts) {
@@ -1657,6 +1695,10 @@ async function discoverList(project, opts) {
1657
1695
  console.log(JSON.stringify(sessions, null, 2));
1658
1696
  return;
1659
1697
  }
1698
+ if (opts.format === "jsonl") {
1699
+ emitJsonl(sessions.map((s) => ({ project, ...s })));
1700
+ return;
1701
+ }
1660
1702
  if (sessions.length === 0) {
1661
1703
  console.log(`No discovery sessions for "${project}".`);
1662
1704
  return;
@@ -1682,12 +1724,17 @@ async function discoverShow(project, sessionId, opts) {
1682
1724
  console.log(JSON.stringify(session, null, 2));
1683
1725
  return;
1684
1726
  }
1727
+ if (opts.format === "jsonl") {
1728
+ const context = { project, sessionId };
1729
+ emitJsonl(session.probes.map((probe) => ({ ...context, ...probe })));
1730
+ return;
1731
+ }
1685
1732
  printSessionDetail(session);
1686
1733
  }
1687
1734
  async function discoverPromotePreview(project, sessionId, opts) {
1688
1735
  const client = getClient4();
1689
1736
  const preview = await client.previewDiscoveryPromote(project, sessionId);
1690
- if (opts.format === "json") {
1737
+ if (isMachineFormat(opts.format)) {
1691
1738
  console.log(JSON.stringify(preview, null, 2));
1692
1739
  return;
1693
1740
  }
@@ -1716,7 +1763,7 @@ async function discoverPromote(project, sessionId, opts) {
1716
1763
  if (opts.competitorTypes && opts.competitorTypes.length > 0) body.competitorTypes = opts.competitorTypes;
1717
1764
  if (opts.includeCompetitors === false) body.includeCompetitors = false;
1718
1765
  const result = await client.promoteDiscovery(project, sessionId, body);
1719
- if (opts.format === "json") {
1766
+ if (isMachineFormat(opts.format)) {
1720
1767
  console.log(JSON.stringify(result, null, 2));
1721
1768
  return;
1722
1769
  }
@@ -2038,6 +2085,8 @@ async function doctorCommand(opts) {
2038
2085
  });
2039
2086
  if (opts.format === "json") {
2040
2087
  console.log(JSON.stringify(report, null, 2));
2088
+ } else if (opts.format === "jsonl") {
2089
+ emitJsonl(report.checks.map((check) => ({ project: report.project, ...check })));
2041
2090
  } else {
2042
2091
  printHumanReport(report);
2043
2092
  }
@@ -2067,6 +2116,12 @@ async function runDoctorAll(opts) {
2067
2116
  });
2068
2117
  if (opts.format === "json") {
2069
2118
  console.log(JSON.stringify(byKey, null, 2));
2119
+ } else if (opts.format === "jsonl") {
2120
+ const scopes = ["__global__", ...projects2.map((p) => p.name)];
2121
+ emitJsonl(scopes.flatMap((key) => {
2122
+ const project = key === "__global__" ? null : key;
2123
+ return byKey[key].checks.map((check) => ({ project, ...check }));
2124
+ }));
2070
2125
  } else {
2071
2126
  printAllHumanReport(byKey, projects2.map((p) => p.name));
2072
2127
  }
@@ -2149,7 +2204,7 @@ ${header}`);
2149
2204
  }
2150
2205
 
2151
2206
  // src/cli-commands/doctor.ts
2152
- var USAGE = "canonry doctor [--project <name>|--all] [--check <id>...] [--format json]";
2207
+ var USAGE = "canonry doctor [--project <name>|--all] [--check <id>...] [--format json|jsonl]";
2153
2208
  var DOCTOR_CLI_COMMANDS = [
2154
2209
  {
2155
2210
  path: ["doctor"],
@@ -2207,7 +2262,7 @@ async function gaConnect(project, opts) {
2207
2262
  }
2208
2263
  const client = getClient5();
2209
2264
  const result = await client.gaConnect(project, body);
2210
- if (opts.format === "json") {
2265
+ if (isMachineFormat(opts.format)) {
2211
2266
  console.log(JSON.stringify(result, null, 2));
2212
2267
  return;
2213
2268
  }
@@ -2222,7 +2277,7 @@ async function gaConnect(project, opts) {
2222
2277
  async function gaDisconnect(project, format) {
2223
2278
  const client = getClient5();
2224
2279
  await client.gaDisconnect(project);
2225
- if (format === "json") {
2280
+ if (isMachineFormat(format)) {
2226
2281
  console.log(JSON.stringify({ project, disconnected: true }, null, 2));
2227
2282
  return;
2228
2283
  }
@@ -2231,7 +2286,7 @@ async function gaDisconnect(project, format) {
2231
2286
  async function gaStatus(project, format) {
2232
2287
  const client = getClient5();
2233
2288
  const result = await client.gaStatus(project);
2234
- if (format === "json") {
2289
+ if (isMachineFormat(format)) {
2235
2290
  console.log(JSON.stringify(result, null, 2));
2236
2291
  return;
2237
2292
  }
@@ -2260,7 +2315,7 @@ async function gaSync(project, opts) {
2260
2315
  if (opts?.days) body.days = opts.days;
2261
2316
  if (opts?.only) body.only = opts.only;
2262
2317
  const result = await client.gaSync(project, body);
2263
- if (opts?.format === "json") {
2318
+ if (isMachineFormat(opts?.format)) {
2264
2319
  console.log(JSON.stringify(result, null, 2));
2265
2320
  return;
2266
2321
  }
@@ -2280,7 +2335,7 @@ async function gaTraffic(project, opts) {
2280
2335
  if (opts?.limit) params.limit = String(opts.limit);
2281
2336
  if (opts?.window) params.window = opts.window;
2282
2337
  const result = await client.gaTraffic(project, Object.keys(params).length > 0 ? params : void 0);
2283
- if (opts?.format === "json") {
2338
+ if (isMachineFormat(opts?.format)) {
2284
2339
  console.log(JSON.stringify(result, null, 2));
2285
2340
  return;
2286
2341
  }
@@ -2370,6 +2425,9 @@ async function gaAiReferralHistory(project, opts) {
2370
2425
  if (opts?.format === "json") {
2371
2426
  console.log(JSON.stringify(result, null, 2));
2372
2427
  return;
2428
+ } else if (opts?.format === "jsonl") {
2429
+ emitJsonl(result.map((row) => ({ project, window: opts?.window, ...row })));
2430
+ return;
2373
2431
  }
2374
2432
  if (result.length === 0) {
2375
2433
  console.log(`No AI referral history.${opts?.window ? " Try a wider window or omit --window." : ' Run "canonry ga sync <project>" first.'}`);
@@ -2395,6 +2453,9 @@ async function gaSocialReferralHistory(project, opts) {
2395
2453
  if (opts?.format === "json") {
2396
2454
  console.log(JSON.stringify(result, null, 2));
2397
2455
  return;
2456
+ } else if (opts?.format === "jsonl") {
2457
+ emitJsonl(result.map((row) => ({ project, window: opts?.window, ...row })));
2458
+ return;
2398
2459
  }
2399
2460
  if (result.length === 0) {
2400
2461
  console.log(`No social referral history.${opts?.window ? " Try a wider window or omit --window." : ' Run "canonry ga sync <project>" first.'}`);
@@ -2420,6 +2481,9 @@ async function gaSessionHistory(project, opts) {
2420
2481
  if (opts?.format === "json") {
2421
2482
  console.log(JSON.stringify(result, null, 2));
2422
2483
  return;
2484
+ } else if (opts?.format === "jsonl") {
2485
+ emitJsonl(result.map((row) => ({ project, window: opts?.window, ...row })));
2486
+ return;
2423
2487
  }
2424
2488
  if (result.length === 0) {
2425
2489
  console.log(`No session history.${opts?.window ? " Try a wider window or omit --window." : ' Run "canonry ga sync <project>" first.'}`);
@@ -2442,6 +2506,9 @@ async function gaCoverage(project, format) {
2442
2506
  if (format === "json") {
2443
2507
  console.log(JSON.stringify(result, null, 2));
2444
2508
  return;
2509
+ } else if (format === "jsonl") {
2510
+ emitJsonl(result.pages.map((row) => ({ project, ...row })));
2511
+ return;
2445
2512
  }
2446
2513
  if (result.pages.length === 0) {
2447
2514
  console.log('No GA4 coverage data. Run "canonry ga sync <project>" first.');
@@ -2464,7 +2531,7 @@ async function gaSocialReferralSummary(project, opts) {
2464
2531
  const traffic = await client.gaTraffic(project);
2465
2532
  if (opts?.trend) {
2466
2533
  const trend = await client.gaSocialReferralTrend(project);
2467
- if (opts.format === "json") {
2534
+ if (isMachineFormat(opts.format)) {
2468
2535
  console.log(JSON.stringify({
2469
2536
  socialSessions: traffic.socialSessions,
2470
2537
  socialUsers: traffic.socialUsers,
@@ -2497,7 +2564,7 @@ async function gaSocialReferralSummary(project, opts) {
2497
2564
  }
2498
2565
  return;
2499
2566
  }
2500
- if (opts?.format === "json") {
2567
+ if (isMachineFormat(opts?.format)) {
2501
2568
  console.log(JSON.stringify({
2502
2569
  socialSessions: traffic.socialSessions,
2503
2570
  socialUsers: traffic.socialUsers,
@@ -2526,7 +2593,7 @@ async function gaAttribution(project, opts) {
2526
2593
  const fmtTrend = (pct2) => pct2 === null ? "n/a" : `${pct2 >= 0 ? "+" : ""}${pct2}%`;
2527
2594
  if (opts?.trend) {
2528
2595
  const trend = await client.gaAttributionTrend(project);
2529
- if (opts.format === "json") {
2596
+ if (isMachineFormat(opts.format)) {
2530
2597
  console.log(JSON.stringify({
2531
2598
  totalSessions: traffic.totalSessions,
2532
2599
  totalUsers: traffic.totalUsers,
@@ -2594,7 +2661,7 @@ async function gaAttribution(project, opts) {
2594
2661
  }
2595
2662
  return;
2596
2663
  }
2597
- if (opts?.format === "json") {
2664
+ if (isMachineFormat(opts?.format)) {
2598
2665
  console.log(JSON.stringify({
2599
2666
  totalSessions: traffic.totalSessions,
2600
2667
  totalUsers: traffic.totalUsers,
@@ -2871,7 +2938,7 @@ async function gbpConnect(project, opts) {
2871
2938
  type: "gbp",
2872
2939
  publicUrl: opts.publicUrl
2873
2940
  });
2874
- if (opts.format === "json") {
2941
+ if (isMachineFormat(opts.format)) {
2875
2942
  console.log(JSON.stringify({ project, type: "gbp", authUrl, redirectUri: redirectUri ?? null }, null, 2));
2876
2943
  return;
2877
2944
  }
@@ -2887,7 +2954,7 @@ async function gbpConnect(project, opts) {
2887
2954
  async function gbpDisconnect(project, opts) {
2888
2955
  const client = getClient6();
2889
2956
  await client.disconnectGbp(project);
2890
- if (opts.format === "json") {
2957
+ if (isMachineFormat(opts.format)) {
2891
2958
  console.log(JSON.stringify({ project, disconnected: true }, null, 2));
2892
2959
  return;
2893
2960
  }
@@ -2899,7 +2966,7 @@ async function gbpLocationsList(project, opts) {
2899
2966
  project,
2900
2967
  opts.selectedOnly ? { selected: true } : void 0
2901
2968
  );
2902
- if (opts.format === "json") {
2969
+ if (isMachineFormat(opts.format)) {
2903
2970
  console.log(JSON.stringify(response, null, 2));
2904
2971
  return;
2905
2972
  }
@@ -2908,7 +2975,7 @@ async function gbpLocationsList(project, opts) {
2908
2975
  async function gbpAccounts(project, opts) {
2909
2976
  const client = getClient6();
2910
2977
  const response = await client.listGbpAccounts(project);
2911
- if (opts.format === "json") {
2978
+ if (isMachineFormat(opts.format)) {
2912
2979
  console.log(JSON.stringify(response, null, 2));
2913
2980
  return;
2914
2981
  }
@@ -2939,7 +3006,7 @@ async function gbpLocationsDiscover(project, opts) {
2939
3006
  ...opts.switchAccount ? { switchAccount: true } : {}
2940
3007
  } : void 0;
2941
3008
  const response = await client.discoverGbpLocations(project, body);
2942
- if (opts.format === "json") {
3009
+ if (isMachineFormat(opts.format)) {
2943
3010
  console.log(JSON.stringify(response, null, 2));
2944
3011
  return;
2945
3012
  }
@@ -2950,7 +3017,7 @@ Discovered ${response.totalDiscovered} location(s); ${response.totalSelected} se
2950
3017
  async function gbpLocationSelect(project, opts) {
2951
3018
  const client = getClient6();
2952
3019
  const updated = await client.setGbpLocationSelection(project, opts.location, true);
2953
- if (opts.format === "json") {
3020
+ if (isMachineFormat(opts.format)) {
2954
3021
  console.log(JSON.stringify(updated, null, 2));
2955
3022
  return;
2956
3023
  }
@@ -2959,7 +3026,7 @@ async function gbpLocationSelect(project, opts) {
2959
3026
  async function gbpLocationDeselect(project, opts) {
2960
3027
  const client = getClient6();
2961
3028
  const updated = await client.setGbpLocationSelection(project, opts.location, false);
2962
- if (opts.format === "json") {
3029
+ if (isMachineFormat(opts.format)) {
2963
3030
  console.log(JSON.stringify(updated, null, 2));
2964
3031
  return;
2965
3032
  }
@@ -2973,7 +3040,7 @@ async function gbpSync(project, opts) {
2973
3040
  monthsOfKeywords: opts.months
2974
3041
  });
2975
3042
  if (!opts.wait) {
2976
- if (opts.format === "json") {
3043
+ if (isMachineFormat(opts.format)) {
2977
3044
  console.log(JSON.stringify({ runId, status }, null, 2));
2978
3045
  return;
2979
3046
  }
@@ -2983,19 +3050,19 @@ async function gbpSync(project, opts) {
2983
3050
  const terminal = /* @__PURE__ */ new Set(["completed", "partial", "failed", "cancelled"]);
2984
3051
  const start = Date.now();
2985
3052
  const timeoutMs = 10 * 60 * 1e3;
2986
- if (opts.format !== "json") process.stderr.write("Syncing");
3053
+ if (!isMachineFormat(opts.format)) process.stderr.write("Syncing");
2987
3054
  let final = status;
2988
3055
  while (Date.now() - start < timeoutMs) {
2989
3056
  await new Promise((r) => setTimeout(r, 2e3));
2990
3057
  const run = await client.getRun(runId);
2991
- if (opts.format !== "json") process.stderr.write(".");
3058
+ if (!isMachineFormat(opts.format)) process.stderr.write(".");
2992
3059
  if (terminal.has(run.status)) {
2993
3060
  final = run.status;
2994
3061
  break;
2995
3062
  }
2996
3063
  }
2997
- if (opts.format !== "json") process.stderr.write("\n");
2998
- if (opts.format === "json") {
3064
+ if (!isMachineFormat(opts.format)) process.stderr.write("\n");
3065
+ if (isMachineFormat(opts.format)) {
2999
3066
  console.log(JSON.stringify({ runId, status: final }, null, 2));
3000
3067
  return;
3001
3068
  }
@@ -3004,7 +3071,7 @@ async function gbpSync(project, opts) {
3004
3071
  async function gbpMetrics(project, opts) {
3005
3072
  const client = getClient6();
3006
3073
  const response = await client.listGbpMetrics(project, { locationName: opts.location, metric: opts.metric });
3007
- if (opts.format === "json") {
3074
+ if (isMachineFormat(opts.format)) {
3008
3075
  console.log(JSON.stringify(response, null, 2));
3009
3076
  return;
3010
3077
  }
@@ -3022,7 +3089,7 @@ async function gbpMetrics(project, opts) {
3022
3089
  async function gbpKeywords(project, opts) {
3023
3090
  const client = getClient6();
3024
3091
  const response = await client.listGbpKeywords(project, { locationName: opts.location });
3025
- if (opts.format === "json") {
3092
+ if (isMachineFormat(opts.format)) {
3026
3093
  console.log(JSON.stringify(response, null, 2));
3027
3094
  return;
3028
3095
  }
@@ -3039,7 +3106,7 @@ async function gbpKeywords(project, opts) {
3039
3106
  async function gbpPlaceActions(project, opts) {
3040
3107
  const client = getClient6();
3041
3108
  const response = await client.listGbpPlaceActions(project, { locationName: opts.location });
3042
- if (opts.format === "json") {
3109
+ if (isMachineFormat(opts.format)) {
3043
3110
  console.log(JSON.stringify(response, null, 2));
3044
3111
  return;
3045
3112
  }
@@ -3056,7 +3123,7 @@ async function gbpPlaceActions(project, opts) {
3056
3123
  async function gbpLodging(project, opts) {
3057
3124
  const client = getClient6();
3058
3125
  const response = await client.listGbpLodging(project, { locationName: opts.location });
3059
- if (opts.format === "json") {
3126
+ if (isMachineFormat(opts.format)) {
3060
3127
  console.log(JSON.stringify(response, null, 2));
3061
3128
  return;
3062
3129
  }
@@ -3073,7 +3140,7 @@ async function gbpLodging(project, opts) {
3073
3140
  async function gbpPlaces(project, opts) {
3074
3141
  const client = getClient6();
3075
3142
  const response = await client.listGbpPlaces(project, { locationName: opts.location });
3076
- if (opts.format === "json") {
3143
+ if (isMachineFormat(opts.format)) {
3077
3144
  console.log(JSON.stringify(response, null, 2));
3078
3145
  return;
3079
3146
  }
@@ -3094,7 +3161,7 @@ function fmtDelta(pct2) {
3094
3161
  async function gbpSummary(project, opts) {
3095
3162
  const client = getClient6();
3096
3163
  const s = await client.getGbpSummary(project, { locationName: opts.location });
3097
- if (opts.format === "json") {
3164
+ if (isMachineFormat(opts.format)) {
3098
3165
  console.log(JSON.stringify(s, null, 2));
3099
3166
  return;
3100
3167
  }
@@ -3336,7 +3403,7 @@ async function getCommand(opts) {
3336
3403
  details: { project: opts.project, path: opts.path, from: source }
3337
3404
  });
3338
3405
  }
3339
- if (opts.format === "json") {
3406
+ if (isMachineFormat(opts.format)) {
3340
3407
  console.log(JSON.stringify(leaf, null, 2));
3341
3408
  return;
3342
3409
  }
@@ -3471,7 +3538,7 @@ async function trafficConnectWordpress(project, opts) {
3471
3538
  applicationPassword,
3472
3539
  displayName: opts.displayName
3473
3540
  });
3474
- if (opts.format === "json") {
3541
+ if (isMachineFormat(opts.format)) {
3475
3542
  console.log(JSON.stringify(result, null, 2));
3476
3543
  return;
3477
3544
  }
@@ -3523,7 +3590,7 @@ async function trafficConnectCloudRun(project, opts) {
3523
3590
  displayName: opts.displayName,
3524
3591
  keyJson
3525
3592
  });
3526
- if (opts.format === "json") {
3593
+ if (isMachineFormat(opts.format)) {
3527
3594
  console.log(JSON.stringify(result, null, 2));
3528
3595
  return;
3529
3596
  }
@@ -3601,7 +3668,7 @@ async function trafficConnectVercel(project, opts) {
3601
3668
  environment: opts.environment,
3602
3669
  displayName: opts.displayName
3603
3670
  });
3604
- if (opts.format === "json") {
3671
+ if (isMachineFormat(opts.format)) {
3605
3672
  console.log(JSON.stringify(result, null, 2));
3606
3673
  return;
3607
3674
  }
@@ -3629,7 +3696,7 @@ async function trafficBackfill(project, opts) {
3629
3696
  days: opts.days
3630
3697
  });
3631
3698
  if (!opts.wait) {
3632
- if (opts.format === "json") {
3699
+ if (isMachineFormat(opts.format)) {
3633
3700
  console.log(JSON.stringify(submitted, null, 2));
3634
3701
  return;
3635
3702
  }
@@ -3661,7 +3728,7 @@ async function trafficBackfill(project, opts) {
3661
3728
  details: { project, runId: submitted.runId }
3662
3729
  });
3663
3730
  }
3664
- if (opts.format === "json") {
3731
+ if (isMachineFormat(opts.format)) {
3665
3732
  console.log(JSON.stringify({ ...submitted, finalStatus: final.status, finalRun: final }, null, 2));
3666
3733
  return;
3667
3734
  }
@@ -3697,7 +3764,7 @@ async function trafficSync(project, opts) {
3697
3764
  const result = await client.trafficSync(project, opts.source, {
3698
3765
  sinceMinutes: opts.sinceMinutes
3699
3766
  });
3700
- if (opts.format === "json") {
3767
+ if (isMachineFormat(opts.format)) {
3701
3768
  console.log(JSON.stringify(result, null, 2));
3702
3769
  return;
3703
3770
  }
@@ -3733,7 +3800,7 @@ async function trafficReset(project, opts) {
3733
3800
  }
3734
3801
  const client = getClient7();
3735
3802
  const updated = await client.trafficReset(project, opts.source);
3736
- if (opts.format === "json") {
3803
+ if (isMachineFormat(opts.format)) {
3737
3804
  console.log(JSON.stringify(updated, null, 2));
3738
3805
  return;
3739
3806
  }
@@ -3760,6 +3827,9 @@ async function trafficSources(project, opts) {
3760
3827
  if (opts.format === "json") {
3761
3828
  console.log(JSON.stringify(result, null, 2));
3762
3829
  return;
3830
+ } else if (opts.format === "jsonl") {
3831
+ emitJsonl(result.sources.map((source) => ({ project, ...source })));
3832
+ return;
3763
3833
  }
3764
3834
  if (result.sources.length === 0) {
3765
3835
  console.log(`No traffic sources connected for project "${project}".`);
@@ -3779,6 +3849,9 @@ async function trafficStatus(project, opts) {
3779
3849
  if (opts.format === "json") {
3780
3850
  console.log(JSON.stringify(result, null, 2));
3781
3851
  return;
3852
+ } else if (opts.format === "jsonl") {
3853
+ emitJsonl(details.map((detail) => ({ project, ...detail })));
3854
+ return;
3782
3855
  }
3783
3856
  if (details.length === 0) {
3784
3857
  console.log(`No traffic sources connected for project "${project}".`);
@@ -3864,6 +3937,14 @@ async function trafficEvents(project, opts) {
3864
3937
  if (opts.format === "json") {
3865
3938
  console.log(JSON.stringify(result, null, 2));
3866
3939
  return;
3940
+ } else if (opts.format === "jsonl") {
3941
+ emitJsonl(result.events.map((event) => ({
3942
+ project,
3943
+ windowStart: result.windowStart,
3944
+ windowEnd: result.windowEnd,
3945
+ ...event
3946
+ })));
3947
+ return;
3867
3948
  }
3868
3949
  console.log(`Traffic events for "${project}" ${result.windowStart} \u2192 ${result.windowEnd}`);
3869
3950
  console.log(` Crawler hits (window): ${result.totals.crawlerHits}`);
@@ -4151,7 +4232,7 @@ async function addCompetitors(project, domains, format) {
4151
4232
  const current = await client.appendCompetitors(project, domains);
4152
4233
  const currentDomains = current.map((c) => c.domain);
4153
4234
  const addedDomains = currentDomains.filter((domain) => requested.has(domain) && !existingSet.has(domain));
4154
- if (format === "json") {
4235
+ if (isMachineFormat(format)) {
4155
4236
  console.log(JSON.stringify({
4156
4237
  project,
4157
4238
  domains: currentDomains,
@@ -4174,7 +4255,7 @@ async function removeCompetitors(project, domains, format) {
4174
4255
  const current = await client.deleteCompetitors(project, domains);
4175
4256
  const currentSet = new Set(current.map((c) => c.domain));
4176
4257
  const removedDomains = existingDomains.filter((domain) => requested.has(domain) && !currentSet.has(domain));
4177
- if (format === "json") {
4258
+ if (isMachineFormat(format)) {
4178
4259
  console.log(JSON.stringify({
4179
4260
  project,
4180
4261
  domains: current.map((c) => c.domain),
@@ -4201,6 +4282,9 @@ async function listCompetitors(project, format) {
4201
4282
  if (format === "json") {
4202
4283
  console.log(JSON.stringify(comps, null, 2));
4203
4284
  return;
4285
+ } else if (format === "jsonl") {
4286
+ emitJsonl(comps.map((c) => ({ project, ...c })));
4287
+ return;
4204
4288
  }
4205
4289
  if (comps.length === 0) {
4206
4290
  console.log(`No competitors found for "${project}".`);
@@ -4337,7 +4421,7 @@ async function googleConnect(project, opts) {
4337
4421
  type: opts.type,
4338
4422
  publicUrl: opts.publicUrl
4339
4423
  });
4340
- if (opts.format === "json") {
4424
+ if (isMachineFormat(opts.format)) {
4341
4425
  console.log(JSON.stringify({
4342
4426
  project,
4343
4427
  type: opts.type,
@@ -4368,7 +4452,7 @@ Open this URL in your browser to authorize Google ${opts.type.toUpperCase()} acc
4368
4452
  async function googleDisconnect(project, opts) {
4369
4453
  const client = getClient9();
4370
4454
  await client.googleDisconnect(project, opts.type);
4371
- if (opts.format === "json") {
4455
+ if (isMachineFormat(opts.format)) {
4372
4456
  console.log(JSON.stringify({ project, type: opts.type, disconnected: true }, null, 2));
4373
4457
  return;
4374
4458
  }
@@ -4380,6 +4464,9 @@ async function googleStatus(project, format) {
4380
4464
  if (format === "json") {
4381
4465
  console.log(JSON.stringify({ connections }, null, 2));
4382
4466
  return;
4467
+ } else if (format === "jsonl") {
4468
+ emitJsonl(connections.map((conn) => ({ project, ...conn })));
4469
+ return;
4383
4470
  }
4384
4471
  if (connections.length === 0) {
4385
4472
  console.log(`No Google connections for project "${project}".`);
@@ -4404,6 +4491,9 @@ async function googleProperties(project, format) {
4404
4491
  if (format === "json") {
4405
4492
  console.log(JSON.stringify({ sites }, null, 2));
4406
4493
  return;
4494
+ } else if (format === "jsonl") {
4495
+ emitJsonl(sites.map((site) => ({ project, ...site })));
4496
+ return;
4407
4497
  }
4408
4498
  if (sites.length === 0) {
4409
4499
  console.log("No verified sites found for this Google account.");
@@ -4422,7 +4512,7 @@ Use "canonry google set-property <project> <siteUrl>" to select a property.`);
4422
4512
  async function googleSetProperty(project, propertyUrl, format) {
4423
4513
  const client = getClient9();
4424
4514
  await client.googleSetProperty(project, "gsc", propertyUrl);
4425
- if (format === "json") {
4515
+ if (isMachineFormat(format)) {
4426
4516
  console.log(JSON.stringify({ project, type: "gsc", propertyUrl }, null, 2));
4427
4517
  return;
4428
4518
  }
@@ -4431,11 +4521,11 @@ async function googleSetProperty(project, propertyUrl, format) {
4431
4521
  async function googleSync(project, opts) {
4432
4522
  const client = getClient9();
4433
4523
  const run = await client.gscSync(project, { days: opts.days, full: opts.full });
4434
- if (!opts.wait && opts.format === "json") {
4524
+ if (!opts.wait && isMachineFormat(opts.format)) {
4435
4525
  console.log(JSON.stringify(run, null, 2));
4436
4526
  return;
4437
4527
  }
4438
- if (opts.format !== "json") {
4528
+ if (!isMachineFormat(opts.format)) {
4439
4529
  console.log(`GSC sync started (run ${run.id})`);
4440
4530
  }
4441
4531
  if (opts.wait) {
@@ -4451,7 +4541,7 @@ async function googleSync(project, opts) {
4451
4541
  failureMessage: "GSC sync failed.",
4452
4542
  details: { project }
4453
4543
  });
4454
- if (opts.format === "json") {
4544
+ if (isMachineFormat(opts.format)) {
4455
4545
  console.log(JSON.stringify({ ...run, status: current.status }, null, 2));
4456
4546
  return;
4457
4547
  }
@@ -4468,6 +4558,9 @@ async function googlePerformanceDaily(project, opts) {
4468
4558
  if (opts.format === "json") {
4469
4559
  console.log(JSON.stringify(data, null, 2));
4470
4560
  return;
4561
+ } else if (opts.format === "jsonl") {
4562
+ emitJsonl(data.daily.map((row) => ({ project, ...row })));
4563
+ return;
4471
4564
  }
4472
4565
  if (data.daily.length === 0) {
4473
4566
  console.log('No GSC data found in this window. Run "canonry google sync" first.');
@@ -4504,6 +4597,9 @@ async function googlePerformance(project, opts) {
4504
4597
  if (opts.format === "json") {
4505
4598
  console.log(JSON.stringify(rows, null, 2));
4506
4599
  return;
4600
+ } else if (opts.format === "jsonl") {
4601
+ emitJsonl(rows.map((row) => ({ project, ...row })));
4602
+ return;
4507
4603
  }
4508
4604
  if (rows.length === 0) {
4509
4605
  console.log('No GSC data found. Run "canonry google sync" first.');
@@ -4527,7 +4623,7 @@ async function googlePerformance(project, opts) {
4527
4623
  async function googleInspect(project, url, format) {
4528
4624
  const client = getClient9();
4529
4625
  const result = await client.gscInspect(project, url);
4530
- if (format === "json") {
4626
+ if (isMachineFormat(format)) {
4531
4627
  console.log(JSON.stringify(result, null, 2));
4532
4628
  return;
4533
4629
  }
@@ -4552,6 +4648,9 @@ async function googleInspections(project, opts) {
4552
4648
  if (opts.format === "json") {
4553
4649
  console.log(JSON.stringify(rows, null, 2));
4554
4650
  return;
4651
+ } else if (opts.format === "jsonl") {
4652
+ emitJsonl(rows.map((row) => ({ project, ...row })));
4653
+ return;
4555
4654
  }
4556
4655
  if (rows.length === 0) {
4557
4656
  console.log("No URL inspections found.");
@@ -4572,7 +4671,7 @@ async function googleInspections(project, opts) {
4572
4671
  async function googleCoverage(project, format) {
4573
4672
  const client = getClient9();
4574
4673
  const result = await client.gscCoverage(project);
4575
- if (format === "json") {
4674
+ if (isMachineFormat(format)) {
4576
4675
  console.log(JSON.stringify(result, null, 2));
4577
4676
  return;
4578
4677
  }
@@ -4618,7 +4717,7 @@ Index Coverage for "${project}"
4618
4717
  async function googleSetSitemap(project, sitemapUrl, format) {
4619
4718
  const client = getClient9();
4620
4719
  await client.googleSetSitemap(project, "gsc", sitemapUrl);
4621
- if (format === "json") {
4720
+ if (isMachineFormat(format)) {
4622
4721
  console.log(JSON.stringify({ project, type: "gsc", sitemapUrl }, null, 2));
4623
4722
  return;
4624
4723
  }
@@ -4630,6 +4729,9 @@ async function googleListSitemaps(project, opts) {
4630
4729
  if (opts.format === "json") {
4631
4730
  console.log(JSON.stringify(result, null, 2));
4632
4731
  return;
4732
+ } else if (opts.format === "jsonl") {
4733
+ emitJsonl(result.sitemaps.map((s) => ({ project, ...s })));
4734
+ return;
4633
4735
  }
4634
4736
  if (result.sitemaps.length === 0) {
4635
4737
  console.log(`No sitemaps found for project "${project}". Submit a sitemap in Google Search Console first.`);
@@ -4651,11 +4753,11 @@ async function googleInspectSitemap(project, opts) {
4651
4753
  const run = await client.gscInspectSitemap(project, {
4652
4754
  sitemapUrl: opts.sitemapUrl
4653
4755
  });
4654
- if (!opts.wait && opts.format === "json") {
4756
+ if (!opts.wait && isMachineFormat(opts.format)) {
4655
4757
  console.log(JSON.stringify(run, null, 2));
4656
4758
  return;
4657
4759
  }
4658
- if (opts.format !== "json") {
4760
+ if (!isMachineFormat(opts.format)) {
4659
4761
  console.log(`Sitemap inspection started (run ${run.id})`);
4660
4762
  }
4661
4763
  if (opts.wait) {
@@ -4671,7 +4773,7 @@ async function googleInspectSitemap(project, opts) {
4671
4773
  failureMessage: "Sitemap inspection failed.",
4672
4774
  details: { project }
4673
4775
  });
4674
- if (opts.format === "json") {
4776
+ if (isMachineFormat(opts.format)) {
4675
4777
  console.log(JSON.stringify({ ...run, status: current.status }, null, 2));
4676
4778
  return;
4677
4779
  }
@@ -4688,6 +4790,9 @@ async function googleCoverageHistory(project, opts) {
4688
4790
  if (opts.format === "json") {
4689
4791
  console.log(JSON.stringify(rows, null, 2));
4690
4792
  return;
4793
+ } else if (opts.format === "jsonl") {
4794
+ emitJsonl(rows.map((row) => ({ project, ...row })));
4795
+ return;
4691
4796
  }
4692
4797
  if (rows.length === 0) {
4693
4798
  console.log("No coverage history found. Run a GSC sync or sitemap inspection first.");
@@ -4707,11 +4812,11 @@ GSC Coverage History for "${project}" (${rows.length} snapshots):
4707
4812
  async function googleDiscoverSitemaps(project, opts) {
4708
4813
  const client = getClient9();
4709
4814
  const result = await client.gscDiscoverSitemaps(project);
4710
- if (!opts.wait && opts.format === "json") {
4815
+ if (!opts.wait && isMachineFormat(opts.format)) {
4711
4816
  console.log(JSON.stringify(result, null, 2));
4712
4817
  return;
4713
4818
  }
4714
- if (opts.format !== "json") {
4819
+ if (!isMachineFormat(opts.format)) {
4715
4820
  console.log(`
4716
4821
  Discovered ${result.sitemaps.length} sitemap(s) for project "${project}":
4717
4822
  `);
@@ -4739,7 +4844,7 @@ Primary sitemap: ${result.primarySitemapUrl}`);
4739
4844
  failureMessage: "Sitemap inspection failed.",
4740
4845
  details: { project }
4741
4846
  });
4742
- if (opts.format === "json") {
4847
+ if (isMachineFormat(opts.format)) {
4743
4848
  console.log(JSON.stringify({
4744
4849
  ...result,
4745
4850
  run: {
@@ -4771,7 +4876,7 @@ async function googleRequestIndexing(project, opts) {
4771
4876
  details: { command: "google.request-indexing" }
4772
4877
  });
4773
4878
  }
4774
- if (opts.format !== "json") {
4879
+ if (!isMachineFormat(opts.format)) {
4775
4880
  console.error(INDEXING_API_SCOPE_NOTICE);
4776
4881
  console.error();
4777
4882
  }
@@ -4828,7 +4933,7 @@ async function googleRequestIndexing(project, opts) {
4828
4933
  });
4829
4934
  }
4830
4935
  }
4831
- if (opts.format === "json") {
4936
+ if (isMachineFormat(opts.format)) {
4832
4937
  console.log(JSON.stringify({ ...result, ...opts.wait ? { indexingConfirmed } : {} }, null, 2));
4833
4938
  return;
4834
4939
  }
@@ -4854,7 +4959,7 @@ async function googleRequestIndexing(project, opts) {
4854
4959
  async function googleRefresh(project, format) {
4855
4960
  const client = getClient9();
4856
4961
  const run = await client.gscSync(project, {});
4857
- if (format !== "json") {
4962
+ if (!isMachineFormat(format)) {
4858
4963
  process.stderr.write("Refreshing GSC coverage data");
4859
4964
  }
4860
4965
  const current = await waitForRunStatus2(client, run.id, {
@@ -4869,7 +4974,7 @@ async function googleRefresh(project, format) {
4869
4974
  failureMessage: "GSC refresh failed.",
4870
4975
  details: { project }
4871
4976
  });
4872
- if (current.status === "partial" && format !== "json") {
4977
+ if (current.status === "partial" && !isMachineFormat(format)) {
4873
4978
  process.stderr.write("Refresh completed with some errors.\n");
4874
4979
  }
4875
4980
  await googleCoverage(project, format);
@@ -4880,6 +4985,9 @@ async function googleDeindexed(project, format) {
4880
4985
  if (format === "json") {
4881
4986
  console.log(JSON.stringify(rows, null, 2));
4882
4987
  return;
4988
+ } else if (format === "jsonl") {
4989
+ emitJsonl(rows.map((row) => ({ project, ...row })));
4990
+ return;
4883
4991
  }
4884
4992
  if (rows.length === 0) {
4885
4993
  console.log("No deindexed pages detected.");
@@ -5188,7 +5296,7 @@ function getClient10() {
5188
5296
  async function addKeywords(project, keywords, format) {
5189
5297
  const client = getClient10();
5190
5298
  await client.appendKeywords(project, keywords);
5191
- if (format === "json") {
5299
+ if (isMachineFormat(format)) {
5192
5300
  console.log(JSON.stringify({
5193
5301
  project,
5194
5302
  keywords,
@@ -5201,7 +5309,7 @@ async function addKeywords(project, keywords, format) {
5201
5309
  async function replaceKeywords(project, keywords, format) {
5202
5310
  const client = getClient10();
5203
5311
  await client.putKeywords(project, keywords);
5204
- if (format === "json") {
5312
+ if (isMachineFormat(format)) {
5205
5313
  console.log(JSON.stringify({
5206
5314
  project,
5207
5315
  keywords,
@@ -5217,7 +5325,7 @@ async function removeKeywords(project, keywords, format) {
5217
5325
  const existingSet = new Set(existing.map((k) => k.keyword));
5218
5326
  const removedKeywords = keywords.filter((k) => existingSet.has(k));
5219
5327
  await client.deleteKeywords(project, keywords);
5220
- if (format === "json") {
5328
+ if (isMachineFormat(format)) {
5221
5329
  console.log(JSON.stringify({
5222
5330
  project,
5223
5331
  keywords,
@@ -5234,6 +5342,9 @@ async function listKeywords(project, format) {
5234
5342
  if (format === "json") {
5235
5343
  console.log(JSON.stringify(kws, null, 2));
5236
5344
  return;
5345
+ } else if (format === "jsonl") {
5346
+ emitJsonl(kws.map((kw) => ({ project, ...kw })));
5347
+ return;
5237
5348
  }
5238
5349
  if (kws.length === 0) {
5239
5350
  console.log(`No key phrases found for "${project}".`);
@@ -5260,7 +5371,7 @@ async function importKeywords(project, filePath, format) {
5260
5371
  const content = fs2.readFileSync(filePath, "utf-8");
5261
5372
  const keywords = content.split("\n").map((line) => line.trim()).filter((line) => line.length > 0 && !line.startsWith("#"));
5262
5373
  if (keywords.length === 0) {
5263
- if (format === "json") {
5374
+ if (isMachineFormat(format)) {
5264
5375
  console.log(JSON.stringify({
5265
5376
  project,
5266
5377
  filePath,
@@ -5274,7 +5385,7 @@ async function importKeywords(project, filePath, format) {
5274
5385
  }
5275
5386
  const client = getClient10();
5276
5387
  await client.appendKeywords(project, keywords);
5277
- if (format === "json") {
5388
+ if (isMachineFormat(format)) {
5278
5389
  console.log(JSON.stringify({
5279
5390
  project,
5280
5391
  filePath,
@@ -5289,7 +5400,7 @@ async function generateKeywords(project, provider, opts) {
5289
5400
  const client = getClient10();
5290
5401
  const result = await client.generateKeywords(project, provider, opts.count);
5291
5402
  const saved = Boolean(opts.save && result.keywords.length > 0);
5292
- if (opts.format !== "json") {
5403
+ if (!isMachineFormat(opts.format)) {
5293
5404
  console.log(`Generated ${result.keywords.length} key phrase(s) using ${result.provider}:
5294
5405
  `);
5295
5406
  for (const kw of result.keywords) {
@@ -5302,12 +5413,12 @@ To add these, run: canonry keyword add ${project} <phrase>...`);
5302
5413
  }
5303
5414
  if (saved) {
5304
5415
  await client.appendKeywords(project, result.keywords);
5305
- if (opts.format !== "json") {
5416
+ if (!isMachineFormat(opts.format)) {
5306
5417
  console.log(`
5307
5418
  Saved ${result.keywords.length} key phrase(s) to "${project}".`);
5308
5419
  }
5309
5420
  }
5310
- if (opts.format === "json") {
5421
+ if (isMachineFormat(opts.format)) {
5311
5422
  console.log(JSON.stringify({
5312
5423
  project,
5313
5424
  provider: result.provider,
@@ -5465,7 +5576,7 @@ function getClient11() {
5465
5576
  async function addQueries(project, queries2, format) {
5466
5577
  const client = getClient11();
5467
5578
  await client.appendQueries(project, queries2);
5468
- if (format === "json") {
5579
+ if (isMachineFormat(format)) {
5469
5580
  console.log(JSON.stringify({
5470
5581
  project,
5471
5582
  queries: queries2,
@@ -5477,7 +5588,7 @@ async function addQueries(project, queries2, format) {
5477
5588
  }
5478
5589
  async function replaceQueries(project, queries2, opts) {
5479
5590
  const client = getClient11();
5480
- const isJson = opts?.format === "json";
5591
+ const isJson = isMachineFormat(opts?.format);
5481
5592
  if (opts?.dryRun) {
5482
5593
  const preview = await client.previewReplaceQueries(project, queries2);
5483
5594
  if (isJson) {
@@ -5517,7 +5628,7 @@ async function removeQueries(project, queries2, format) {
5517
5628
  const existingSet = new Set(existing.map((q) => q.query));
5518
5629
  const removedQueries = queries2.filter((q) => existingSet.has(q));
5519
5630
  await client.deleteQueries(project, queries2);
5520
- if (format === "json") {
5631
+ if (isMachineFormat(format)) {
5521
5632
  console.log(JSON.stringify({
5522
5633
  project,
5523
5634
  queries: queries2,
@@ -5534,6 +5645,9 @@ async function listQueries(project, format) {
5534
5645
  if (format === "json") {
5535
5646
  console.log(JSON.stringify(qs, null, 2));
5536
5647
  return;
5648
+ } else if (format === "jsonl") {
5649
+ emitJsonl(qs.map((q) => ({ project, ...q })));
5650
+ return;
5537
5651
  }
5538
5652
  if (qs.length === 0) {
5539
5653
  console.log(`No queries found for "${project}".`);
@@ -5560,7 +5674,7 @@ async function importQueries(project, filePath, format) {
5560
5674
  const content = fs3.readFileSync(filePath, "utf-8");
5561
5675
  const queries2 = content.split("\n").map((line) => line.trim()).filter((line) => line.length > 0 && !line.startsWith("#"));
5562
5676
  if (queries2.length === 0) {
5563
- if (format === "json") {
5677
+ if (isMachineFormat(format)) {
5564
5678
  console.log(JSON.stringify({
5565
5679
  project,
5566
5680
  filePath,
@@ -5574,7 +5688,7 @@ async function importQueries(project, filePath, format) {
5574
5688
  }
5575
5689
  const client = getClient11();
5576
5690
  await client.appendQueries(project, queries2);
5577
- if (format === "json") {
5691
+ if (isMachineFormat(format)) {
5578
5692
  console.log(JSON.stringify({
5579
5693
  project,
5580
5694
  filePath,
@@ -5589,7 +5703,7 @@ async function generateQueries(project, provider, opts) {
5589
5703
  const client = getClient11();
5590
5704
  const result = await client.generateQueries(project, provider, opts.count);
5591
5705
  const saved = Boolean(opts.save && result.queries.length > 0);
5592
- if (opts.format !== "json") {
5706
+ if (!isMachineFormat(opts.format)) {
5593
5707
  console.log(`Generated ${result.queries.length} ${result.queries.length === 1 ? "query" : "queries"} using ${result.provider}:
5594
5708
  `);
5595
5709
  for (const q of result.queries) {
@@ -5602,12 +5716,12 @@ To add these, run: canonry query add ${project} <query>...`);
5602
5716
  }
5603
5717
  if (saved) {
5604
5718
  await client.appendQueries(project, result.queries);
5605
- if (opts.format !== "json") {
5719
+ if (!isMachineFormat(opts.format)) {
5606
5720
  console.log(`
5607
5721
  Saved ${result.queries.length} ${result.queries.length === 1 ? "query" : "queries"} to "${project}".`);
5608
5722
  }
5609
5723
  }
5610
- if (opts.format === "json") {
5724
+ if (isMachineFormat(opts.format)) {
5611
5725
  console.log(JSON.stringify({
5612
5726
  project,
5613
5727
  provider: result.provider,
@@ -5986,7 +6100,7 @@ async function printMcpConfig(opts) {
5986
6100
  const serverName = opts.name?.trim() || "canonry";
5987
6101
  const entry = buildEntry({ binPath: opts.binPath, readOnly: opts.readOnly, platform: opts.platform });
5988
6102
  const snippet = renderClientSnippet(client, serverName, entry);
5989
- if (opts.format === "json") {
6103
+ if (isMachineFormat(opts.format)) {
5990
6104
  console.log(JSON.stringify({
5991
6105
  client: client.id,
5992
6106
  configPath: client.configPath(),
@@ -6000,7 +6114,7 @@ async function printMcpConfig(opts) {
6000
6114
  console.log(snippet);
6001
6115
  }
6002
6116
  function emitInstallResult(result, format) {
6003
- if (format === "json") {
6117
+ if (isMachineFormat(format)) {
6004
6118
  console.log(JSON.stringify(result, null, 2));
6005
6119
  return;
6006
6120
  }
@@ -6091,7 +6205,7 @@ async function addNotification(project, opts) {
6091
6205
  url: opts.webhook,
6092
6206
  events: opts.events
6093
6207
  });
6094
- if (opts.format === "json") {
6208
+ if (isMachineFormat(opts.format)) {
6095
6209
  console.log(JSON.stringify(result, null, 2));
6096
6210
  return;
6097
6211
  }
@@ -6104,6 +6218,9 @@ async function listNotifications(project, format) {
6104
6218
  if (format === "json") {
6105
6219
  console.log(JSON.stringify(results, null, 2));
6106
6220
  return;
6221
+ } else if (format === "jsonl") {
6222
+ emitJsonl(results);
6223
+ return;
6107
6224
  }
6108
6225
  if (results.length === 0) {
6109
6226
  console.log(`No notifications configured for "${project}"`);
@@ -6119,7 +6236,7 @@ async function listNotifications(project, format) {
6119
6236
  async function removeNotification(project, id, format) {
6120
6237
  const client = getClient12();
6121
6238
  await client.deleteNotification(project, id);
6122
- if (format === "json") {
6239
+ if (isMachineFormat(format)) {
6123
6240
  console.log(JSON.stringify({ project, id, removed: true }, null, 2));
6124
6241
  return;
6125
6242
  }
@@ -6128,7 +6245,7 @@ async function removeNotification(project, id, format) {
6128
6245
  async function testNotification(project, id, format) {
6129
6246
  const client = getClient12();
6130
6247
  const result = await client.testNotification(project, id);
6131
- if (format === "json") {
6248
+ if (isMachineFormat(format)) {
6132
6249
  console.log(JSON.stringify({ project, id, ...result }, null, 2));
6133
6250
  return;
6134
6251
  }
@@ -6148,8 +6265,12 @@ var EVENT_DESCRIPTIONS = {
6148
6265
  };
6149
6266
  function listEvents(format) {
6150
6267
  const events = notificationEventSchema.options;
6268
+ const catalog = events.map((e) => ({ event: e, description: EVENT_DESCRIPTIONS[e] ?? "" }));
6151
6269
  if (format === "json") {
6152
- console.log(JSON.stringify(events.map((e) => ({ event: e, description: EVENT_DESCRIPTIONS[e] ?? "" })), null, 2));
6270
+ console.log(JSON.stringify(catalog, null, 2));
6271
+ return;
6272
+ } else if (format === "jsonl") {
6273
+ emitJsonl(catalog);
6153
6274
  return;
6154
6275
  }
6155
6276
  console.log("Available notification events:\n");
@@ -6292,7 +6413,7 @@ async function applyConfigs(filePaths, format) {
6292
6413
  };
6293
6414
  }
6294
6415
  files.push(result);
6295
- if (format !== "json") {
6416
+ if (!isMachineFormat(format)) {
6296
6417
  for (const applied of result.applied) {
6297
6418
  console.log(`Applied config for "${applied.name}" (revision ${applied.configRevision})`);
6298
6419
  }
@@ -6311,7 +6432,7 @@ async function applyConfigs(filePaths, format) {
6311
6432
  details: summary
6312
6433
  });
6313
6434
  }
6314
- if (format === "json") {
6435
+ if (isMachineFormat(format)) {
6315
6436
  console.log(JSON.stringify(summary, null, 2));
6316
6437
  }
6317
6438
  }
@@ -6329,19 +6450,19 @@ async function showAnalytics(project, options) {
6329
6450
  case "metrics": {
6330
6451
  const data = await client.getAnalyticsMetrics(project, options.window);
6331
6452
  results.metrics = data;
6332
- if (options.format !== "json") printMetrics(data);
6453
+ if (!isMachineFormat(options.format)) printMetrics(data);
6333
6454
  break;
6334
6455
  }
6335
6456
  case "gaps": {
6336
6457
  const data = await client.getAnalyticsGaps(project, options.window);
6337
6458
  results.gaps = data;
6338
- if (options.format !== "json") printGaps(data);
6459
+ if (!isMachineFormat(options.format)) printGaps(data);
6339
6460
  break;
6340
6461
  }
6341
6462
  case "sources": {
6342
6463
  const data = await client.getAnalyticsSources(project, options.window);
6343
6464
  results.sources = data;
6344
- if (options.format !== "json") printSources(data);
6465
+ if (!isMachineFormat(options.format)) printSources(data);
6345
6466
  break;
6346
6467
  }
6347
6468
  default:
@@ -6356,7 +6477,7 @@ async function showAnalytics(project, options) {
6356
6477
  });
6357
6478
  }
6358
6479
  }
6359
- if (options.format === "json") {
6480
+ if (isMachineFormat(options.format)) {
6360
6481
  console.log(JSON.stringify(results, null, 2));
6361
6482
  }
6362
6483
  }
@@ -6437,6 +6558,13 @@ async function showEvidence(project, format) {
6437
6558
  }));
6438
6559
  console.log(JSON.stringify(enriched, null, 2));
6439
6560
  return;
6561
+ } else if (format === "jsonl") {
6562
+ emitJsonl(timeline.map((entry) => ({
6563
+ project,
6564
+ ...entry,
6565
+ cited: entry.runs[entry.runs.length - 1]?.citationState === CitationStates.cited
6566
+ })));
6567
+ return;
6440
6568
  }
6441
6569
  if (timeline.length === 0) {
6442
6570
  console.log('No query evidence yet. Trigger a run first with "canonry run".');
@@ -6466,7 +6594,7 @@ async function exportProject(project, opts) {
6466
6594
  const results = await loadLatestRunForExport(client, project);
6467
6595
  if (results) data.results = results;
6468
6596
  }
6469
- if (opts.format === "json") {
6597
+ if (isMachineFormat(opts.format)) {
6470
6598
  console.log(JSON.stringify(data, null, 2));
6471
6599
  return;
6472
6600
  }
@@ -6499,6 +6627,10 @@ async function showHistory(project, format) {
6499
6627
  console.log(JSON.stringify(entries, null, 2));
6500
6628
  return;
6501
6629
  }
6630
+ if (format === "jsonl") {
6631
+ emitJsonl(entries.map((entry) => ({ project, ...entry })));
6632
+ return;
6633
+ }
6502
6634
  if (entries.length === 0) {
6503
6635
  console.log(`No audit history for "${project}".`);
6504
6636
  return;
@@ -6534,7 +6666,7 @@ async function showStatus(project, format) {
6534
6666
  const client = getClient16();
6535
6667
  const projectData = await client.getProject(project);
6536
6668
  const latest = await getLatestRunSummary(client, project);
6537
- if (format === "json") {
6669
+ if (isMachineFormat(format)) {
6538
6670
  let runs = [];
6539
6671
  try {
6540
6672
  runs = await client.listRuns(project);
@@ -6675,7 +6807,7 @@ async function createProject(name, opts) {
6675
6807
  country: opts.country,
6676
6808
  language: opts.language
6677
6809
  });
6678
- if (opts.format === "json") {
6810
+ if (isMachineFormat(opts.format)) {
6679
6811
  console.log(JSON.stringify(result, null, 2));
6680
6812
  return;
6681
6813
  }
@@ -6688,6 +6820,10 @@ async function listProjects(format) {
6688
6820
  console.log(JSON.stringify(projects2, null, 2));
6689
6821
  return;
6690
6822
  }
6823
+ if (format === "jsonl") {
6824
+ emitJsonl(projects2);
6825
+ return;
6826
+ }
6691
6827
  if (projects2.length === 0) {
6692
6828
  console.log("No projects found.");
6693
6829
  return;
@@ -6712,7 +6848,7 @@ async function listProjects(format) {
6712
6848
  async function showProject(name, format) {
6713
6849
  const client = getClient17();
6714
6850
  const project = await client.getProject(name);
6715
- if (format === "json") {
6851
+ if (isMachineFormat(format)) {
6716
6852
  console.log(JSON.stringify(project, null, 2));
6717
6853
  return;
6718
6854
  }
@@ -6769,7 +6905,7 @@ async function updateProjectSettings(name, opts) {
6769
6905
  country: opts.country ?? project.country,
6770
6906
  language: opts.language ?? project.language
6771
6907
  });
6772
- if (opts.format === "json") {
6908
+ if (isMachineFormat(opts.format)) {
6773
6909
  console.log(JSON.stringify(result, null, 2));
6774
6910
  return;
6775
6911
  }
@@ -6777,7 +6913,7 @@ async function updateProjectSettings(name, opts) {
6777
6913
  }
6778
6914
  async function deleteProject(name, opts) {
6779
6915
  const client = getClient17();
6780
- const isJson = opts?.format === "json";
6916
+ const isJson = isMachineFormat(opts?.format);
6781
6917
  if (opts?.dryRun) {
6782
6918
  const preview = await client.previewProjectDelete(name);
6783
6919
  if (isJson) {
@@ -6814,7 +6950,7 @@ async function addLocation(project, opts) {
6814
6950
  country: opts.country,
6815
6951
  timezone: opts.timezone
6816
6952
  });
6817
- if (opts.format === "json") {
6953
+ if (isMachineFormat(opts.format)) {
6818
6954
  console.log(JSON.stringify(location, null, 2));
6819
6955
  return;
6820
6956
  }
@@ -6827,6 +6963,14 @@ async function listLocations(project, format) {
6827
6963
  console.log(JSON.stringify(result, null, 2));
6828
6964
  return;
6829
6965
  }
6966
+ if (format === "jsonl") {
6967
+ emitJsonl(result.locations.map((loc) => ({
6968
+ project,
6969
+ isDefault: loc.label === result.defaultLocation,
6970
+ ...loc
6971
+ })));
6972
+ return;
6973
+ }
6830
6974
  if (result.locations.length === 0) {
6831
6975
  console.log(`No locations configured for "${project}".`);
6832
6976
  return;
@@ -6849,7 +6993,7 @@ async function listLocations(project, format) {
6849
6993
  async function removeLocation(project, label, format) {
6850
6994
  const client = getClient17();
6851
6995
  await client.removeLocation(project, label);
6852
- if (format === "json") {
6996
+ if (isMachineFormat(format)) {
6853
6997
  console.log(JSON.stringify({ project, label, removed: true }, null, 2));
6854
6998
  return;
6855
6999
  }
@@ -6858,7 +7002,7 @@ async function removeLocation(project, label, format) {
6858
7002
  async function setDefaultLocation(project, label, format) {
6859
7003
  const client = getClient17();
6860
7004
  const result = await client.setDefaultLocation(project, label);
6861
- if (format === "json") {
7005
+ if (isMachineFormat(format)) {
6862
7006
  console.log(JSON.stringify({ project, ...result }, null, 2));
6863
7007
  return;
6864
7008
  }
@@ -7054,7 +7198,7 @@ async function runReportCommand(project, opts = {}) {
7054
7198
  const client = createApiClient();
7055
7199
  const report = await client.getReport(project);
7056
7200
  const audience = opts.audience ?? "agency";
7057
- if (opts.format === "json") {
7201
+ if (isMachineFormat(opts.format)) {
7058
7202
  console.log(JSON.stringify(report, null, 2));
7059
7203
  return;
7060
7204
  }
@@ -7127,7 +7271,7 @@ async function triggerRun(project, opts) {
7127
7271
  const response = await client.triggerRun(project, body);
7128
7272
  if (Array.isArray(response)) {
7129
7273
  const locationRuns = response;
7130
- if (opts?.format === "json") {
7274
+ if (isMachineFormat(opts?.format)) {
7131
7275
  if (opts?.wait) {
7132
7276
  const settled = await Promise.all(
7133
7277
  locationRuns.map(async (r) => {
@@ -7175,7 +7319,7 @@ async function triggerRun(project, opts) {
7175
7319
  if (opts?.wait && run.id && !TERMINAL_STATUSES.has(run.status)) {
7176
7320
  process.stderr.write(`Run ${run.id} started`);
7177
7321
  const result = await pollRun2(client, run.id);
7178
- if (opts?.format === "json") {
7322
+ if (isMachineFormat(opts?.format)) {
7179
7323
  console.log(JSON.stringify(result, null, 2));
7180
7324
  } else {
7181
7325
  process.stderr.write("\n");
@@ -7185,14 +7329,14 @@ async function triggerRun(project, opts) {
7185
7329
  }
7186
7330
  if (opts?.wait && (TERMINAL_STATUSES.has(run.status) || !run.id)) {
7187
7331
  const result = run.id ? await client.getRun(run.id) : run;
7188
- if (opts?.format === "json") {
7332
+ if (isMachineFormat(opts?.format)) {
7189
7333
  console.log(JSON.stringify(result, null, 2));
7190
7334
  } else {
7191
7335
  printRunDetail(result);
7192
7336
  }
7193
7337
  return;
7194
7338
  }
7195
- if (opts?.format === "json") {
7339
+ if (isMachineFormat(opts?.format)) {
7196
7340
  console.log(JSON.stringify(run, null, 2));
7197
7341
  return;
7198
7342
  }
@@ -7207,7 +7351,7 @@ async function triggerRunAll(opts) {
7207
7351
  const client = getClient18();
7208
7352
  const projects2 = await client.listProjects();
7209
7353
  if (projects2.length === 0) {
7210
- if (opts?.format === "json") {
7354
+ if (isMachineFormat(opts?.format)) {
7211
7355
  console.log("[]");
7212
7356
  } else {
7213
7357
  console.log("No projects found.");
@@ -7259,7 +7403,7 @@ async function triggerRunAll(opts) {
7259
7403
  process.stderr.write("\n");
7260
7404
  }
7261
7405
  }
7262
- if (opts?.format === "json") {
7406
+ if (isMachineFormat(opts?.format)) {
7263
7407
  console.log(JSON.stringify(results, null, 2));
7264
7408
  return;
7265
7409
  }
@@ -7312,7 +7456,7 @@ To cancel by ID : canonry run cancel ${project} <run-id>`,
7312
7456
  targetId = active.id;
7313
7457
  }
7314
7458
  const result = await client.cancelRun(targetId);
7315
- if (format === "json") {
7459
+ if (isMachineFormat(format)) {
7316
7460
  console.log(JSON.stringify(result, null, 2));
7317
7461
  return;
7318
7462
  }
@@ -7321,7 +7465,7 @@ To cancel by ID : canonry run cancel ${project} <run-id>`,
7321
7465
  async function showRun(id, format) {
7322
7466
  const client = getClient18();
7323
7467
  const run = await client.getRun(id);
7324
- if (format === "json") {
7468
+ if (isMachineFormat(format)) {
7325
7469
  console.log(JSON.stringify(run, null, 2));
7326
7470
  return;
7327
7471
  }
@@ -7333,6 +7477,9 @@ async function listRuns(project, opts) {
7333
7477
  if (opts?.format === "json") {
7334
7478
  console.log(JSON.stringify(runs, null, 2));
7335
7479
  return;
7480
+ } else if (opts?.format === "jsonl") {
7481
+ emitJsonl(runs.map((run) => ({ project, ...run })));
7482
+ return;
7336
7483
  }
7337
7484
  if (runs.length === 0) {
7338
7485
  console.log(`No runs found for "${project}".`);
@@ -7513,7 +7660,7 @@ async function setSchedule(project, opts) {
7513
7660
  if (opts.timezone) body.timezone = opts.timezone;
7514
7661
  if (opts.providers?.length) body.providers = opts.providers;
7515
7662
  const result = await client.putSchedule(project, body);
7516
- if (opts.format === "json") {
7663
+ if (isMachineFormat(opts.format)) {
7517
7664
  console.log(JSON.stringify(result, null, 2));
7518
7665
  return;
7519
7666
  }
@@ -7523,7 +7670,7 @@ async function setSchedule(project, opts) {
7523
7670
  async function showSchedule(project, format, kind) {
7524
7671
  const client = getClient19();
7525
7672
  const result = await client.getSchedule(project, kind);
7526
- if (format === "json") {
7673
+ if (isMachineFormat(format)) {
7527
7674
  console.log(JSON.stringify(result, null, 2));
7528
7675
  return;
7529
7676
  }
@@ -7538,7 +7685,7 @@ async function enableSchedule(project, format, kind) {
7538
7685
  if (current.providers.length) body.providers = current.providers;
7539
7686
  if (current.sourceId) body.sourceId = current.sourceId;
7540
7687
  const result = await client.putSchedule(project, body);
7541
- if (format === "json") {
7688
+ if (isMachineFormat(format)) {
7542
7689
  console.log(JSON.stringify(result, null, 2));
7543
7690
  return;
7544
7691
  }
@@ -7553,7 +7700,7 @@ async function disableSchedule(project, format, kind) {
7553
7700
  if (current.providers.length) body.providers = current.providers;
7554
7701
  if (current.sourceId) body.sourceId = current.sourceId;
7555
7702
  const result = await client.putSchedule(project, body);
7556
- if (format === "json") {
7703
+ if (isMachineFormat(format)) {
7557
7704
  console.log(JSON.stringify(result, null, 2));
7558
7705
  return;
7559
7706
  }
@@ -7563,7 +7710,7 @@ async function removeSchedule(project, format, kind) {
7563
7710
  const client = getClient19();
7564
7711
  await client.deleteSchedule(project, kind);
7565
7712
  const resolvedKind = kind ?? "answer-visibility";
7566
- if (format === "json") {
7713
+ if (isMachineFormat(format)) {
7567
7714
  console.log(JSON.stringify({ project, kind: resolvedKind, removed: true }, null, 2));
7568
7715
  return;
7569
7716
  }
@@ -7685,7 +7832,7 @@ async function setProvider(name, opts) {
7685
7832
  const client = getClient20();
7686
7833
  const { format, ...payload } = opts;
7687
7834
  const result = await client.updateProvider(name, payload);
7688
- if (format === "json") {
7835
+ if (isMachineFormat(format)) {
7689
7836
  console.log(JSON.stringify(result, null, 2));
7690
7837
  return;
7691
7838
  }
@@ -7701,7 +7848,7 @@ async function showSettings(format) {
7701
7848
  const client = getClient20();
7702
7849
  const config = loadConfig();
7703
7850
  const settings = await client.getSettings();
7704
- if (format === "json") {
7851
+ if (isMachineFormat(format)) {
7705
7852
  console.log(JSON.stringify({
7706
7853
  ...settings,
7707
7854
  google: {
@@ -7732,7 +7879,7 @@ function setGoogleAuth(opts) {
7732
7879
  clientSecret: opts.clientSecret
7733
7880
  });
7734
7881
  saveConfigPatch(config);
7735
- if (opts.format === "json") {
7882
+ if (isMachineFormat(opts.format)) {
7736
7883
  console.log(JSON.stringify({
7737
7884
  configured: true,
7738
7885
  configPath: getConfigPath(),
@@ -8273,7 +8420,7 @@ async function createSnapshotReport(companyName, opts) {
8273
8420
  const pdfPath = opts.outputPath && !opts.md ? opts.outputPath : autoOutputPath(companyName, "pdf");
8274
8421
  savedPdfPath = await writeSnapshotPdf(report, pdfPath);
8275
8422
  }
8276
- if (opts.format === "json") {
8423
+ if (isMachineFormat(opts.format)) {
8277
8424
  console.log(JSON.stringify(report, null, 2));
8278
8425
  if (savedMdPath) process.stderr.write(`Saved markdown: ${savedMdPath}
8279
8426
  `);
@@ -8481,6 +8628,10 @@ async function listInsights(project, opts) {
8481
8628
  console.log(JSON.stringify(insights, null, 2));
8482
8629
  return;
8483
8630
  }
8631
+ if (opts.format === "jsonl") {
8632
+ emitJsonl(insights.map((insight) => ({ project, ...insight })));
8633
+ return;
8634
+ }
8484
8635
  if (insights.length === 0) {
8485
8636
  console.log("No insights found.");
8486
8637
  return;
@@ -8502,7 +8653,7 @@ async function listInsights(project, opts) {
8502
8653
  async function dismissInsight(project, id, opts) {
8503
8654
  const client = createApiClient();
8504
8655
  const result = await client.dismissInsight(project, id);
8505
- if (opts.format === "json") {
8656
+ if (isMachineFormat(opts.format)) {
8506
8657
  console.log(JSON.stringify(result, null, 2));
8507
8658
  return;
8508
8659
  }
@@ -8517,6 +8668,9 @@ async function showHealth(project, opts) {
8517
8668
  if (opts.format === "json") {
8518
8669
  console.log(JSON.stringify(snapshots, null, 2));
8519
8670
  return;
8671
+ } else if (opts.format === "jsonl") {
8672
+ emitJsonl(snapshots.map((snap) => ({ project, ...snap })));
8673
+ return;
8520
8674
  }
8521
8675
  if (snapshots.length === 0) {
8522
8676
  console.log("No health history available.");
@@ -8533,7 +8687,7 @@ async function showHealth(project, opts) {
8533
8687
  return;
8534
8688
  }
8535
8689
  const health = await client.getHealth(project);
8536
- if (opts.format === "json") {
8690
+ if (opts.format === "json" || opts.format === "jsonl") {
8537
8691
  console.log(JSON.stringify(health, null, 2));
8538
8692
  return;
8539
8693
  }
@@ -8560,7 +8714,7 @@ async function showOverview(project, opts) {
8560
8714
  location: opts.location,
8561
8715
  since: opts.since
8562
8716
  });
8563
- if (opts.format === "json") {
8717
+ if (isMachineFormat(opts.format)) {
8564
8718
  console.log(JSON.stringify(overview, null, 2));
8565
8719
  return;
8566
8720
  }
@@ -8570,7 +8724,7 @@ async function showAllOverviews(opts) {
8570
8724
  const client = createApiClient();
8571
8725
  const projects2 = await client.listProjects();
8572
8726
  if (projects2.length === 0) {
8573
- if (opts.format === "json") {
8727
+ if (isMachineFormat(opts.format)) {
8574
8728
  console.log("[]");
8575
8729
  return;
8576
8730
  }
@@ -8582,7 +8736,7 @@ async function showAllOverviews(opts) {
8582
8736
  (p) => client.getProjectOverview(p.name, { location: opts.location, since: opts.since })
8583
8737
  )
8584
8738
  );
8585
- if (opts.format === "json") {
8739
+ if (isMachineFormat(opts.format)) {
8586
8740
  console.log(JSON.stringify(overviews, null, 2));
8587
8741
  return;
8588
8742
  }
@@ -8739,7 +8893,7 @@ function pct(value) {
8739
8893
  async function searchProject(project, opts) {
8740
8894
  const client = createApiClient();
8741
8895
  const result = await client.searchProject(project, { q: opts.query, limit: opts.limit });
8742
- if (opts.format === "json") {
8896
+ if (isMachineFormat(opts.format)) {
8743
8897
  console.log(JSON.stringify(result, null, 2));
8744
8898
  return;
8745
8899
  }
@@ -8969,6 +9123,16 @@ async function listContentTargets(project, opts) {
8969
9123
  console.log(JSON.stringify(response, null, 2));
8970
9124
  return;
8971
9125
  }
9126
+ if (opts.format === "jsonl") {
9127
+ emitJsonl(
9128
+ response.targets.map((target) => ({
9129
+ project,
9130
+ latestRunId: response.contextMetrics.latestRunId,
9131
+ ...target
9132
+ }))
9133
+ );
9134
+ return;
9135
+ }
8972
9136
  if (response.targets.length === 0) {
8973
9137
  console.log("No content targets surfaced. (Run `canonry run` to generate fresh signal.)");
8974
9138
  return;
@@ -9005,6 +9169,10 @@ async function listContentSources(project, opts) {
9005
9169
  console.log(JSON.stringify(response, null, 2));
9006
9170
  return;
9007
9171
  }
9172
+ if (opts.format === "jsonl") {
9173
+ emitJsonl(response.sources.map((row) => ({ project, ...row })));
9174
+ return;
9175
+ }
9008
9176
  if (response.sources.length === 0) {
9009
9177
  console.log("No grounding sources captured yet.");
9010
9178
  return;
@@ -9029,6 +9197,10 @@ async function listContentGaps(project, opts) {
9029
9197
  console.log(JSON.stringify(response, null, 2));
9030
9198
  return;
9031
9199
  }
9200
+ if (opts.format === "jsonl") {
9201
+ emitJsonl(response.gaps.map((gap) => ({ project, ...gap })));
9202
+ return;
9203
+ }
9032
9204
  if (response.gaps.length === 0) {
9033
9205
  console.log("No competitor-only-cited queries detected.");
9034
9206
  return;
@@ -9381,7 +9553,7 @@ async function startDaemon(opts) {
9381
9553
  fs9.writeFileSync(pidPath, String(child.pid), "utf-8");
9382
9554
  const port = opts.port ?? "4100";
9383
9555
  const host = opts.host ?? "127.0.0.1";
9384
- if (format !== "json") {
9556
+ if (!isMachineFormat(format)) {
9385
9557
  process.stderr.write("Waiting for server to start...");
9386
9558
  }
9387
9559
  const ready = await waitForReady(host, port);
@@ -9401,11 +9573,11 @@ async function startDaemon(opts) {
9401
9573
  }
9402
9574
  });
9403
9575
  }
9404
- if (format !== "json") {
9576
+ if (!isMachineFormat(format)) {
9405
9577
  process.stderr.write("\n");
9406
9578
  }
9407
9579
  const url = `http://${host === "0.0.0.0" ? "localhost" : host}:${port}`;
9408
- if (format === "json") {
9580
+ if (isMachineFormat(format)) {
9409
9581
  console.log(JSON.stringify({
9410
9582
  started: true,
9411
9583
  pid: child.pid,
@@ -9420,7 +9592,7 @@ async function startDaemon(opts) {
9420
9592
  function stopDaemon(format = "text") {
9421
9593
  const pidPath = getPidPath();
9422
9594
  if (!fs9.existsSync(pidPath)) {
9423
- if (format === "json") {
9595
+ if (isMachineFormat(format)) {
9424
9596
  console.log(JSON.stringify({
9425
9597
  stopped: false,
9426
9598
  reason: "not_running"
@@ -9432,7 +9604,7 @@ function stopDaemon(format = "text") {
9432
9604
  }
9433
9605
  const pid = parseInt(fs9.readFileSync(pidPath, "utf-8").trim(), 10);
9434
9606
  if (isNaN(pid)) {
9435
- if (format === "json") {
9607
+ if (isMachineFormat(format)) {
9436
9608
  console.log(JSON.stringify({
9437
9609
  stopped: false,
9438
9610
  reason: "invalid_pid",
@@ -9445,7 +9617,7 @@ function stopDaemon(format = "text") {
9445
9617
  return;
9446
9618
  }
9447
9619
  if (!isProcessAlive(pid)) {
9448
- if (format === "json") {
9620
+ if (isMachineFormat(format)) {
9449
9621
  console.log(JSON.stringify({
9450
9622
  stopped: false,
9451
9623
  reason: "stale_pid",
@@ -9461,7 +9633,7 @@ function stopDaemon(format = "text") {
9461
9633
  try {
9462
9634
  process.kill(pid, "SIGTERM");
9463
9635
  fs9.unlinkSync(pidPath);
9464
- if (format === "json") {
9636
+ if (isMachineFormat(format)) {
9465
9637
  console.log(JSON.stringify({
9466
9638
  stopped: true,
9467
9639
  pid
@@ -9521,11 +9693,11 @@ var DEFAULT_AGENT_MODELS = {
9521
9693
  };
9522
9694
  async function initCommand(opts) {
9523
9695
  const format = opts?.format ?? "text";
9524
- if (format !== "json") {
9696
+ if (!isMachineFormat(format)) {
9525
9697
  console.log("Initializing canonry...\n");
9526
9698
  }
9527
9699
  if (configExists() && !opts?.force) {
9528
- if (format === "json") {
9700
+ if (isMachineFormat(format)) {
9529
9701
  console.log(JSON.stringify({
9530
9702
  initialized: false,
9531
9703
  reason: "config_exists",
@@ -9567,7 +9739,7 @@ async function initCommand(opts) {
9567
9739
  const nonInteractive = !!(envProviders.gemini || envProviders.openai || envProviders.claude || envProviders.perplexity || envProviders.local || envGoogleConfigured);
9568
9740
  const providers = {};
9569
9741
  let google;
9570
- if (format === "json" && !nonInteractive) {
9742
+ if (isMachineFormat(format) && !nonInteractive) {
9571
9743
  throw new CliError({
9572
9744
  code: "INIT_JSON_REQUIRES_NON_INTERACTIVE",
9573
9745
  message: "--format json requires non-interactive provider configuration via flags or environment variables.",
@@ -9708,7 +9880,7 @@ async function initCommand(opts) {
9708
9880
  }
9709
9881
  }
9710
9882
  const nextSteps = buildNextSteps();
9711
- if (format === "json") {
9883
+ if (isMachineFormat(format)) {
9712
9884
  console.log(JSON.stringify({
9713
9885
  initialized: true,
9714
9886
  configPath: getConfigPath(),
@@ -9767,7 +9939,7 @@ ${mcpTip}`);
9767
9939
  agentLLM = { provider, key, model };
9768
9940
  }
9769
9941
  }
9770
- if (format !== "json") {
9942
+ if (!isMachineFormat(format)) {
9771
9943
  showFirstRunNotice();
9772
9944
  console.log("\nNext steps:");
9773
9945
  for (const line of nextSteps) {
@@ -9871,7 +10043,7 @@ Received ${signal}, stopping server...`);
9871
10043
  try {
9872
10044
  await app.listen({ host, port });
9873
10045
  const url = `http://${host === "0.0.0.0" ? "localhost" : host}:${port}`;
9874
- if (format === "json") {
10046
+ if (isMachineFormat(format)) {
9875
10047
  console.log(JSON.stringify({
9876
10048
  started: true,
9877
10049
  host,
@@ -9919,7 +10091,7 @@ function telemetryCommand(subcommand, format = "text") {
9919
10091
  if (process.env.CANONRY_TELEMETRY_DISABLED === "1") {
9920
10092
  payload.enabled = false;
9921
10093
  payload.reason = "CANONRY_TELEMETRY_DISABLED";
9922
- if (format === "json") {
10094
+ if (isMachineFormat(format)) {
9923
10095
  console.log(JSON.stringify(payload, null, 2));
9924
10096
  return;
9925
10097
  }
@@ -9929,7 +10101,7 @@ function telemetryCommand(subcommand, format = "text") {
9929
10101
  if (process.env.DO_NOT_TRACK === "1") {
9930
10102
  payload.enabled = false;
9931
10103
  payload.reason = "DO_NOT_TRACK";
9932
- if (format === "json") {
10104
+ if (isMachineFormat(format)) {
9933
10105
  console.log(JSON.stringify(payload, null, 2));
9934
10106
  return;
9935
10107
  }
@@ -9939,7 +10111,7 @@ function telemetryCommand(subcommand, format = "text") {
9939
10111
  if (process.env.CI) {
9940
10112
  payload.enabled = false;
9941
10113
  payload.reason = "CI";
9942
- if (format === "json") {
10114
+ if (isMachineFormat(format)) {
9943
10115
  console.log(JSON.stringify(payload, null, 2));
9944
10116
  return;
9945
10117
  }
@@ -9948,7 +10120,7 @@ function telemetryCommand(subcommand, format = "text") {
9948
10120
  }
9949
10121
  if (!configExists()) {
9950
10122
  payload.reason = "NO_CONFIG";
9951
- if (format === "json") {
10123
+ if (isMachineFormat(format)) {
9952
10124
  console.log(JSON.stringify(payload, null, 2));
9953
10125
  return;
9954
10126
  }
@@ -9961,7 +10133,7 @@ function telemetryCommand(subcommand, format = "text") {
9961
10133
  if (config.anonymousId) {
9962
10134
  payload.anonymousIdMasked = config.anonymousId.slice(0, 8) + "...";
9963
10135
  }
9964
- if (format === "json") {
10136
+ if (isMachineFormat(format)) {
9965
10137
  console.log(JSON.stringify(payload, null, 2));
9966
10138
  return;
9967
10139
  }
@@ -9987,7 +10159,7 @@ function telemetryCommand(subcommand, format = "text") {
9987
10159
  const config = loadConfig();
9988
10160
  config.telemetry = true;
9989
10161
  saveConfigPatch(config);
9990
- if (format === "json") {
10162
+ if (isMachineFormat(format)) {
9991
10163
  console.log(JSON.stringify({
9992
10164
  enabled: true,
9993
10165
  configPath: getConfigPath()
@@ -10011,7 +10183,7 @@ function telemetryCommand(subcommand, format = "text") {
10011
10183
  const config = loadConfig();
10012
10184
  config.telemetry = false;
10013
10185
  saveConfigPatch(config);
10014
- if (format === "json") {
10186
+ if (isMachineFormat(format)) {
10015
10187
  console.log(JSON.stringify({
10016
10188
  enabled: false,
10017
10189
  configPath: getConfigPath()
@@ -10335,7 +10507,7 @@ async function wordpressConnect(project, opts) {
10335
10507
  appPassword,
10336
10508
  defaultEnv: opts.defaultEnv
10337
10509
  });
10338
- if (opts.format === "json") {
10510
+ if (isMachineFormat(opts.format)) {
10339
10511
  printJson2(result);
10340
10512
  return;
10341
10513
  }
@@ -10346,7 +10518,7 @@ async function wordpressConnect(project, opts) {
10346
10518
  async function wordpressDisconnect(project, format) {
10347
10519
  const client = getClient22();
10348
10520
  await client.wordpressDisconnect(project);
10349
- if (format === "json") {
10521
+ if (isMachineFormat(format)) {
10350
10522
  printJson2({ project, disconnected: true });
10351
10523
  return;
10352
10524
  }
@@ -10355,7 +10527,7 @@ async function wordpressDisconnect(project, format) {
10355
10527
  async function wordpressStatus(project, format) {
10356
10528
  const client = getClient22();
10357
10529
  const result = await client.wordpressStatus(project);
10358
- if (format === "json") {
10530
+ if (isMachineFormat(format)) {
10359
10531
  printJson2(result);
10360
10532
  return;
10361
10533
  }
@@ -10364,7 +10536,7 @@ async function wordpressStatus(project, format) {
10364
10536
  async function wordpressPages(project, opts) {
10365
10537
  const client = getClient22();
10366
10538
  const result = await client.wordpressPages(project, opts.env);
10367
- if (opts.format === "json") {
10539
+ if (isMachineFormat(opts.format)) {
10368
10540
  printJson2(result);
10369
10541
  return;
10370
10542
  }
@@ -10373,7 +10545,7 @@ async function wordpressPages(project, opts) {
10373
10545
  async function wordpressPage(project, slug, opts) {
10374
10546
  const client = getClient22();
10375
10547
  const result = await client.wordpressPage(project, slug, opts.env);
10376
- if (opts.format === "json") {
10548
+ if (isMachineFormat(opts.format)) {
10377
10549
  printJson2(result);
10378
10550
  return;
10379
10551
  }
@@ -10382,7 +10554,7 @@ async function wordpressPage(project, slug, opts) {
10382
10554
  async function wordpressCreatePage(project, body) {
10383
10555
  const client = getClient22();
10384
10556
  const result = await client.wordpressCreatePage(project, body);
10385
- if (body.format === "json") {
10557
+ if (isMachineFormat(body.format)) {
10386
10558
  printJson2(result);
10387
10559
  return;
10388
10560
  }
@@ -10393,7 +10565,7 @@ async function wordpressCreatePage(project, body) {
10393
10565
  async function wordpressUpdatePage(project, body) {
10394
10566
  const client = getClient22();
10395
10567
  const result = await client.wordpressUpdatePage(project, body);
10396
- if (body.format === "json") {
10568
+ if (isMachineFormat(body.format)) {
10397
10569
  printJson2(result);
10398
10570
  return;
10399
10571
  }
@@ -10404,7 +10576,7 @@ async function wordpressUpdatePage(project, body) {
10404
10576
  async function wordpressSetMeta(project, body) {
10405
10577
  const client = getClient22();
10406
10578
  const result = await client.wordpressSetMeta(project, body);
10407
- if (body.format === "json") {
10579
+ if (isMachineFormat(body.format)) {
10408
10580
  printJson2(result);
10409
10581
  return;
10410
10582
  }
@@ -10454,7 +10626,7 @@ async function wordpressBulkSetMeta(project, opts) {
10454
10626
  }
10455
10627
  const client = getClient22();
10456
10628
  const result = await client.wordpressBulkSetMeta(project, { entries, env: opts.env });
10457
- if (opts.format === "json") {
10629
+ if (isMachineFormat(opts.format)) {
10458
10630
  printJson2(result);
10459
10631
  return;
10460
10632
  }
@@ -10497,7 +10669,7 @@ Total: ${applied.length} applied, ${skipped.length} skipped, ${manual.length} ma
10497
10669
  async function wordpressSchema(project, slug, opts) {
10498
10670
  const client = getClient22();
10499
10671
  const result = await client.wordpressSchema(project, slug, opts.env);
10500
- if (opts.format === "json") {
10672
+ if (isMachineFormat(opts.format)) {
10501
10673
  printJson2(result);
10502
10674
  return;
10503
10675
  }
@@ -10508,7 +10680,7 @@ async function wordpressSchema(project, slug, opts) {
10508
10680
  async function wordpressSetSchema(project, body) {
10509
10681
  const client = getClient22();
10510
10682
  const result = await client.wordpressSetSchema(project, body);
10511
- if (body.format === "json") {
10683
+ if (isMachineFormat(body.format)) {
10512
10684
  printJson2(result);
10513
10685
  return;
10514
10686
  }
@@ -10556,7 +10728,7 @@ async function wordpressSchemaDeploy(project, opts) {
10556
10728
  }
10557
10729
  const client = getClient22();
10558
10730
  const result = await client.wordpressSchemaDeploy(project, { profile: parsed, env: opts.env });
10559
- if (opts.format === "json") {
10731
+ if (isMachineFormat(opts.format)) {
10560
10732
  printJson2(result);
10561
10733
  return;
10562
10734
  }
@@ -10595,7 +10767,7 @@ Total: ${deployed} deployed, ${stripped} stripped, ${skipped} skipped, ${failed}
10595
10767
  async function wordpressSchemaStatus(project, opts) {
10596
10768
  const client = getClient22();
10597
10769
  const result = await client.wordpressSchemaStatus(project, opts.env);
10598
- if (opts.format === "json") {
10770
+ if (isMachineFormat(opts.format)) {
10599
10771
  printJson2(result);
10600
10772
  return;
10601
10773
  }
@@ -10663,7 +10835,7 @@ async function wordpressOnboard(project, opts) {
10663
10835
  skipSchema: opts.skipSchema,
10664
10836
  skipSubmit: opts.skipSubmit
10665
10837
  });
10666
- if (opts.format === "json") {
10838
+ if (isMachineFormat(opts.format)) {
10667
10839
  printJson2(result);
10668
10840
  return;
10669
10841
  }
@@ -10679,7 +10851,7 @@ async function wordpressOnboard(project, opts) {
10679
10851
  async function wordpressLlmsTxt(project, opts) {
10680
10852
  const client = getClient22();
10681
10853
  const result = await client.wordpressLlmsTxt(project, opts.env);
10682
- if (opts.format === "json") {
10854
+ if (isMachineFormat(opts.format)) {
10683
10855
  printJson2(result);
10684
10856
  return;
10685
10857
  }
@@ -10690,7 +10862,7 @@ async function wordpressLlmsTxt(project, opts) {
10690
10862
  async function wordpressSetLlmsTxt(project, body) {
10691
10863
  const client = getClient22();
10692
10864
  const result = await client.wordpressSetLlmsTxt(project, body);
10693
- if (body.format === "json") {
10865
+ if (isMachineFormat(body.format)) {
10694
10866
  printJson2(result);
10695
10867
  return;
10696
10868
  }
@@ -10699,7 +10871,7 @@ async function wordpressSetLlmsTxt(project, body) {
10699
10871
  async function wordpressAudit(project, opts) {
10700
10872
  const client = getClient22();
10701
10873
  const result = await client.wordpressAudit(project, opts.env);
10702
- if (opts.format === "json") {
10874
+ if (isMachineFormat(opts.format)) {
10703
10875
  printJson2(result);
10704
10876
  return;
10705
10877
  }
@@ -10713,7 +10885,7 @@ async function wordpressAudit(project, opts) {
10713
10885
  async function wordpressDiff(project, slug, format) {
10714
10886
  const client = getClient22();
10715
10887
  const result = await client.wordpressDiff(project, slug);
10716
- if (format === "json") {
10888
+ if (isMachineFormat(format)) {
10717
10889
  printJson2(result);
10718
10890
  return;
10719
10891
  }
@@ -10722,7 +10894,7 @@ async function wordpressDiff(project, slug, format) {
10722
10894
  async function wordpressStagingStatus(project, format) {
10723
10895
  const client = getClient22();
10724
10896
  const result = await client.wordpressStagingStatus(project);
10725
- if (format === "json") {
10897
+ if (isMachineFormat(format)) {
10726
10898
  printJson2(result);
10727
10899
  return;
10728
10900
  }
@@ -10736,7 +10908,7 @@ async function wordpressStagingStatus(project, format) {
10736
10908
  async function wordpressStagingPush(project, format) {
10737
10909
  const client = getClient22();
10738
10910
  const result = await client.wordpressStagingPush(project);
10739
- if (format === "json") {
10911
+ if (isMachineFormat(format)) {
10740
10912
  printJson2(result);
10741
10913
  return;
10742
10914
  }
@@ -11222,7 +11394,7 @@ async function agentAttach(opts) {
11222
11394
  const existing = await client.listNotifications(opts.project);
11223
11395
  const hasAgent = existing.some((n) => n.source === "agent");
11224
11396
  if (hasAgent) {
11225
- if (opts.format === "json") {
11397
+ if (isMachineFormat(opts.format)) {
11226
11398
  console.log(JSON.stringify({ status: "already-attached", project: opts.project }));
11227
11399
  } else {
11228
11400
  console.log(`Agent webhook already attached to "${opts.project}"`);
@@ -11235,7 +11407,7 @@ async function agentAttach(opts) {
11235
11407
  events: [...AGENT_WEBHOOK_EVENTS],
11236
11408
  source: "agent"
11237
11409
  });
11238
- if (opts.format === "json") {
11410
+ if (isMachineFormat(opts.format)) {
11239
11411
  console.log(JSON.stringify({ status: "attached", project: opts.project, notificationId: result.id }));
11240
11412
  } else {
11241
11413
  console.log(`Agent webhook attached to "${opts.project}" (${opts.url})`);
@@ -11246,7 +11418,7 @@ async function agentDetach(opts) {
11246
11418
  const existing = await client.listNotifications(opts.project);
11247
11419
  const agentNotif = existing.find((n) => n.source === "agent");
11248
11420
  if (!agentNotif) {
11249
- if (opts.format === "json") {
11421
+ if (isMachineFormat(opts.format)) {
11250
11422
  console.log(JSON.stringify({ status: "not-attached", project: opts.project }));
11251
11423
  } else {
11252
11424
  console.log(`No agent webhook found on "${opts.project}"`);
@@ -11254,7 +11426,7 @@ async function agentDetach(opts) {
11254
11426
  return;
11255
11427
  }
11256
11428
  await client.deleteNotification(opts.project, agentNotif.id);
11257
- if (opts.format === "json") {
11429
+ if (isMachineFormat(opts.format)) {
11258
11430
  console.log(JSON.stringify({ status: "detached", project: opts.project }));
11259
11431
  } else {
11260
11432
  console.log(`Agent webhook detached from "${opts.project}"`);
@@ -11262,9 +11434,14 @@ async function agentDetach(opts) {
11262
11434
  }
11263
11435
 
11264
11436
  // src/commands/agent-ask.ts
11437
+ function toFormat2(raw) {
11438
+ if (raw === "json") return "json";
11439
+ if (raw === "jsonl") return "jsonl";
11440
+ return "text";
11441
+ }
11265
11442
  async function agentAsk(opts) {
11266
- const format = opts.format === "json" ? "json" : "text";
11267
- const isJson = format === "json";
11443
+ const format = toFormat2(opts.format);
11444
+ const isJson = isMachineFormat(format);
11268
11445
  const controller = new AbortController();
11269
11446
  const onSigint = () => controller.abort();
11270
11447
  process.on("SIGINT", onSigint);
@@ -11369,13 +11546,22 @@ function renderEvent(event, isJson) {
11369
11546
 
11370
11547
  // src/commands/agent-providers.ts
11371
11548
  async function agentProviders(opts) {
11372
- const format = opts.format === "json" ? "json" : "text";
11549
+ const format = opts.format === "json" ? "json" : opts.format === "jsonl" ? "jsonl" : "text";
11373
11550
  try {
11374
11551
  const client = createApiClient();
11375
11552
  const res = await client.listAgentProviders(opts.project);
11376
11553
  if (format === "json") {
11377
11554
  console.log(JSON.stringify(res, null, 2));
11378
11555
  return;
11556
+ } else if (format === "jsonl") {
11557
+ emitJsonl(
11558
+ res.providers.map((provider) => ({
11559
+ project: opts.project,
11560
+ defaultProvider: res.defaultProvider,
11561
+ ...provider
11562
+ }))
11563
+ );
11564
+ return;
11379
11565
  }
11380
11566
  console.log(
11381
11567
  `Aero providers for ${opts.project} (default: ${res.defaultProvider ?? "none configured"})
@@ -11397,12 +11583,17 @@ async function agentProviders(opts) {
11397
11583
  }
11398
11584
 
11399
11585
  // src/commands/agent-transcript.ts
11586
+ function toFormat3(raw) {
11587
+ if (raw === "json") return "json";
11588
+ if (raw === "jsonl") return "jsonl";
11589
+ return "text";
11590
+ }
11400
11591
  async function agentTranscript(opts) {
11401
- const format = opts.format === "json" ? "json" : "text";
11592
+ const format = toFormat3(opts.format);
11402
11593
  try {
11403
11594
  const client = createApiClient();
11404
11595
  const transcript = await client.getAgentTranscript(opts.project);
11405
- if (format === "json") {
11596
+ if (isMachineFormat(format)) {
11406
11597
  console.log(JSON.stringify(transcript, null, 2));
11407
11598
  return;
11408
11599
  }
@@ -11436,11 +11627,11 @@ async function agentTranscript(opts) {
11436
11627
  }
11437
11628
  }
11438
11629
  async function agentTranscriptReset(opts) {
11439
- const format = opts.format === "json" ? "json" : "text";
11630
+ const format = toFormat3(opts.format);
11440
11631
  try {
11441
11632
  const client = createApiClient();
11442
11633
  await client.resetAgentTranscript(opts.project);
11443
- if (format === "json") {
11634
+ if (isMachineFormat(format)) {
11444
11635
  console.log(JSON.stringify({ status: "reset", project: opts.project }));
11445
11636
  } else {
11446
11637
  console.log(`Aero conversation reset for "${opts.project}".`);
@@ -11453,17 +11644,22 @@ async function agentTranscriptReset(opts) {
11453
11644
  }
11454
11645
 
11455
11646
  // src/commands/agent-memory.ts
11456
- function toFormat2(raw) {
11457
- return raw === "json" ? "json" : "text";
11647
+ function toFormat4(raw) {
11648
+ if (raw === "json") return "json";
11649
+ if (raw === "jsonl") return "jsonl";
11650
+ return "text";
11458
11651
  }
11459
11652
  async function agentMemoryList(opts) {
11460
- const format = toFormat2(opts.format);
11653
+ const format = toFormat4(opts.format);
11461
11654
  try {
11462
11655
  const client = createApiClient();
11463
11656
  const result = await client.listAgentMemory(opts.project);
11464
11657
  if (format === "json") {
11465
11658
  console.log(JSON.stringify(result, null, 2));
11466
11659
  return;
11660
+ } else if (format === "jsonl") {
11661
+ emitJsonl(result.entries.map((entry) => ({ project: opts.project, ...entry })));
11662
+ return;
11467
11663
  }
11468
11664
  if (result.entries.length === 0) {
11469
11665
  console.log(`No Aero memory notes for "${opts.project}".`);
@@ -11482,14 +11678,14 @@ async function agentMemoryList(opts) {
11482
11678
  }
11483
11679
  }
11484
11680
  async function agentMemorySet(opts) {
11485
- const format = toFormat2(opts.format);
11681
+ const format = toFormat4(opts.format);
11486
11682
  try {
11487
11683
  const client = createApiClient();
11488
11684
  const result = await client.setAgentMemory(opts.project, {
11489
11685
  key: opts.key,
11490
11686
  value: opts.value
11491
11687
  });
11492
- if (format === "json") {
11688
+ if (isMachineFormat(format)) {
11493
11689
  console.log(JSON.stringify(result, null, 2));
11494
11690
  return;
11495
11691
  }
@@ -11500,11 +11696,11 @@ async function agentMemorySet(opts) {
11500
11696
  }
11501
11697
  }
11502
11698
  async function agentMemoryForget(opts) {
11503
- const format = toFormat2(opts.format);
11699
+ const format = toFormat4(opts.format);
11504
11700
  try {
11505
11701
  const client = createApiClient();
11506
11702
  const result = await client.forgetAgentMemory(opts.project, opts.key);
11507
- if (format === "json") {
11703
+ if (isMachineFormat(format)) {
11508
11704
  console.log(JSON.stringify(result, null, 2));
11509
11705
  return;
11510
11706
  }
@@ -11788,7 +11984,8 @@ Admin:
11788
11984
  history <project> Show audit trail
11789
11985
 
11790
11986
  Global options:
11791
- --format json Machine-readable output (all commands)
11987
+ --format json Machine-readable output: one JSON document (all commands)
11988
+ --format jsonl Machine-readable output: one record per line, no jq needed
11792
11989
  --help, -h Show help (use with any command group)
11793
11990
  --version, -v Show version
11794
11991
 
@@ -11798,7 +11995,9 @@ var _require2 = createRequire2(import.meta.url);
11798
11995
  var { version: VERSION } = _require2("../package.json");
11799
11996
  function extractFormat(cmdArgs) {
11800
11997
  const idx = cmdArgs.indexOf("--format");
11801
- if (idx !== -1 && cmdArgs[idx + 1] === "json") return "json";
11998
+ const value = idx !== -1 ? cmdArgs[idx + 1] : void 0;
11999
+ if (value === "json") return "json";
12000
+ if (value === "jsonl") return "jsonl";
11802
12001
  return "text";
11803
12002
  }
11804
12003
  async function runCli(args = process.argv.slice(2)) {
@@ -11838,7 +12037,7 @@ async function runCli(args = process.argv.slice(2)) {
11838
12037
  ...setupState ? { setup_state: setupState } : {}
11839
12038
  });
11840
12039
  }
11841
- if (!isHelpRequest && command !== "telemetry") {
12040
+ if (!isHelpRequest && command !== "telemetry" && process.stderr.isTTY) {
11842
12041
  void checkLatestVersionForCli().then((update) => {
11843
12042
  if (!update) return;
11844
12043
  process.stderr.write(