@ainyc/canonry 1.21.1 → 1.24.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
@@ -19,7 +19,7 @@ import {
19
19
  setGoogleAuthConfig,
20
20
  showFirstRunNotice,
21
21
  trackEvent
22
- } from "./chunk-2JBQ7NMO.js";
22
+ } from "./chunk-Q5REKIL6.js";
23
23
 
24
24
  // src/cli.ts
25
25
  import { pathToFileURL } from "url";
@@ -416,6 +416,26 @@ var ApiClient = class {
416
416
  async getBrowserDiff(project, runId) {
417
417
  return this.request("GET", `/projects/${encodeURIComponent(project)}/runs/${encodeURIComponent(runId)}/browser-diff`);
418
418
  }
419
+ // Google Analytics 4
420
+ async gaConnect(project, body) {
421
+ return this.request("POST", `/projects/${encodeURIComponent(project)}/ga/connect`, body);
422
+ }
423
+ async gaDisconnect(project) {
424
+ await this.request("DELETE", `/projects/${encodeURIComponent(project)}/ga/disconnect`);
425
+ }
426
+ async gaStatus(project) {
427
+ return this.request("GET", `/projects/${encodeURIComponent(project)}/ga/status`);
428
+ }
429
+ async gaSync(project, body) {
430
+ return this.request("POST", `/projects/${encodeURIComponent(project)}/ga/sync`, body ?? {});
431
+ }
432
+ async gaTraffic(project, params) {
433
+ const qs = params ? "?" + new URLSearchParams(params).toString() : "";
434
+ return this.request("GET", `/projects/${encodeURIComponent(project)}/ga/traffic${qs}`);
435
+ }
436
+ async gaCoverage(project) {
437
+ return this.request("GET", `/projects/${encodeURIComponent(project)}/ga/coverage`);
438
+ }
419
439
  };
420
440
 
421
441
  // src/commands/bing.ts
@@ -1073,13 +1093,256 @@ var CDP_CLI_COMMANDS = [
1073
1093
  }
1074
1094
  ];
1075
1095
 
1076
- // src/commands/competitor.ts
1096
+ // src/commands/ga.ts
1077
1097
  function getClient3() {
1078
1098
  const config = loadConfig();
1079
1099
  return new ApiClient(config.apiUrl, config.apiKey);
1080
1100
  }
1081
- async function addCompetitors(project, domains, format) {
1101
+ async function gaConnect(project, opts) {
1102
+ if (!opts.propertyId) {
1103
+ throw new CliError({
1104
+ code: "GA_PROPERTY_ID_REQUIRED",
1105
+ message: "Property ID is required (pass --property-id)",
1106
+ displayMessage: "Error: --property-id is required",
1107
+ details: { project }
1108
+ });
1109
+ }
1110
+ if (!opts.keyFile && !opts.keyJson) {
1111
+ throw new CliError({
1112
+ code: "GA_KEY_REQUIRED",
1113
+ message: "Service account key is required (pass --key-file or --key-json)",
1114
+ displayMessage: "Error: --key-file or --key-json is required",
1115
+ details: { project }
1116
+ });
1117
+ }
1118
+ const body = {
1119
+ propertyId: opts.propertyId
1120
+ };
1121
+ if (opts.keyFile) {
1122
+ const fs5 = await import("fs");
1123
+ try {
1124
+ const content = fs5.readFileSync(opts.keyFile, "utf-8");
1125
+ JSON.parse(content);
1126
+ body.keyJson = content;
1127
+ } catch (e) {
1128
+ const msg = e instanceof Error ? e.message : String(e);
1129
+ throw new CliError({
1130
+ code: "GA_KEY_FILE_READ_ERROR",
1131
+ message: `Failed to read key file: ${msg}`,
1132
+ displayMessage: `Error: failed to read key file "${opts.keyFile}": ${msg}`,
1133
+ details: { project, keyFile: opts.keyFile }
1134
+ });
1135
+ }
1136
+ } else if (opts.keyJson) {
1137
+ body.keyJson = opts.keyJson;
1138
+ }
1139
+ const client = getClient3();
1140
+ const result = await client.gaConnect(project, body);
1141
+ if (opts.format === "json") {
1142
+ console.log(JSON.stringify(result, null, 2));
1143
+ return;
1144
+ }
1145
+ console.log(`GA4 connected for project "${project}".`);
1146
+ console.log(` Property ID: ${result.propertyId}`);
1147
+ console.log(` Service Account: ${result.clientEmail}`);
1148
+ }
1149
+ async function gaDisconnect(project, format) {
1150
+ const client = getClient3();
1151
+ await client.gaDisconnect(project);
1152
+ if (format === "json") {
1153
+ console.log(JSON.stringify({ project, disconnected: true }, null, 2));
1154
+ return;
1155
+ }
1156
+ console.log(`GA4 disconnected from project "${project}".`);
1157
+ }
1158
+ async function gaStatus(project, format) {
1159
+ const client = getClient3();
1160
+ const result = await client.gaStatus(project);
1161
+ if (format === "json") {
1162
+ console.log(JSON.stringify(result, null, 2));
1163
+ return;
1164
+ }
1165
+ if (!result.connected) {
1166
+ console.log(`No GA4 connection for project "${project}".`);
1167
+ console.log('Run "canonry ga connect <project> --property-id <id> --key-file <path>" to connect.');
1168
+ return;
1169
+ }
1170
+ console.log(`GA4 for "${project}":
1171
+ `);
1172
+ console.log(` Property ID: ${result.propertyId}`);
1173
+ console.log(` Service Account: ${result.clientEmail}`);
1174
+ console.log(` Last Synced: ${result.lastSyncedAt ?? "(never)"}`);
1175
+ console.log(` Connected: ${result.createdAt ?? "unknown"}`);
1176
+ }
1177
+ async function gaSync(project, opts) {
1178
+ const client = getClient3();
1179
+ const result = await client.gaSync(project, { days: opts?.days });
1180
+ if (opts?.format === "json") {
1181
+ console.log(JSON.stringify(result, null, 2));
1182
+ return;
1183
+ }
1184
+ console.log(`GA4 sync complete for "${project}".`);
1185
+ console.log(` Rows synced: ${result.rowCount}`);
1186
+ console.log(` Period: ${result.days} days`);
1187
+ console.log(` Synced at: ${result.syncedAt}`);
1188
+ }
1189
+ async function gaTraffic(project, opts) {
1082
1190
  const client = getClient3();
1191
+ const params = {};
1192
+ if (opts?.limit) params.limit = String(opts.limit);
1193
+ const result = await client.gaTraffic(project, Object.keys(params).length > 0 ? params : void 0);
1194
+ if (opts?.format === "json") {
1195
+ console.log(JSON.stringify(result, null, 2));
1196
+ return;
1197
+ }
1198
+ if (result.topPages.length === 0) {
1199
+ console.log('No GA4 traffic data. Run "canonry ga sync <project>" first.');
1200
+ return;
1201
+ }
1202
+ console.log(`GA4 Traffic for "${project}"
1203
+ `);
1204
+ console.log(` Total Sessions: ${result.totalSessions}`);
1205
+ console.log(` Organic Sessions: ${result.totalOrganicSessions}`);
1206
+ console.log(` Total Users: ${result.totalUsers}`);
1207
+ console.log();
1208
+ const pageWidth = Math.min(60, Math.max(15, ...result.topPages.map((r) => r.landingPage.length)));
1209
+ console.log(` ${"LANDING PAGE".padEnd(pageWidth)} ${"SESSIONS".padEnd(10)}${"ORGANIC".padEnd(10)}${"USERS".padEnd(8)}`);
1210
+ console.log(` ${"\u2500".repeat(pageWidth)} ${"\u2500".repeat(10)}${"\u2500".repeat(10)}${"\u2500".repeat(8)}`);
1211
+ for (const row of result.topPages) {
1212
+ const page = row.landingPage.length > pageWidth ? row.landingPage.slice(0, pageWidth - 3) + "..." : row.landingPage;
1213
+ console.log(
1214
+ ` ${page.padEnd(pageWidth)} ${String(row.sessions).padEnd(10)}${String(row.organicSessions).padEnd(10)}${String(row.users).padEnd(8)}`
1215
+ );
1216
+ }
1217
+ if (result.lastSyncedAt) {
1218
+ console.log(`
1219
+ Last synced: ${result.lastSyncedAt}`);
1220
+ }
1221
+ }
1222
+ async function gaCoverage(project, format) {
1223
+ const client = getClient3();
1224
+ const result = await client.gaCoverage(project);
1225
+ if (format === "json") {
1226
+ console.log(JSON.stringify(result, null, 2));
1227
+ return;
1228
+ }
1229
+ if (result.pages.length === 0) {
1230
+ console.log('No GA4 coverage data. Run "canonry ga sync <project>" first.');
1231
+ return;
1232
+ }
1233
+ console.log(`GA4 Page Coverage (${result.pages.length} pages with traffic):
1234
+ `);
1235
+ const pageWidth = Math.min(60, Math.max(15, ...result.pages.map((r) => r.landingPage.length)));
1236
+ console.log(` ${"LANDING PAGE".padEnd(pageWidth)} ${"SESSIONS".padEnd(10)}${"ORGANIC".padEnd(10)}${"USERS".padEnd(8)}`);
1237
+ console.log(` ${"\u2500".repeat(pageWidth)} ${"\u2500".repeat(10)}${"\u2500".repeat(10)}${"\u2500".repeat(8)}`);
1238
+ for (const row of result.pages) {
1239
+ const page = row.landingPage.length > pageWidth ? row.landingPage.slice(0, pageWidth - 3) + "..." : row.landingPage;
1240
+ console.log(
1241
+ ` ${page.padEnd(pageWidth)} ${String(row.sessions).padEnd(10)}${String(row.organicSessions).padEnd(10)}${String(row.users).padEnd(8)}`
1242
+ );
1243
+ }
1244
+ }
1245
+
1246
+ // src/cli-commands/ga.ts
1247
+ var GA_CLI_COMMANDS = [
1248
+ {
1249
+ path: ["ga", "connect"],
1250
+ usage: "canonry ga connect <project> --property-id <id> --key-file <path> [--key-json <json>] [--format json]",
1251
+ options: {
1252
+ "property-id": stringOption(),
1253
+ "key-file": stringOption(),
1254
+ "key-json": stringOption()
1255
+ },
1256
+ run: async (input) => {
1257
+ const project = requireProject(input, "ga.connect", "canonry ga connect <project> --property-id <id> --key-file <path>");
1258
+ const propertyId = getString(input.values, "property-id");
1259
+ if (!propertyId) {
1260
+ throw new Error("--property-id is required");
1261
+ }
1262
+ await gaConnect(project, {
1263
+ propertyId,
1264
+ keyFile: getString(input.values, "key-file"),
1265
+ keyJson: getString(input.values, "key-json"),
1266
+ format: input.format
1267
+ });
1268
+ }
1269
+ },
1270
+ {
1271
+ path: ["ga", "disconnect"],
1272
+ usage: "canonry ga disconnect <project> [--format json]",
1273
+ run: async (input) => {
1274
+ const project = requireProject(input, "ga.disconnect", "canonry ga disconnect <project> [--format json]");
1275
+ await gaDisconnect(project, input.format);
1276
+ }
1277
+ },
1278
+ {
1279
+ path: ["ga", "status"],
1280
+ usage: "canonry ga status <project> [--format json]",
1281
+ run: async (input) => {
1282
+ const project = requireProject(input, "ga.status", "canonry ga status <project> [--format json]");
1283
+ await gaStatus(project, input.format);
1284
+ }
1285
+ },
1286
+ {
1287
+ path: ["ga", "sync"],
1288
+ usage: "canonry ga sync <project> [--days 30] [--format json]",
1289
+ options: {
1290
+ days: stringOption()
1291
+ },
1292
+ run: async (input) => {
1293
+ const project = requireProject(input, "ga.sync", "canonry ga sync <project> [--days 30] [--format json]");
1294
+ const daysStr = getString(input.values, "days");
1295
+ const days = daysStr ? parseInt(daysStr, 10) : void 0;
1296
+ await gaSync(project, {
1297
+ days,
1298
+ format: input.format
1299
+ });
1300
+ }
1301
+ },
1302
+ {
1303
+ path: ["ga", "traffic"],
1304
+ usage: "canonry ga traffic <project> [--limit 50] [--format json]",
1305
+ options: {
1306
+ limit: stringOption()
1307
+ },
1308
+ run: async (input) => {
1309
+ const project = requireProject(input, "ga.traffic", "canonry ga traffic <project> [--limit 50] [--format json]");
1310
+ const limitStr = getString(input.values, "limit");
1311
+ const limit = limitStr ? parseInt(limitStr, 10) : void 0;
1312
+ await gaTraffic(project, {
1313
+ limit,
1314
+ format: input.format
1315
+ });
1316
+ }
1317
+ },
1318
+ {
1319
+ path: ["ga", "coverage"],
1320
+ usage: "canonry ga coverage <project> [--format json]",
1321
+ run: async (input) => {
1322
+ const project = requireProject(input, "ga.coverage", "canonry ga coverage <project> [--format json]");
1323
+ await gaCoverage(project, input.format);
1324
+ }
1325
+ },
1326
+ {
1327
+ path: ["ga"],
1328
+ usage: "canonry ga <connect|disconnect|status|sync|traffic|coverage> <project> [args]",
1329
+ run: async (input) => {
1330
+ unknownSubcommand(input.positionals[0], {
1331
+ command: "ga",
1332
+ usage: "canonry ga <connect|disconnect|status|sync|traffic|coverage> <project> [args]",
1333
+ available: ["connect", "disconnect", "status", "sync", "traffic", "coverage"]
1334
+ });
1335
+ }
1336
+ }
1337
+ ];
1338
+
1339
+ // src/commands/competitor.ts
1340
+ function getClient4() {
1341
+ const config = loadConfig();
1342
+ return new ApiClient(config.apiUrl, config.apiKey);
1343
+ }
1344
+ async function addCompetitors(project, domains, format) {
1345
+ const client = getClient4();
1083
1346
  const existing = await client.listCompetitors(project);
1084
1347
  const existingDomains = existing.map((c) => c.domain);
1085
1348
  const addedDomains = domains.filter((domain) => !existingDomains.includes(domain));
@@ -1097,7 +1360,7 @@ async function addCompetitors(project, domains, format) {
1097
1360
  console.log(`Added ${domains.length} competitor(s) to "${project}".`);
1098
1361
  }
1099
1362
  async function listCompetitors(project, format) {
1100
- const client = getClient3();
1363
+ const client = getClient4();
1101
1364
  const comps = await client.listCompetitors(project);
1102
1365
  if (format === "json") {
1103
1366
  console.log(JSON.stringify(comps, null, 2));
@@ -1156,7 +1419,7 @@ var COMPETITOR_CLI_COMMANDS = [
1156
1419
  ];
1157
1420
 
1158
1421
  // src/commands/google.ts
1159
- function getClient4() {
1422
+ function getClient5() {
1160
1423
  const config = loadConfig();
1161
1424
  return new ApiClient(config.apiUrl, config.apiKey);
1162
1425
  }
@@ -1197,7 +1460,7 @@ async function waitForRunStatus(client, runId, config) {
1197
1460
  });
1198
1461
  }
1199
1462
  async function googleConnect(project, opts) {
1200
- const client = getClient4();
1463
+ const client = getClient5();
1201
1464
  const { authUrl, redirectUri } = await client.googleConnect(project, {
1202
1465
  type: opts.type,
1203
1466
  publicUrl: opts.publicUrl
@@ -1231,7 +1494,7 @@ Open this URL in your browser to authorize Google ${opts.type.toUpperCase()} acc
1231
1494
  }
1232
1495
  }
1233
1496
  async function googleDisconnect(project, opts) {
1234
- const client = getClient4();
1497
+ const client = getClient5();
1235
1498
  await client.googleDisconnect(project, opts.type);
1236
1499
  if (opts.format === "json") {
1237
1500
  console.log(JSON.stringify({ project, type: opts.type, disconnected: true }, null, 2));
@@ -1240,7 +1503,7 @@ async function googleDisconnect(project, opts) {
1240
1503
  console.log(`Disconnected Google ${opts.type.toUpperCase()} from project "${project}".`);
1241
1504
  }
1242
1505
  async function googleStatus(project, format) {
1243
- const client = getClient4();
1506
+ const client = getClient5();
1244
1507
  const connections = await client.googleConnections(project);
1245
1508
  if (format === "json") {
1246
1509
  console.log(JSON.stringify({ connections }, null, 2));
@@ -1264,7 +1527,7 @@ async function googleStatus(project, format) {
1264
1527
  }
1265
1528
  }
1266
1529
  async function googleProperties(project, format) {
1267
- const client = getClient4();
1530
+ const client = getClient5();
1268
1531
  const { sites } = await client.googleProperties(project);
1269
1532
  if (format === "json") {
1270
1533
  console.log(JSON.stringify({ sites }, null, 2));
@@ -1285,7 +1548,7 @@ async function googleProperties(project, format) {
1285
1548
  Use "canonry google set-property <project> <siteUrl>" to select a property.`);
1286
1549
  }
1287
1550
  async function googleSetProperty(project, propertyUrl, format) {
1288
- const client = getClient4();
1551
+ const client = getClient5();
1289
1552
  await client.googleSetProperty(project, "gsc", propertyUrl);
1290
1553
  if (format === "json") {
1291
1554
  console.log(JSON.stringify({ project, type: "gsc", propertyUrl }, null, 2));
@@ -1294,7 +1557,7 @@ async function googleSetProperty(project, propertyUrl, format) {
1294
1557
  console.log(`GSC property set to "${propertyUrl}" for project "${project}".`);
1295
1558
  }
1296
1559
  async function googleSync(project, opts) {
1297
- const client = getClient4();
1560
+ const client = getClient5();
1298
1561
  const run = await client.gscSync(project, { days: opts.days, full: opts.full });
1299
1562
  if (!opts.wait && opts.format === "json") {
1300
1563
  console.log(JSON.stringify(run, null, 2));
@@ -1324,7 +1587,7 @@ async function googleSync(project, opts) {
1324
1587
  }
1325
1588
  }
1326
1589
  async function googlePerformance(project, opts) {
1327
- const client = getClient4();
1590
+ const client = getClient5();
1328
1591
  const params = {};
1329
1592
  if (opts.days) {
1330
1593
  const end = /* @__PURE__ */ new Date();
@@ -1360,7 +1623,7 @@ async function googlePerformance(project, opts) {
1360
1623
  }
1361
1624
  }
1362
1625
  async function googleInspect(project, url, format) {
1363
- const client = getClient4();
1626
+ const client = getClient5();
1364
1627
  const result = await client.gscInspect(project, url);
1365
1628
  if (format === "json") {
1366
1629
  console.log(JSON.stringify(result, null, 2));
@@ -1380,7 +1643,7 @@ URL Inspection: ${result.url}
1380
1643
  console.log(` Inspected At: ${result.inspectedAt}`);
1381
1644
  }
1382
1645
  async function googleInspections(project, opts) {
1383
- const client = getClient4();
1646
+ const client = getClient5();
1384
1647
  const params = {};
1385
1648
  if (opts.url) params.url = opts.url;
1386
1649
  const rows = await client.gscInspections(project, Object.keys(params).length > 0 ? params : void 0);
@@ -1405,7 +1668,7 @@ async function googleInspections(project, opts) {
1405
1668
  }
1406
1669
  }
1407
1670
  async function googleCoverage(project, format) {
1408
- const client = getClient4();
1671
+ const client = getClient5();
1409
1672
  const result = await client.gscCoverage(project);
1410
1673
  if (format === "json") {
1411
1674
  console.log(JSON.stringify(result, null, 2));
@@ -1451,7 +1714,7 @@ Index Coverage for "${project}"
1451
1714
  }
1452
1715
  }
1453
1716
  async function googleSetSitemap(project, sitemapUrl, format) {
1454
- const client = getClient4();
1717
+ const client = getClient5();
1455
1718
  await client.googleSetSitemap(project, "gsc", sitemapUrl);
1456
1719
  if (format === "json") {
1457
1720
  console.log(JSON.stringify({ project, type: "gsc", sitemapUrl }, null, 2));
@@ -1460,7 +1723,7 @@ async function googleSetSitemap(project, sitemapUrl, format) {
1460
1723
  console.log(`GSC sitemap URL set to "${sitemapUrl}" for project "${project}".`);
1461
1724
  }
1462
1725
  async function googleListSitemaps(project, opts) {
1463
- const client = getClient4();
1726
+ const client = getClient5();
1464
1727
  const result = await client.gscSitemaps(project);
1465
1728
  if (opts.format === "json") {
1466
1729
  console.log(JSON.stringify(result, null, 2));
@@ -1482,7 +1745,7 @@ Sitemaps for project "${project}":
1482
1745
  }
1483
1746
  }
1484
1747
  async function googleInspectSitemap(project, opts) {
1485
- const client = getClient4();
1748
+ const client = getClient5();
1486
1749
  const run = await client.gscInspectSitemap(project, {
1487
1750
  sitemapUrl: opts.sitemapUrl
1488
1751
  });
@@ -1518,7 +1781,7 @@ async function googleInspectSitemap(project, opts) {
1518
1781
  }
1519
1782
  }
1520
1783
  async function googleCoverageHistory(project, opts) {
1521
- const client = getClient4();
1784
+ const client = getClient5();
1522
1785
  const rows = await client.gscCoverageHistory(project, { limit: opts.limit });
1523
1786
  if (opts.format === "json") {
1524
1787
  console.log(JSON.stringify(rows, null, 2));
@@ -1540,7 +1803,7 @@ GSC Coverage History for "${project}" (${rows.length} snapshots):
1540
1803
  }
1541
1804
  }
1542
1805
  async function googleDiscoverSitemaps(project, opts) {
1543
- const client = getClient4();
1806
+ const client = getClient5();
1544
1807
  const result = await client.gscDiscoverSitemaps(project);
1545
1808
  if (!opts.wait && opts.format === "json") {
1546
1809
  console.log(JSON.stringify(result, null, 2));
@@ -1592,7 +1855,7 @@ Primary sitemap: ${result.primarySitemapUrl}`);
1592
1855
  }
1593
1856
  }
1594
1857
  async function googleRequestIndexing(project, opts) {
1595
- const client = getClient4();
1858
+ const client = getClient5();
1596
1859
  const body = { urls: [] };
1597
1860
  if (opts.allUnindexed) {
1598
1861
  body.allUnindexed = true;
@@ -1672,7 +1935,7 @@ async function googleRequestIndexing(project, opts) {
1672
1935
  }
1673
1936
  }
1674
1937
  async function googleDeindexed(project, format) {
1675
- const client = getClient4();
1938
+ const client = getClient5();
1676
1939
  const rows = await client.gscDeindexed(project);
1677
1940
  if (format === "json") {
1678
1941
  console.log(JSON.stringify(rows, null, 2));
@@ -1953,12 +2216,12 @@ var GOOGLE_CLI_COMMANDS = [
1953
2216
 
1954
2217
  // src/commands/keyword.ts
1955
2218
  import fs from "fs";
1956
- function getClient5() {
2219
+ function getClient6() {
1957
2220
  const config = loadConfig();
1958
2221
  return new ApiClient(config.apiUrl, config.apiKey);
1959
2222
  }
1960
2223
  async function addKeywords(project, keywords, format) {
1961
- const client = getClient5();
2224
+ const client = getClient6();
1962
2225
  await client.appendKeywords(project, keywords);
1963
2226
  if (format === "json") {
1964
2227
  console.log(JSON.stringify({
@@ -1971,7 +2234,7 @@ async function addKeywords(project, keywords, format) {
1971
2234
  console.log(`Added ${keywords.length} key phrase(s) to "${project}".`);
1972
2235
  }
1973
2236
  async function removeKeywords(project, keywords, format) {
1974
- const client = getClient5();
2237
+ const client = getClient6();
1975
2238
  const existing = await client.listKeywords(project);
1976
2239
  const existingSet = new Set(existing.map((k) => k.keyword));
1977
2240
  const removedKeywords = keywords.filter((k) => existingSet.has(k));
@@ -1988,7 +2251,7 @@ async function removeKeywords(project, keywords, format) {
1988
2251
  console.log(`Removed ${removedKeywords.length} key phrase(s) from "${project}".`);
1989
2252
  }
1990
2253
  async function listKeywords(project, format) {
1991
- const client = getClient5();
2254
+ const client = getClient6();
1992
2255
  const kws = await client.listKeywords(project);
1993
2256
  if (format === "json") {
1994
2257
  console.log(JSON.stringify(kws, null, 2));
@@ -2030,7 +2293,7 @@ async function importKeywords(project, filePath, format) {
2030
2293
  console.log("No key phrases found in file.");
2031
2294
  return;
2032
2295
  }
2033
- const client = getClient5();
2296
+ const client = getClient6();
2034
2297
  await client.appendKeywords(project, keywords);
2035
2298
  if (format === "json") {
2036
2299
  console.log(JSON.stringify({
@@ -2044,7 +2307,7 @@ async function importKeywords(project, filePath, format) {
2044
2307
  console.log(`Imported ${keywords.length} key phrase(s) to "${project}".`);
2045
2308
  }
2046
2309
  async function generateKeywords(project, provider, opts) {
2047
- const client = getClient5();
2310
+ const client = getClient6();
2048
2311
  const result = await client.generateKeywords(project, provider, opts.count);
2049
2312
  const saved = Boolean(opts.save && result.keywords.length > 0);
2050
2313
  if (opts.format !== "json") {
@@ -2198,12 +2461,12 @@ var KEYWORD_CLI_COMMANDS = [
2198
2461
  ];
2199
2462
 
2200
2463
  // src/commands/notify.ts
2201
- function getClient6() {
2464
+ function getClient7() {
2202
2465
  const config = loadConfig();
2203
2466
  return new ApiClient(config.apiUrl, config.apiKey);
2204
2467
  }
2205
2468
  async function addNotification(project, opts) {
2206
- const client = getClient6();
2469
+ const client = getClient7();
2207
2470
  const result = await client.createNotification(project, {
2208
2471
  channel: "webhook",
2209
2472
  url: opts.webhook,
@@ -2217,7 +2480,7 @@ async function addNotification(project, opts) {
2217
2480
  printNotification(result);
2218
2481
  }
2219
2482
  async function listNotifications(project, format) {
2220
- const client = getClient6();
2483
+ const client = getClient7();
2221
2484
  const results = await client.listNotifications(project);
2222
2485
  if (format === "json") {
2223
2486
  console.log(JSON.stringify(results, null, 2));
@@ -2235,7 +2498,7 @@ async function listNotifications(project, format) {
2235
2498
  }
2236
2499
  }
2237
2500
  async function removeNotification(project, id, format) {
2238
- const client = getClient6();
2501
+ const client = getClient7();
2239
2502
  await client.deleteNotification(project, id);
2240
2503
  if (format === "json") {
2241
2504
  console.log(JSON.stringify({ project, id, removed: true }, null, 2));
@@ -2244,7 +2507,7 @@ async function removeNotification(project, id, format) {
2244
2507
  console.log(`Notification ${id} removed from "${project}"`);
2245
2508
  }
2246
2509
  async function testNotification(project, id, format) {
2247
- const client = getClient6();
2510
+ const client = getClient7();
2248
2511
  const result = await client.testNotification(project, id);
2249
2512
  if (format === "json") {
2250
2513
  console.log(JSON.stringify({ project, id, ...result }, null, 2));
@@ -2434,12 +2697,12 @@ async function applyConfigs(filePaths, format) {
2434
2697
  }
2435
2698
 
2436
2699
  // src/commands/analytics.ts
2437
- function getClient7() {
2700
+ function getClient8() {
2438
2701
  const config = loadConfig();
2439
2702
  return new ApiClient(config.apiUrl, config.apiKey);
2440
2703
  }
2441
2704
  async function showAnalytics(project, options) {
2442
- const client = getClient7();
2705
+ const client = getClient8();
2443
2706
  const features = options.feature ? [options.feature] : ["metrics", "gaps", "sources"];
2444
2707
  const results = {};
2445
2708
  for (const feature of features) {
@@ -2542,12 +2805,12 @@ Source Origin Breakdown`);
2542
2805
  }
2543
2806
 
2544
2807
  // src/commands/evidence.ts
2545
- function getClient8() {
2808
+ function getClient9() {
2546
2809
  const config = loadConfig();
2547
2810
  return new ApiClient(config.apiUrl, config.apiKey);
2548
2811
  }
2549
2812
  async function showEvidence(project, format) {
2550
- const client = getClient8();
2813
+ const client = getClient9();
2551
2814
  const timeline = await client.getTimeline(project);
2552
2815
  if (format === "json") {
2553
2816
  const enriched = timeline.map((entry) => ({
@@ -2600,12 +2863,12 @@ async function exportProject(project, opts) {
2600
2863
  }
2601
2864
 
2602
2865
  // src/commands/history.ts
2603
- function getClient9() {
2866
+ function getClient10() {
2604
2867
  const config = loadConfig();
2605
2868
  return new ApiClient(config.apiUrl, config.apiKey);
2606
2869
  }
2607
2870
  async function showHistory(project, format) {
2608
- const client = getClient9();
2871
+ const client = getClient10();
2609
2872
  try {
2610
2873
  const entries = await client.getHistory(project);
2611
2874
  if (format === "json") {
@@ -2640,12 +2903,12 @@ async function showHistory(project, format) {
2640
2903
  }
2641
2904
 
2642
2905
  // src/commands/status.ts
2643
- function getClient10() {
2906
+ function getClient11() {
2644
2907
  const config = loadConfig();
2645
2908
  return new ApiClient(config.apiUrl, config.apiKey);
2646
2909
  }
2647
2910
  async function showStatus(project, format) {
2648
- const client = getClient10();
2911
+ const client = getClient11();
2649
2912
  const projectData = await client.getProject(project);
2650
2913
  let runs = [];
2651
2914
  try {
@@ -2753,12 +3016,12 @@ var OPERATOR_CLI_COMMANDS = [
2753
3016
  ];
2754
3017
 
2755
3018
  // src/commands/project.ts
2756
- function getClient11() {
3019
+ function getClient12() {
2757
3020
  const config = loadConfig();
2758
3021
  return new ApiClient(config.apiUrl, config.apiKey);
2759
3022
  }
2760
3023
  async function createProject(name, opts) {
2761
- const client = getClient11();
3024
+ const client = getClient12();
2762
3025
  const result = await client.putProject(name, {
2763
3026
  displayName: opts.displayName,
2764
3027
  canonicalDomain: opts.domain,
@@ -2773,7 +3036,7 @@ async function createProject(name, opts) {
2773
3036
  console.log(`Project created: ${result.name} (${result.id})`);
2774
3037
  }
2775
3038
  async function listProjects(format) {
2776
- const client = getClient11();
3039
+ const client = getClient12();
2777
3040
  const projects = await client.listProjects();
2778
3041
  if (format === "json") {
2779
3042
  console.log(JSON.stringify(projects, null, 2));
@@ -2801,7 +3064,7 @@ async function listProjects(format) {
2801
3064
  }
2802
3065
  }
2803
3066
  async function showProject(name, format) {
2804
- const client = getClient11();
3067
+ const client = getClient12();
2805
3068
  const project = await client.getProject(name);
2806
3069
  if (format === "json") {
2807
3070
  console.log(JSON.stringify(project, null, 2));
@@ -2827,7 +3090,7 @@ async function showProject(name, format) {
2827
3090
  console.log(` Updated: ${project.updatedAt}`);
2828
3091
  }
2829
3092
  async function updateProjectSettings(name, opts) {
2830
- const client = getClient11();
3093
+ const client = getClient12();
2831
3094
  const project = await client.getProject(name);
2832
3095
  let ownedDomains = opts.ownedDomains ?? project.ownedDomains ?? [];
2833
3096
  if (opts.addOwnedDomain) {
@@ -2852,7 +3115,7 @@ async function updateProjectSettings(name, opts) {
2852
3115
  console.log(`Project updated: ${result.name}`);
2853
3116
  }
2854
3117
  async function deleteProject(name, format) {
2855
- const client = getClient11();
3118
+ const client = getClient12();
2856
3119
  await client.deleteProject(name);
2857
3120
  if (format === "json") {
2858
3121
  console.log(JSON.stringify({ name, deleted: true }, null, 2));
@@ -2861,7 +3124,7 @@ async function deleteProject(name, format) {
2861
3124
  console.log(`Project deleted: ${name}`);
2862
3125
  }
2863
3126
  async function addLocation(project, opts) {
2864
- const client = getClient11();
3127
+ const client = getClient12();
2865
3128
  const location = await client.addLocation(project, {
2866
3129
  label: opts.label,
2867
3130
  city: opts.city,
@@ -2876,7 +3139,7 @@ async function addLocation(project, opts) {
2876
3139
  console.log(`Location added: ${opts.label} (${opts.city}, ${opts.region}, ${opts.country})`);
2877
3140
  }
2878
3141
  async function listLocations(project, format) {
2879
- const client = getClient11();
3142
+ const client = getClient12();
2880
3143
  const result = await client.listLocations(project);
2881
3144
  if (format === "json") {
2882
3145
  console.log(JSON.stringify(result, null, 2));
@@ -2902,7 +3165,7 @@ async function listLocations(project, format) {
2902
3165
  }
2903
3166
  }
2904
3167
  async function removeLocation(project, label, format) {
2905
- const client = getClient11();
3168
+ const client = getClient12();
2906
3169
  await client.removeLocation(project, label);
2907
3170
  if (format === "json") {
2908
3171
  console.log(JSON.stringify({ project, label, removed: true }, null, 2));
@@ -2911,7 +3174,7 @@ async function removeLocation(project, label, format) {
2911
3174
  console.log(`Location removed: ${label}`);
2912
3175
  }
2913
3176
  async function setDefaultLocation(project, label, format) {
2914
- const client = getClient11();
3177
+ const client = getClient12();
2915
3178
  const result = await client.setDefaultLocation(project, label);
2916
3179
  if (format === "json") {
2917
3180
  console.log(JSON.stringify({ project, ...result }, null, 2));
@@ -3090,13 +3353,13 @@ var PROJECT_CLI_COMMANDS = [
3090
3353
  ];
3091
3354
 
3092
3355
  // src/commands/run.ts
3093
- function getClient12() {
3356
+ function getClient13() {
3094
3357
  const config = loadConfig();
3095
3358
  return new ApiClient(config.apiUrl, config.apiKey);
3096
3359
  }
3097
3360
  var TERMINAL_STATUSES = /* @__PURE__ */ new Set(["completed", "partial", "failed", "cancelled"]);
3098
3361
  async function triggerRun(project, opts) {
3099
- const client = getClient12();
3362
+ const client = getClient13();
3100
3363
  const body = {};
3101
3364
  if (opts?.provider) {
3102
3365
  const providerInputs = opts.provider.split(",").map((s) => s.trim()).filter(Boolean);
@@ -3183,7 +3446,7 @@ async function triggerRun(project, opts) {
3183
3446
  }
3184
3447
  }
3185
3448
  async function triggerRunAll(opts) {
3186
- const client = getClient12();
3449
+ const client = getClient13();
3187
3450
  const projects = await client.listProjects();
3188
3451
  if (projects.length === 0) {
3189
3452
  if (opts?.format === "json") {
@@ -3235,7 +3498,7 @@ async function triggerRunAll(opts) {
3235
3498
  }
3236
3499
  }
3237
3500
  async function cancelRun(project, runId, format) {
3238
- const client = getClient12();
3501
+ const client = getClient13();
3239
3502
  let targetId = runId;
3240
3503
  if (!targetId) {
3241
3504
  const runs = await client.listRuns(project);
@@ -3267,7 +3530,7 @@ To cancel by ID : canonry run cancel ${project} <run-id>`,
3267
3530
  console.log(`Run ${result.id} cancelled.`);
3268
3531
  }
3269
3532
  async function showRun(id, format) {
3270
- const client = getClient12();
3533
+ const client = getClient13();
3271
3534
  const run = await client.getRun(id);
3272
3535
  if (format === "json") {
3273
3536
  console.log(JSON.stringify(run, null, 2));
@@ -3276,7 +3539,7 @@ async function showRun(id, format) {
3276
3539
  printRunDetail(run);
3277
3540
  }
3278
3541
  async function listRuns(project, opts) {
3279
- const client = getClient12();
3542
+ const client = getClient13();
3280
3543
  const runs = await client.listRuns(project, opts?.limit);
3281
3544
  if (opts?.format === "json") {
3282
3545
  console.log(JSON.stringify(runs, null, 2));
@@ -3420,12 +3683,12 @@ var RUN_CLI_COMMANDS = [
3420
3683
  ];
3421
3684
 
3422
3685
  // src/commands/schedule.ts
3423
- function getClient13() {
3686
+ function getClient14() {
3424
3687
  const config = loadConfig();
3425
3688
  return new ApiClient(config.apiUrl, config.apiKey);
3426
3689
  }
3427
3690
  async function setSchedule(project, opts) {
3428
- const client = getClient13();
3691
+ const client = getClient14();
3429
3692
  const body = {};
3430
3693
  if (opts.preset) body.preset = opts.preset;
3431
3694
  if (opts.cron) body.cron = opts.cron;
@@ -3440,7 +3703,7 @@ async function setSchedule(project, opts) {
3440
3703
  printSchedule(result);
3441
3704
  }
3442
3705
  async function showSchedule(project, format) {
3443
- const client = getClient13();
3706
+ const client = getClient14();
3444
3707
  const result = await client.getSchedule(project);
3445
3708
  if (format === "json") {
3446
3709
  console.log(JSON.stringify(result, null, 2));
@@ -3449,7 +3712,7 @@ async function showSchedule(project, format) {
3449
3712
  printSchedule(result);
3450
3713
  }
3451
3714
  async function enableSchedule(project, format) {
3452
- const client = getClient13();
3715
+ const client = getClient14();
3453
3716
  const current = await client.getSchedule(project);
3454
3717
  const body = { timezone: current.timezone };
3455
3718
  if (current.preset) body.preset = current.preset;
@@ -3463,7 +3726,7 @@ async function enableSchedule(project, format) {
3463
3726
  console.log(`Schedule enabled for "${project}"`);
3464
3727
  }
3465
3728
  async function disableSchedule(project, format) {
3466
- const client = getClient13();
3729
+ const client = getClient14();
3467
3730
  const current = await client.getSchedule(project);
3468
3731
  const body = { timezone: current.timezone, enabled: false };
3469
3732
  if (current.preset) body.preset = current.preset;
@@ -3477,7 +3740,7 @@ async function disableSchedule(project, format) {
3477
3740
  console.log(`Schedule disabled for "${project}"`);
3478
3741
  }
3479
3742
  async function removeSchedule(project, format) {
3480
- const client = getClient13();
3743
+ const client = getClient14();
3481
3744
  await client.deleteSchedule(project);
3482
3745
  if (format === "json") {
3483
3746
  console.log(JSON.stringify({ project, removed: true }, null, 2));
@@ -3584,12 +3847,12 @@ var SCHEDULE_CLI_COMMANDS = [
3584
3847
  ];
3585
3848
 
3586
3849
  // src/commands/settings.ts
3587
- function getClient14() {
3850
+ function getClient15() {
3588
3851
  const config = loadConfig();
3589
3852
  return new ApiClient(config.apiUrl, config.apiKey);
3590
3853
  }
3591
3854
  async function setProvider(name, opts) {
3592
- const client = getClient14();
3855
+ const client = getClient15();
3593
3856
  const { format, ...payload } = opts;
3594
3857
  const result = await client.updateProvider(name, payload);
3595
3858
  if (format === "json") {
@@ -3605,7 +3868,7 @@ async function setProvider(name, opts) {
3605
3868
  }
3606
3869
  }
3607
3870
  async function showSettings(format) {
3608
- const client = getClient14();
3871
+ const client = getClient15();
3609
3872
  const config = loadConfig();
3610
3873
  const settings = await client.getSettings();
3611
3874
  if (format === "json") {
@@ -4674,7 +4937,8 @@ var REGISTERED_CLI_COMMANDS = [
4674
4937
  ...NOTIFY_CLI_COMMANDS,
4675
4938
  ...GOOGLE_CLI_COMMANDS,
4676
4939
  ...BING_CLI_COMMANDS,
4677
- ...CDP_CLI_COMMANDS
4940
+ ...CDP_CLI_COMMANDS,
4941
+ ...GA_CLI_COMMANDS
4678
4942
  ];
4679
4943
 
4680
4944
  // src/cli.ts