@ainyc/canonry 1.16.0 → 1.19.2
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/assets/assets/index-BIXLW5Li.js +246 -0
- package/assets/assets/index-DdQKI2_i.css +1 -0
- package/assets/index.html +2 -2
- package/dist/{chunk-RU7RHCWK.js → chunk-GX673NKZ.js} +1426 -120
- package/dist/cli.js +310 -36
- package/dist/index.d.ts +6 -0
- package/dist/index.js +1 -1
- package/package.json +7 -5
- package/assets/assets/index-s0lvtR39.js +0 -246
- package/assets/assets/index-slXPFOsf.css +0 -1
package/dist/cli.js
CHANGED
|
@@ -15,11 +15,12 @@ import {
|
|
|
15
15
|
migrate,
|
|
16
16
|
notificationEventSchema,
|
|
17
17
|
providerQuotaPolicySchema,
|
|
18
|
+
resolveProviderInput,
|
|
18
19
|
saveConfig,
|
|
19
20
|
setGoogleAuthConfig,
|
|
20
21
|
showFirstRunNotice,
|
|
21
22
|
trackEvent
|
|
22
|
-
} from "./chunk-
|
|
23
|
+
} from "./chunk-GX673NKZ.js";
|
|
23
24
|
|
|
24
25
|
// src/cli.ts
|
|
25
26
|
import { parseArgs } from "util";
|
|
@@ -673,10 +674,33 @@ var ApiClient = class {
|
|
|
673
674
|
async gscDiscoverSitemaps(project) {
|
|
674
675
|
return this.request("POST", `/projects/${encodeURIComponent(project)}/google/gsc/discover-sitemaps`, {});
|
|
675
676
|
}
|
|
677
|
+
// Analytics
|
|
678
|
+
async getAnalyticsMetrics(project, window) {
|
|
679
|
+
const qs = window ? `?window=${encodeURIComponent(window)}` : "";
|
|
680
|
+
return this.request("GET", `/projects/${encodeURIComponent(project)}/analytics/metrics${qs}`);
|
|
681
|
+
}
|
|
682
|
+
async getAnalyticsGaps(project, window) {
|
|
683
|
+
const qs = window ? `?window=${encodeURIComponent(window)}` : "";
|
|
684
|
+
return this.request("GET", `/projects/${encodeURIComponent(project)}/analytics/gaps${qs}`);
|
|
685
|
+
}
|
|
686
|
+
async getAnalyticsSources(project, window) {
|
|
687
|
+
const qs = window ? `?window=${encodeURIComponent(window)}` : "";
|
|
688
|
+
return this.request("GET", `/projects/${encodeURIComponent(project)}/analytics/sources${qs}`);
|
|
689
|
+
}
|
|
676
690
|
// Google Indexing API
|
|
677
691
|
async googleRequestIndexing(project, body) {
|
|
678
692
|
return this.request("POST", `/projects/${encodeURIComponent(project)}/google/indexing/request`, body);
|
|
679
693
|
}
|
|
694
|
+
// CDP browser provider
|
|
695
|
+
async getCdpStatus() {
|
|
696
|
+
return this.request("GET", "/cdp/status");
|
|
697
|
+
}
|
|
698
|
+
async cdpScreenshot(query, targets) {
|
|
699
|
+
return this.request("POST", "/cdp/screenshot", { query, targets });
|
|
700
|
+
}
|
|
701
|
+
async getBrowserDiff(project, runId) {
|
|
702
|
+
return this.request("GET", `/projects/${encodeURIComponent(project)}/runs/${encodeURIComponent(runId)}/browser-diff`);
|
|
703
|
+
}
|
|
680
704
|
};
|
|
681
705
|
|
|
682
706
|
// src/commands/project.ts
|
|
@@ -926,7 +950,9 @@ async function triggerRun(project, opts) {
|
|
|
926
950
|
const client = getClient4();
|
|
927
951
|
const body = {};
|
|
928
952
|
if (opts?.provider) {
|
|
929
|
-
|
|
953
|
+
const providerInputs = opts.provider.split(",").map((s) => s.trim()).filter(Boolean);
|
|
954
|
+
const resolved = providerInputs.flatMap((p) => resolveProviderInput(p));
|
|
955
|
+
body.providers = resolved.length > 0 ? resolved : providerInputs;
|
|
930
956
|
}
|
|
931
957
|
if (opts?.location) {
|
|
932
958
|
body.location = opts.location;
|
|
@@ -1020,7 +1046,9 @@ async function triggerRunAll(opts) {
|
|
|
1020
1046
|
}
|
|
1021
1047
|
const body = {};
|
|
1022
1048
|
if (opts?.provider) {
|
|
1023
|
-
|
|
1049
|
+
const providerInputs = opts.provider.split(",").map((s) => s.trim()).filter(Boolean);
|
|
1050
|
+
const resolved = providerInputs.flatMap((p) => resolveProviderInput(p));
|
|
1051
|
+
body.providers = resolved.length > 0 ? resolved : providerInputs;
|
|
1024
1052
|
}
|
|
1025
1053
|
const results = [];
|
|
1026
1054
|
for (const p of projects) {
|
|
@@ -1226,6 +1254,107 @@ async function showHistory(project, format) {
|
|
|
1226
1254
|
}
|
|
1227
1255
|
}
|
|
1228
1256
|
|
|
1257
|
+
// src/commands/analytics.ts
|
|
1258
|
+
function getClient8() {
|
|
1259
|
+
const config = loadConfig();
|
|
1260
|
+
return new ApiClient(config.apiUrl, config.apiKey);
|
|
1261
|
+
}
|
|
1262
|
+
async function showAnalytics(project, options) {
|
|
1263
|
+
const client = getClient8();
|
|
1264
|
+
const features = options.feature ? [options.feature] : ["metrics", "gaps", "sources"];
|
|
1265
|
+
const results = {};
|
|
1266
|
+
for (const feature of features) {
|
|
1267
|
+
switch (feature) {
|
|
1268
|
+
case "metrics": {
|
|
1269
|
+
const data = await client.getAnalyticsMetrics(project, options.window);
|
|
1270
|
+
results.metrics = data;
|
|
1271
|
+
if (options.format !== "json") printMetrics(data);
|
|
1272
|
+
break;
|
|
1273
|
+
}
|
|
1274
|
+
case "gaps": {
|
|
1275
|
+
const data = await client.getAnalyticsGaps(project, options.window);
|
|
1276
|
+
results.gaps = data;
|
|
1277
|
+
if (options.format !== "json") printGaps(data);
|
|
1278
|
+
break;
|
|
1279
|
+
}
|
|
1280
|
+
case "sources": {
|
|
1281
|
+
const data = await client.getAnalyticsSources(project, options.window);
|
|
1282
|
+
results.sources = data;
|
|
1283
|
+
if (options.format !== "json") printSources(data);
|
|
1284
|
+
break;
|
|
1285
|
+
}
|
|
1286
|
+
default:
|
|
1287
|
+
console.error(`Unknown feature: ${feature}. Use: metrics, gaps, sources`);
|
|
1288
|
+
process.exit(1);
|
|
1289
|
+
}
|
|
1290
|
+
}
|
|
1291
|
+
if (options.format === "json") {
|
|
1292
|
+
console.log(JSON.stringify(results, null, 2));
|
|
1293
|
+
}
|
|
1294
|
+
}
|
|
1295
|
+
function printMetrics(data) {
|
|
1296
|
+
console.log(`
|
|
1297
|
+
Citation Rate Trends (${data.window})`);
|
|
1298
|
+
console.log("\u2500".repeat(50));
|
|
1299
|
+
const pct = (n) => `${(n * 100).toFixed(1)}%`;
|
|
1300
|
+
console.log(` Overall: ${pct(data.overall.citationRate)} (${data.overall.cited}/${data.overall.total})`);
|
|
1301
|
+
console.log(` Trend: ${data.trend}`);
|
|
1302
|
+
if (Object.keys(data.byProvider).length > 0) {
|
|
1303
|
+
console.log(`
|
|
1304
|
+
By Provider:`);
|
|
1305
|
+
for (const [provider, metric] of Object.entries(data.byProvider)) {
|
|
1306
|
+
console.log(` ${provider.padEnd(10)} ${pct(metric.citationRate).padStart(6)} (${metric.cited}/${metric.total})`);
|
|
1307
|
+
}
|
|
1308
|
+
}
|
|
1309
|
+
if (data.buckets.length > 0) {
|
|
1310
|
+
console.log(`
|
|
1311
|
+
Timeline:`);
|
|
1312
|
+
for (const bucket of data.buckets) {
|
|
1313
|
+
const start = bucket.startDate.slice(0, 10);
|
|
1314
|
+
const bar = bucket.total > 0 ? "\u2588".repeat(Math.round(bucket.citationRate * 20)) : "";
|
|
1315
|
+
console.log(` ${start} ${pct(bucket.citationRate).padStart(6)} ${bar}`);
|
|
1316
|
+
}
|
|
1317
|
+
}
|
|
1318
|
+
}
|
|
1319
|
+
function printGaps(data) {
|
|
1320
|
+
console.log(`
|
|
1321
|
+
Brand Gap Analysis`);
|
|
1322
|
+
console.log("\u2500".repeat(50));
|
|
1323
|
+
console.log(` Cited: ${data.cited.length} | Gap: ${data.gap.length} | Uncited: ${data.uncited.length}`);
|
|
1324
|
+
if (data.gap.length > 0) {
|
|
1325
|
+
console.log(`
|
|
1326
|
+
Opportunity Gaps (competitors cited, you're not):`);
|
|
1327
|
+
for (const kw of data.gap) {
|
|
1328
|
+
const competitors = kw.competitorsCiting.join(", ");
|
|
1329
|
+
const cons = kw.consistency.totalRuns > 0 ? ` [cited ${kw.consistency.citedRuns}/${kw.consistency.totalRuns} runs]` : "";
|
|
1330
|
+
console.log(` \u2022 ${kw.keyword}${cons}`);
|
|
1331
|
+
console.log(` Competitors: ${competitors}`);
|
|
1332
|
+
}
|
|
1333
|
+
}
|
|
1334
|
+
if (data.cited.length > 0) {
|
|
1335
|
+
console.log(`
|
|
1336
|
+
Cited Keywords:`);
|
|
1337
|
+
for (const kw of data.cited) {
|
|
1338
|
+
const cons = kw.consistency.totalRuns > 0 ? ` [${kw.consistency.citedRuns}/${kw.consistency.totalRuns} runs]` : "";
|
|
1339
|
+
console.log(` \u2713 ${kw.keyword} (${kw.providers.join(", ")})${cons}`);
|
|
1340
|
+
}
|
|
1341
|
+
}
|
|
1342
|
+
}
|
|
1343
|
+
function printSources(data) {
|
|
1344
|
+
console.log(`
|
|
1345
|
+
Source Origin Breakdown`);
|
|
1346
|
+
console.log("\u2500".repeat(50));
|
|
1347
|
+
if (data.overall.length === 0) {
|
|
1348
|
+
console.log(" No source data available");
|
|
1349
|
+
return;
|
|
1350
|
+
}
|
|
1351
|
+
for (const cat of data.overall) {
|
|
1352
|
+
const pct = `${(cat.percentage * 100).toFixed(1)}%`;
|
|
1353
|
+
const domains = cat.topDomains.slice(0, 3).map((d) => d.domain).join(", ");
|
|
1354
|
+
console.log(` ${cat.label.padEnd(20)} ${pct.padStart(6)} (${cat.count}) ${domains}`);
|
|
1355
|
+
}
|
|
1356
|
+
}
|
|
1357
|
+
|
|
1229
1358
|
// src/commands/apply.ts
|
|
1230
1359
|
import fs4 from "fs";
|
|
1231
1360
|
import { parseAllDocuments } from "yaml";
|
|
@@ -1279,13 +1408,99 @@ async function exportProject(project, opts) {
|
|
|
1279
1408
|
console.log(stringify(data));
|
|
1280
1409
|
}
|
|
1281
1410
|
|
|
1411
|
+
// src/commands/cdp.ts
|
|
1412
|
+
function getClient9() {
|
|
1413
|
+
const config = loadConfig();
|
|
1414
|
+
return new ApiClient(config.apiUrl, config.apiKey);
|
|
1415
|
+
}
|
|
1416
|
+
async function cdpConnect(opts) {
|
|
1417
|
+
const config = loadConfig();
|
|
1418
|
+
const host = opts.host ?? "localhost";
|
|
1419
|
+
const port = parseInt(opts.port ?? "9222", 10);
|
|
1420
|
+
config.cdp = {
|
|
1421
|
+
...config.cdp,
|
|
1422
|
+
host,
|
|
1423
|
+
port
|
|
1424
|
+
};
|
|
1425
|
+
saveConfig(config);
|
|
1426
|
+
console.log(`CDP endpoint configured: ws://${host}:${port}`);
|
|
1427
|
+
console.log("Restart canonry server for changes to take effect.");
|
|
1428
|
+
}
|
|
1429
|
+
async function cdpStatus() {
|
|
1430
|
+
const client = getClient9();
|
|
1431
|
+
try {
|
|
1432
|
+
const status = await client.getCdpStatus();
|
|
1433
|
+
if (status.connected) {
|
|
1434
|
+
console.log(`CDP connected: ${status.endpoint}`);
|
|
1435
|
+
if (status.browserVersion) console.log(`Browser: ${status.browserVersion}`);
|
|
1436
|
+
if (status.targets?.length) {
|
|
1437
|
+
console.log("\nTargets:");
|
|
1438
|
+
for (const t of status.targets) {
|
|
1439
|
+
const status_label = t.alive ? "\u25CF alive" : "\u25CB idle";
|
|
1440
|
+
const lastUsed = t.lastUsed ? ` (last used: ${t.lastUsed})` : "";
|
|
1441
|
+
console.log(` ${t.name}: ${status_label}${lastUsed}`);
|
|
1442
|
+
}
|
|
1443
|
+
}
|
|
1444
|
+
} else {
|
|
1445
|
+
console.log(`CDP not connected at ${status.endpoint}`);
|
|
1446
|
+
console.log("Launch Chrome with: chrome --remote-debugging-port=9222");
|
|
1447
|
+
}
|
|
1448
|
+
} catch (err) {
|
|
1449
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
1450
|
+
if (msg.includes("501") || msg.includes("not configured")) {
|
|
1451
|
+
console.log("CDP not configured. Run: canonry cdp connect --host <host> --port <port>");
|
|
1452
|
+
} else {
|
|
1453
|
+
console.error(`Error checking CDP status: ${msg}`);
|
|
1454
|
+
}
|
|
1455
|
+
}
|
|
1456
|
+
}
|
|
1457
|
+
async function cdpTargets() {
|
|
1458
|
+
await cdpStatus();
|
|
1459
|
+
}
|
|
1460
|
+
async function cdpScreenshot(query, opts) {
|
|
1461
|
+
if (!query) {
|
|
1462
|
+
console.error("Error: query is required");
|
|
1463
|
+
console.error('Usage: canonry cdp screenshot "best coffee in NYC"');
|
|
1464
|
+
process.exit(1);
|
|
1465
|
+
}
|
|
1466
|
+
const client = getClient9();
|
|
1467
|
+
const body = { query };
|
|
1468
|
+
if (opts?.targets) {
|
|
1469
|
+
body.targets = opts.targets.split(",").map((s) => s.trim());
|
|
1470
|
+
}
|
|
1471
|
+
try {
|
|
1472
|
+
const response = await client.cdpScreenshot(query, body.targets);
|
|
1473
|
+
for (const r of response.results) {
|
|
1474
|
+
console.log(`
|
|
1475
|
+
--- ${r.target} ---`);
|
|
1476
|
+
console.log(`Screenshot: ${r.screenshotPath}`);
|
|
1477
|
+
if (r.citations.length > 0) {
|
|
1478
|
+
console.log("Citations:");
|
|
1479
|
+
for (const c of r.citations) {
|
|
1480
|
+
console.log(` ${c.title}: ${c.uri}`);
|
|
1481
|
+
}
|
|
1482
|
+
} else {
|
|
1483
|
+
console.log("No citations found.");
|
|
1484
|
+
}
|
|
1485
|
+
if (r.answerText) {
|
|
1486
|
+
const preview = r.answerText.length > 200 ? r.answerText.slice(0, 200) + "..." : r.answerText;
|
|
1487
|
+
console.log(`Answer preview: ${preview}`);
|
|
1488
|
+
}
|
|
1489
|
+
}
|
|
1490
|
+
} catch (err) {
|
|
1491
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
1492
|
+
console.error(`CDP screenshot failed: ${msg}`);
|
|
1493
|
+
process.exit(1);
|
|
1494
|
+
}
|
|
1495
|
+
}
|
|
1496
|
+
|
|
1282
1497
|
// src/commands/settings.ts
|
|
1283
|
-
function
|
|
1498
|
+
function getClient10() {
|
|
1284
1499
|
const config = loadConfig();
|
|
1285
1500
|
return new ApiClient(config.apiUrl, config.apiKey);
|
|
1286
1501
|
}
|
|
1287
1502
|
async function setProvider(name, opts) {
|
|
1288
|
-
const client =
|
|
1503
|
+
const client = getClient10();
|
|
1289
1504
|
const result = await client.updateProvider(name, opts);
|
|
1290
1505
|
console.log(`Provider ${result.name} updated successfully.`);
|
|
1291
1506
|
if (result.model) {
|
|
@@ -1296,7 +1511,7 @@ async function setProvider(name, opts) {
|
|
|
1296
1511
|
}
|
|
1297
1512
|
}
|
|
1298
1513
|
async function showSettings(format) {
|
|
1299
|
-
const client =
|
|
1514
|
+
const client = getClient10();
|
|
1300
1515
|
const config = loadConfig();
|
|
1301
1516
|
const settings = await client.getSettings();
|
|
1302
1517
|
if (format === "json") {
|
|
@@ -1334,12 +1549,12 @@ function setGoogleAuth(opts) {
|
|
|
1334
1549
|
}
|
|
1335
1550
|
|
|
1336
1551
|
// src/commands/schedule.ts
|
|
1337
|
-
function
|
|
1552
|
+
function getClient11() {
|
|
1338
1553
|
const config = loadConfig();
|
|
1339
1554
|
return new ApiClient(config.apiUrl, config.apiKey);
|
|
1340
1555
|
}
|
|
1341
1556
|
async function setSchedule(project, opts) {
|
|
1342
|
-
const client =
|
|
1557
|
+
const client = getClient11();
|
|
1343
1558
|
const body = {};
|
|
1344
1559
|
if (opts.preset) body.preset = opts.preset;
|
|
1345
1560
|
if (opts.cron) body.cron = opts.cron;
|
|
@@ -1350,7 +1565,7 @@ async function setSchedule(project, opts) {
|
|
|
1350
1565
|
printSchedule(result);
|
|
1351
1566
|
}
|
|
1352
1567
|
async function showSchedule(project, format) {
|
|
1353
|
-
const client =
|
|
1568
|
+
const client = getClient11();
|
|
1354
1569
|
const result = await client.getSchedule(project);
|
|
1355
1570
|
if (format === "json") {
|
|
1356
1571
|
console.log(JSON.stringify(result, null, 2));
|
|
@@ -1359,7 +1574,7 @@ async function showSchedule(project, format) {
|
|
|
1359
1574
|
printSchedule(result);
|
|
1360
1575
|
}
|
|
1361
1576
|
async function enableSchedule(project) {
|
|
1362
|
-
const client =
|
|
1577
|
+
const client = getClient11();
|
|
1363
1578
|
const current = await client.getSchedule(project);
|
|
1364
1579
|
const body = { timezone: current.timezone };
|
|
1365
1580
|
if (current.preset) body.preset = current.preset;
|
|
@@ -1369,7 +1584,7 @@ async function enableSchedule(project) {
|
|
|
1369
1584
|
console.log(`Schedule enabled for "${project}"`);
|
|
1370
1585
|
}
|
|
1371
1586
|
async function disableSchedule(project) {
|
|
1372
|
-
const client =
|
|
1587
|
+
const client = getClient11();
|
|
1373
1588
|
const current = await client.getSchedule(project);
|
|
1374
1589
|
const body = { timezone: current.timezone, enabled: false };
|
|
1375
1590
|
if (current.preset) body.preset = current.preset;
|
|
@@ -1379,7 +1594,7 @@ async function disableSchedule(project) {
|
|
|
1379
1594
|
console.log(`Schedule disabled for "${project}"`);
|
|
1380
1595
|
}
|
|
1381
1596
|
async function removeSchedule(project) {
|
|
1382
|
-
const client =
|
|
1597
|
+
const client = getClient11();
|
|
1383
1598
|
await client.deleteSchedule(project);
|
|
1384
1599
|
console.log(`Schedule removed for "${project}"`);
|
|
1385
1600
|
}
|
|
@@ -1401,12 +1616,12 @@ function printSchedule(s) {
|
|
|
1401
1616
|
}
|
|
1402
1617
|
|
|
1403
1618
|
// src/commands/notify.ts
|
|
1404
|
-
function
|
|
1619
|
+
function getClient12() {
|
|
1405
1620
|
const config = loadConfig();
|
|
1406
1621
|
return new ApiClient(config.apiUrl, config.apiKey);
|
|
1407
1622
|
}
|
|
1408
1623
|
async function addNotification(project, opts) {
|
|
1409
|
-
const client =
|
|
1624
|
+
const client = getClient12();
|
|
1410
1625
|
const result = await client.createNotification(project, {
|
|
1411
1626
|
channel: "webhook",
|
|
1412
1627
|
url: opts.webhook,
|
|
@@ -1416,7 +1631,7 @@ async function addNotification(project, opts) {
|
|
|
1416
1631
|
printNotification(result);
|
|
1417
1632
|
}
|
|
1418
1633
|
async function listNotifications(project, format) {
|
|
1419
|
-
const client =
|
|
1634
|
+
const client = getClient12();
|
|
1420
1635
|
const results = await client.listNotifications(project);
|
|
1421
1636
|
if (format === "json") {
|
|
1422
1637
|
console.log(JSON.stringify(results, null, 2));
|
|
@@ -1434,12 +1649,12 @@ async function listNotifications(project, format) {
|
|
|
1434
1649
|
}
|
|
1435
1650
|
}
|
|
1436
1651
|
async function removeNotification(project, id) {
|
|
1437
|
-
const client =
|
|
1652
|
+
const client = getClient12();
|
|
1438
1653
|
await client.deleteNotification(project, id);
|
|
1439
1654
|
console.log(`Notification ${id} removed from "${project}"`);
|
|
1440
1655
|
}
|
|
1441
1656
|
async function testNotification(project, id) {
|
|
1442
|
-
const client =
|
|
1657
|
+
const client = getClient12();
|
|
1443
1658
|
const result = await client.testNotification(project, id);
|
|
1444
1659
|
if (result.ok) {
|
|
1445
1660
|
console.log(`Test webhook delivered successfully (HTTP ${result.status})`);
|
|
@@ -1531,12 +1746,12 @@ function telemetryCommand(subcommand) {
|
|
|
1531
1746
|
}
|
|
1532
1747
|
|
|
1533
1748
|
// src/commands/google.ts
|
|
1534
|
-
function
|
|
1749
|
+
function getClient13() {
|
|
1535
1750
|
const config = loadConfig();
|
|
1536
1751
|
return new ApiClient(config.apiUrl, config.apiKey);
|
|
1537
1752
|
}
|
|
1538
1753
|
async function googleConnect(project, opts) {
|
|
1539
|
-
const client =
|
|
1754
|
+
const client = getClient13();
|
|
1540
1755
|
const { authUrl, redirectUri } = await client.googleConnect(project, {
|
|
1541
1756
|
type: opts.type,
|
|
1542
1757
|
publicUrl: opts.publicUrl
|
|
@@ -1561,12 +1776,12 @@ Open this URL in your browser to authorize Google ${opts.type.toUpperCase()} acc
|
|
|
1561
1776
|
}
|
|
1562
1777
|
}
|
|
1563
1778
|
async function googleDisconnect(project, opts) {
|
|
1564
|
-
const client =
|
|
1779
|
+
const client = getClient13();
|
|
1565
1780
|
await client.googleDisconnect(project, opts.type);
|
|
1566
1781
|
console.log(`Disconnected Google ${opts.type.toUpperCase()} from project "${project}".`);
|
|
1567
1782
|
}
|
|
1568
1783
|
async function googleStatus(project, format) {
|
|
1569
|
-
const client =
|
|
1784
|
+
const client = getClient13();
|
|
1570
1785
|
const connections = await client.googleConnections(project);
|
|
1571
1786
|
if (format === "json") {
|
|
1572
1787
|
console.log(JSON.stringify({ connections }, null, 2));
|
|
@@ -1590,7 +1805,7 @@ async function googleStatus(project, format) {
|
|
|
1590
1805
|
}
|
|
1591
1806
|
}
|
|
1592
1807
|
async function googleProperties(project, format) {
|
|
1593
|
-
const client =
|
|
1808
|
+
const client = getClient13();
|
|
1594
1809
|
const { sites } = await client.googleProperties(project);
|
|
1595
1810
|
if (format === "json") {
|
|
1596
1811
|
console.log(JSON.stringify({ sites }, null, 2));
|
|
@@ -1611,12 +1826,12 @@ async function googleProperties(project, format) {
|
|
|
1611
1826
|
Use "canonry google set-property <project> <siteUrl>" to select a property.`);
|
|
1612
1827
|
}
|
|
1613
1828
|
async function googleSetProperty(project, propertyUrl) {
|
|
1614
|
-
const client =
|
|
1829
|
+
const client = getClient13();
|
|
1615
1830
|
await client.googleSetProperty(project, "gsc", propertyUrl);
|
|
1616
1831
|
console.log(`GSC property set to "${propertyUrl}" for project "${project}".`);
|
|
1617
1832
|
}
|
|
1618
1833
|
async function googleSync(project, opts) {
|
|
1619
|
-
const client =
|
|
1834
|
+
const client = getClient13();
|
|
1620
1835
|
const run = await client.gscSync(project, { days: opts.days, full: opts.full });
|
|
1621
1836
|
if (opts.format === "json") {
|
|
1622
1837
|
console.log(JSON.stringify(run, null, 2));
|
|
@@ -1647,7 +1862,7 @@ async function googleSync(project, opts) {
|
|
|
1647
1862
|
}
|
|
1648
1863
|
}
|
|
1649
1864
|
async function googlePerformance(project, opts) {
|
|
1650
|
-
const client =
|
|
1865
|
+
const client = getClient13();
|
|
1651
1866
|
const params = {};
|
|
1652
1867
|
if (opts.days) {
|
|
1653
1868
|
const end = /* @__PURE__ */ new Date();
|
|
@@ -1683,7 +1898,7 @@ async function googlePerformance(project, opts) {
|
|
|
1683
1898
|
}
|
|
1684
1899
|
}
|
|
1685
1900
|
async function googleInspect(project, url, format) {
|
|
1686
|
-
const client =
|
|
1901
|
+
const client = getClient13();
|
|
1687
1902
|
const result = await client.gscInspect(project, url);
|
|
1688
1903
|
if (format === "json") {
|
|
1689
1904
|
console.log(JSON.stringify(result, null, 2));
|
|
@@ -1703,7 +1918,7 @@ URL Inspection: ${result.url}
|
|
|
1703
1918
|
console.log(` Inspected At: ${result.inspectedAt}`);
|
|
1704
1919
|
}
|
|
1705
1920
|
async function googleInspections(project, opts) {
|
|
1706
|
-
const client =
|
|
1921
|
+
const client = getClient13();
|
|
1707
1922
|
const params = {};
|
|
1708
1923
|
if (opts.url) params.url = opts.url;
|
|
1709
1924
|
const rows = await client.gscInspections(project, Object.keys(params).length > 0 ? params : void 0);
|
|
@@ -1728,7 +1943,7 @@ async function googleInspections(project, opts) {
|
|
|
1728
1943
|
}
|
|
1729
1944
|
}
|
|
1730
1945
|
async function googleCoverage(project, format) {
|
|
1731
|
-
const client =
|
|
1946
|
+
const client = getClient13();
|
|
1732
1947
|
const result = await client.gscCoverage(project);
|
|
1733
1948
|
if (format === "json") {
|
|
1734
1949
|
console.log(JSON.stringify(result, null, 2));
|
|
@@ -1774,12 +1989,12 @@ Index Coverage for "${project}"
|
|
|
1774
1989
|
}
|
|
1775
1990
|
}
|
|
1776
1991
|
async function googleSetSitemap(project, sitemapUrl) {
|
|
1777
|
-
const client =
|
|
1992
|
+
const client = getClient13();
|
|
1778
1993
|
await client.googleSetSitemap(project, "gsc", sitemapUrl);
|
|
1779
1994
|
console.log(`GSC sitemap URL set to "${sitemapUrl}" for project "${project}".`);
|
|
1780
1995
|
}
|
|
1781
1996
|
async function googleListSitemaps(project, opts) {
|
|
1782
|
-
const client =
|
|
1997
|
+
const client = getClient13();
|
|
1783
1998
|
const result = await client.gscSitemaps(project);
|
|
1784
1999
|
if (opts.format === "json") {
|
|
1785
2000
|
console.log(JSON.stringify(result, null, 2));
|
|
@@ -1801,7 +2016,7 @@ Sitemaps for project "${project}":
|
|
|
1801
2016
|
}
|
|
1802
2017
|
}
|
|
1803
2018
|
async function googleInspectSitemap(project, opts) {
|
|
1804
|
-
const client =
|
|
2019
|
+
const client = getClient13();
|
|
1805
2020
|
const run = await client.gscInspectSitemap(project, {
|
|
1806
2021
|
sitemapUrl: opts.sitemapUrl
|
|
1807
2022
|
});
|
|
@@ -1836,7 +2051,7 @@ async function googleInspectSitemap(project, opts) {
|
|
|
1836
2051
|
}
|
|
1837
2052
|
}
|
|
1838
2053
|
async function googleCoverageHistory(project, opts) {
|
|
1839
|
-
const client =
|
|
2054
|
+
const client = getClient13();
|
|
1840
2055
|
const rows = await client.gscCoverageHistory(project, { limit: opts.limit });
|
|
1841
2056
|
if (opts.format === "json") {
|
|
1842
2057
|
console.log(JSON.stringify(rows, null, 2));
|
|
@@ -1858,7 +2073,7 @@ GSC Coverage History for "${project}" (${rows.length} snapshots):
|
|
|
1858
2073
|
}
|
|
1859
2074
|
}
|
|
1860
2075
|
async function googleDiscoverSitemaps(project, opts) {
|
|
1861
|
-
const client =
|
|
2076
|
+
const client = getClient13();
|
|
1862
2077
|
const result = await client.gscDiscoverSitemaps(project);
|
|
1863
2078
|
if (opts.format === "json") {
|
|
1864
2079
|
console.log(JSON.stringify(result, null, 2));
|
|
@@ -1903,7 +2118,7 @@ Primary sitemap: ${result.primarySitemapUrl}`);
|
|
|
1903
2118
|
}
|
|
1904
2119
|
}
|
|
1905
2120
|
async function googleRequestIndexing(project, opts) {
|
|
1906
|
-
const client =
|
|
2121
|
+
const client = getClient13();
|
|
1907
2122
|
const body = { urls: [] };
|
|
1908
2123
|
if (opts.allUnindexed) {
|
|
1909
2124
|
body.allUnindexed = true;
|
|
@@ -1965,7 +2180,7 @@ async function googleRequestIndexing(project, opts) {
|
|
|
1965
2180
|
}
|
|
1966
2181
|
}
|
|
1967
2182
|
async function googleDeindexed(project, format) {
|
|
1968
|
-
const client =
|
|
2183
|
+
const client = getClient13();
|
|
1969
2184
|
const rows = await client.gscDeindexed(project);
|
|
1970
2185
|
if (format === "json") {
|
|
1971
2186
|
console.log(JSON.stringify(rows, null, 2));
|
|
@@ -2023,6 +2238,7 @@ Usage:
|
|
|
2023
2238
|
canonry runs <project> List runs for a project
|
|
2024
2239
|
canonry status <project> Show project summary
|
|
2025
2240
|
canonry evidence <project> Show per-phrase results
|
|
2241
|
+
canonry analytics <project> Show analytics (--feature metrics|gaps|sources, --window 7d|30d|90d|all)
|
|
2026
2242
|
canonry history <project> Show audit trail
|
|
2027
2243
|
canonry export <project> Export project as YAML
|
|
2028
2244
|
canonry apply <file...> Apply declarative config (multi-doc YAML supported)
|
|
@@ -2080,7 +2296,7 @@ Options:
|
|
|
2080
2296
|
--display-name <name> Display name for project create/update
|
|
2081
2297
|
--country <code> Country code (default: US)
|
|
2082
2298
|
--language <lang> Language code (default: en)
|
|
2083
|
-
--provider <name> Provider to use (gemini, openai, claude, local)
|
|
2299
|
+
--provider <name> Provider to use (gemini, openai, claude, local, cdp:chatgpt, or cdp for all CDP targets)
|
|
2084
2300
|
--format <fmt> Output format: text (default) or json
|
|
2085
2301
|
--location <label> Run with a specific configured location
|
|
2086
2302
|
--all-locations Run for every configured location
|
|
@@ -2539,6 +2755,19 @@ async function main() {
|
|
|
2539
2755
|
await showHistory(project, format);
|
|
2540
2756
|
break;
|
|
2541
2757
|
}
|
|
2758
|
+
case "analytics": {
|
|
2759
|
+
const project = args[1];
|
|
2760
|
+
if (!project) {
|
|
2761
|
+
console.error("Error: project name is required");
|
|
2762
|
+
process.exit(1);
|
|
2763
|
+
}
|
|
2764
|
+
const featureIdx = args.indexOf("--feature");
|
|
2765
|
+
const feature = featureIdx !== -1 ? args[featureIdx + 1] : void 0;
|
|
2766
|
+
const windowIdx = args.indexOf("--window");
|
|
2767
|
+
const windowArg = windowIdx !== -1 ? args[windowIdx + 1] : void 0;
|
|
2768
|
+
await showAnalytics(project, { feature, window: windowArg, format });
|
|
2769
|
+
break;
|
|
2770
|
+
}
|
|
2542
2771
|
case "export": {
|
|
2543
2772
|
const project = args[1];
|
|
2544
2773
|
if (!project) {
|
|
@@ -3035,6 +3264,51 @@ async function main() {
|
|
|
3035
3264
|
}
|
|
3036
3265
|
break;
|
|
3037
3266
|
}
|
|
3267
|
+
case "cdp": {
|
|
3268
|
+
const subcommand = args[1];
|
|
3269
|
+
switch (subcommand) {
|
|
3270
|
+
case "connect": {
|
|
3271
|
+
const { values: connectValues } = parseArgs({
|
|
3272
|
+
args: args.slice(2),
|
|
3273
|
+
options: {
|
|
3274
|
+
host: { type: "string", default: "localhost" },
|
|
3275
|
+
port: { type: "string", default: "9222" }
|
|
3276
|
+
},
|
|
3277
|
+
allowPositionals: false
|
|
3278
|
+
});
|
|
3279
|
+
await cdpConnect({ host: connectValues.host, port: connectValues.port });
|
|
3280
|
+
break;
|
|
3281
|
+
}
|
|
3282
|
+
case "status":
|
|
3283
|
+
await cdpStatus();
|
|
3284
|
+
break;
|
|
3285
|
+
case "targets":
|
|
3286
|
+
await cdpTargets();
|
|
3287
|
+
break;
|
|
3288
|
+
case "screenshot": {
|
|
3289
|
+
const query = args[2];
|
|
3290
|
+
if (!query) {
|
|
3291
|
+
console.error("Error: query is required");
|
|
3292
|
+
console.error('Usage: canonry cdp screenshot "best coffee in NYC"');
|
|
3293
|
+
process.exit(1);
|
|
3294
|
+
}
|
|
3295
|
+
const { values: screenshotValues } = parseArgs({
|
|
3296
|
+
args: args.slice(3),
|
|
3297
|
+
options: {
|
|
3298
|
+
targets: { type: "string" }
|
|
3299
|
+
},
|
|
3300
|
+
allowPositionals: false
|
|
3301
|
+
});
|
|
3302
|
+
await cdpScreenshot(query, { targets: screenshotValues.targets });
|
|
3303
|
+
break;
|
|
3304
|
+
}
|
|
3305
|
+
default:
|
|
3306
|
+
console.error(`Unknown cdp subcommand: ${subcommand ?? "(none)"}`);
|
|
3307
|
+
console.log("Available: connect, status, targets, screenshot");
|
|
3308
|
+
process.exit(1);
|
|
3309
|
+
}
|
|
3310
|
+
break;
|
|
3311
|
+
}
|
|
3038
3312
|
default:
|
|
3039
3313
|
console.error(`Unknown command: ${command}`);
|
|
3040
3314
|
console.log('Run "canonry --help" for usage.');
|
package/dist/index.d.ts
CHANGED
|
@@ -9,6 +9,11 @@ interface ProviderConfigEntry {
|
|
|
9
9
|
model?: string;
|
|
10
10
|
quota?: ProviderQuotaPolicy;
|
|
11
11
|
}
|
|
12
|
+
interface CdpConfigEntry {
|
|
13
|
+
host?: string;
|
|
14
|
+
port?: number;
|
|
15
|
+
quota?: ProviderQuotaPolicy;
|
|
16
|
+
}
|
|
12
17
|
interface GoogleConnectionConfigEntry {
|
|
13
18
|
domain: string;
|
|
14
19
|
connectionType: GoogleConnectionType;
|
|
@@ -43,6 +48,7 @@ interface CanonryConfig {
|
|
|
43
48
|
claude?: ProviderConfigEntry;
|
|
44
49
|
local?: ProviderConfigEntry;
|
|
45
50
|
};
|
|
51
|
+
cdp?: CdpConfigEntry;
|
|
46
52
|
google?: GoogleConfigEntry;
|
|
47
53
|
telemetry?: boolean;
|
|
48
54
|
anonymousId?: string;
|
package/dist/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ainyc/canonry",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.19.2",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "The ultimate open-source AEO monitoring tool - track how answer engines cite your domain",
|
|
6
6
|
"license": "FSL-1.1-ALv2",
|
|
@@ -44,7 +44,8 @@
|
|
|
44
44
|
"openai": "^6.0.0",
|
|
45
45
|
"pino-pretty": "^13.1.3",
|
|
46
46
|
"yaml": "^2.7.1",
|
|
47
|
-
"zod": "^4.1.12"
|
|
47
|
+
"zod": "^4.1.12",
|
|
48
|
+
"chrome-remote-interface": "^0.33.2"
|
|
48
49
|
},
|
|
49
50
|
"devDependencies": {
|
|
50
51
|
"@types/better-sqlite3": "^7.6.13",
|
|
@@ -52,13 +53,14 @@
|
|
|
52
53
|
"tsup": "^8.5.1",
|
|
53
54
|
"tsx": "^4.19.0",
|
|
54
55
|
"@ainyc/canonry-api-routes": "0.0.0",
|
|
55
|
-
"@ainyc/canonry-contracts": "0.0.0",
|
|
56
56
|
"@ainyc/canonry-db": "0.0.0",
|
|
57
57
|
"@ainyc/canonry-config": "0.0.0",
|
|
58
|
-
"@ainyc/canonry-provider-gemini": "0.0.0",
|
|
59
|
-
"@ainyc/canonry-integration-google": "0.0.0",
|
|
60
58
|
"@ainyc/canonry-provider-claude": "0.0.0",
|
|
59
|
+
"@ainyc/canonry-contracts": "0.0.0",
|
|
60
|
+
"@ainyc/canonry-provider-cdp": "0.0.0",
|
|
61
|
+
"@ainyc/canonry-provider-gemini": "0.0.0",
|
|
61
62
|
"@ainyc/canonry-provider-openai": "0.0.0",
|
|
63
|
+
"@ainyc/canonry-integration-google": "0.0.0",
|
|
62
64
|
"@ainyc/canonry-provider-local": "0.0.0"
|
|
63
65
|
},
|
|
64
66
|
"scripts": {
|