@ainyc/canonry 1.12.0 → 1.13.3
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-BUh6m3HV.css +1 -0
- package/assets/assets/index-DOhW7c21.js +245 -0
- package/assets/index.html +2 -2
- package/dist/{chunk-O4HLQBL7.js → chunk-JKIWFSYI.js} +836 -78
- package/dist/cli.js +384 -8
- package/dist/index.js +1 -1
- package/package.json +3 -3
- package/assets/assets/index-BEsueXzg.css +0 -1
- package/assets/assets/index-Bol7Z6qk.js +0 -243
package/dist/cli.js
CHANGED
|
@@ -19,7 +19,7 @@ import {
|
|
|
19
19
|
setGoogleAuthConfig,
|
|
20
20
|
showFirstRunNotice,
|
|
21
21
|
trackEvent
|
|
22
|
-
} from "./chunk-
|
|
22
|
+
} from "./chunk-JKIWFSYI.js";
|
|
23
23
|
|
|
24
24
|
// src/cli.ts
|
|
25
25
|
import { parseArgs } from "util";
|
|
@@ -319,7 +319,7 @@ async function initCommand(opts) {
|
|
|
319
319
|
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
320
320
|
}).run();
|
|
321
321
|
saveConfig({
|
|
322
|
-
apiUrl:
|
|
322
|
+
apiUrl: `http://localhost:${process.env.CANONRY_PORT || "4100"}`,
|
|
323
323
|
database: databasePath,
|
|
324
324
|
apiKey: rawApiKey,
|
|
325
325
|
providers,
|
|
@@ -344,6 +344,7 @@ async function serveCommand() {
|
|
|
344
344
|
const config = loadConfig();
|
|
345
345
|
const port = parseInt(process.env.CANONRY_PORT ?? "4100", 10);
|
|
346
346
|
const host = process.env.CANONRY_HOST ?? "127.0.0.1";
|
|
347
|
+
config.port = port;
|
|
347
348
|
const db = createClient(config.database);
|
|
348
349
|
migrate(db);
|
|
349
350
|
const app = await createServer({ config, db });
|
|
@@ -476,16 +477,17 @@ var ApiClient = class {
|
|
|
476
477
|
}
|
|
477
478
|
async request(method, path4, body) {
|
|
478
479
|
const url = `${this.baseUrl}${path4}`;
|
|
480
|
+
const serializedBody = body != null ? JSON.stringify(body) : void 0;
|
|
479
481
|
const headers = {
|
|
480
482
|
"Authorization": `Bearer ${this.apiKey}`,
|
|
481
|
-
"Content-Type": "application/json"
|
|
483
|
+
...serializedBody != null ? { "Content-Type": "application/json" } : {}
|
|
482
484
|
};
|
|
483
485
|
let res;
|
|
484
486
|
try {
|
|
485
487
|
res = await fetch(url, {
|
|
486
488
|
method,
|
|
487
489
|
headers,
|
|
488
|
-
body:
|
|
490
|
+
body: serializedBody
|
|
489
491
|
});
|
|
490
492
|
} catch (err) {
|
|
491
493
|
const msg = err instanceof Error ? err.message : String(err);
|
|
@@ -529,6 +531,9 @@ var ApiClient = class {
|
|
|
529
531
|
async listKeywords(project) {
|
|
530
532
|
return this.request("GET", `/projects/${encodeURIComponent(project)}/keywords`);
|
|
531
533
|
}
|
|
534
|
+
async deleteKeywords(project, keywords) {
|
|
535
|
+
await this.request("DELETE", `/projects/${encodeURIComponent(project)}/keywords`, { keywords });
|
|
536
|
+
}
|
|
532
537
|
async appendKeywords(project, keywords) {
|
|
533
538
|
await this.request("POST", `/projects/${encodeURIComponent(project)}/keywords`, { keywords });
|
|
534
539
|
}
|
|
@@ -589,6 +594,18 @@ var ApiClient = class {
|
|
|
589
594
|
async testNotification(project, id) {
|
|
590
595
|
return this.request("POST", `/projects/${encodeURIComponent(project)}/notifications/${encodeURIComponent(id)}/test`);
|
|
591
596
|
}
|
|
597
|
+
async addLocation(project, body) {
|
|
598
|
+
return this.request("POST", `/projects/${encodeURIComponent(project)}/locations`, body);
|
|
599
|
+
}
|
|
600
|
+
async listLocations(project) {
|
|
601
|
+
return this.request("GET", `/projects/${encodeURIComponent(project)}/locations`);
|
|
602
|
+
}
|
|
603
|
+
async removeLocation(project, label) {
|
|
604
|
+
await this.request("DELETE", `/projects/${encodeURIComponent(project)}/locations/${encodeURIComponent(label)}`);
|
|
605
|
+
}
|
|
606
|
+
async setDefaultLocation(project, label) {
|
|
607
|
+
return this.request("PUT", `/projects/${encodeURIComponent(project)}/locations/default`, { label });
|
|
608
|
+
}
|
|
592
609
|
async getTelemetry() {
|
|
593
610
|
return this.request("GET", "/telemetry");
|
|
594
611
|
}
|
|
@@ -636,6 +653,16 @@ var ApiClient = class {
|
|
|
636
653
|
async gscDeindexed(project) {
|
|
637
654
|
return this.request("GET", `/projects/${encodeURIComponent(project)}/google/gsc/deindexed`);
|
|
638
655
|
}
|
|
656
|
+
async gscCoverage(project) {
|
|
657
|
+
return this.request("GET", `/projects/${encodeURIComponent(project)}/google/gsc/coverage`);
|
|
658
|
+
}
|
|
659
|
+
async gscCoverageHistory(project, params) {
|
|
660
|
+
const qs = params?.limit != null ? `?limit=${params.limit}` : "";
|
|
661
|
+
return this.request("GET", `/projects/${encodeURIComponent(project)}/google/gsc/coverage/history${qs}`);
|
|
662
|
+
}
|
|
663
|
+
async gscInspectSitemap(project, body) {
|
|
664
|
+
return this.request("POST", `/projects/${encodeURIComponent(project)}/google/gsc/inspect-sitemap`, body ?? {});
|
|
665
|
+
}
|
|
639
666
|
};
|
|
640
667
|
|
|
641
668
|
// src/commands/project.ts
|
|
@@ -734,6 +761,47 @@ async function deleteProject(name) {
|
|
|
734
761
|
await client.deleteProject(name);
|
|
735
762
|
console.log(`Project deleted: ${name}`);
|
|
736
763
|
}
|
|
764
|
+
async function addLocation(project, opts) {
|
|
765
|
+
const client = getClient();
|
|
766
|
+
await client.addLocation(project, opts);
|
|
767
|
+
console.log(`Location added: ${opts.label} (${opts.city}, ${opts.region}, ${opts.country})`);
|
|
768
|
+
}
|
|
769
|
+
async function listLocations(project, format) {
|
|
770
|
+
const client = getClient();
|
|
771
|
+
const result = await client.listLocations(project);
|
|
772
|
+
if (format === "json") {
|
|
773
|
+
console.log(JSON.stringify(result, null, 2));
|
|
774
|
+
return;
|
|
775
|
+
}
|
|
776
|
+
if (result.locations.length === 0) {
|
|
777
|
+
console.log(`No locations configured for "${project}".`);
|
|
778
|
+
return;
|
|
779
|
+
}
|
|
780
|
+
console.log(`Locations for "${project}" (${result.locations.length}):
|
|
781
|
+
`);
|
|
782
|
+
console.log(" LABEL CITY REGION COUNTRY DEFAULT");
|
|
783
|
+
console.log(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 \u2500\u2500\u2500\u2500\u2500\u2500\u2500 \u2500\u2500\u2500\u2500\u2500\u2500\u2500");
|
|
784
|
+
for (const loc of result.locations) {
|
|
785
|
+
const isDefault = loc.label === result.defaultLocation ? " *" : "";
|
|
786
|
+
console.log(
|
|
787
|
+
` ${loc.label.padEnd(15)} ${loc.city.padEnd(19)} ${loc.region.padEnd(19)} ${loc.country.padEnd(7)}${isDefault}`
|
|
788
|
+
);
|
|
789
|
+
}
|
|
790
|
+
if (result.defaultLocation) {
|
|
791
|
+
console.log(`
|
|
792
|
+
Default: ${result.defaultLocation}`);
|
|
793
|
+
}
|
|
794
|
+
}
|
|
795
|
+
async function removeLocation(project, label) {
|
|
796
|
+
const client = getClient();
|
|
797
|
+
await client.removeLocation(project, label);
|
|
798
|
+
console.log(`Location removed: ${label}`);
|
|
799
|
+
}
|
|
800
|
+
async function setDefaultLocation(project, label) {
|
|
801
|
+
const client = getClient();
|
|
802
|
+
await client.setDefaultLocation(project, label);
|
|
803
|
+
console.log(`Default location set to: ${label}`);
|
|
804
|
+
}
|
|
737
805
|
|
|
738
806
|
// src/commands/keyword.ts
|
|
739
807
|
import fs3 from "fs";
|
|
@@ -746,6 +814,14 @@ async function addKeywords(project, keywords) {
|
|
|
746
814
|
await client.appendKeywords(project, keywords);
|
|
747
815
|
console.log(`Added ${keywords.length} key phrase(s) to "${project}".`);
|
|
748
816
|
}
|
|
817
|
+
async function removeKeywords(project, keywords) {
|
|
818
|
+
const client = getClient2();
|
|
819
|
+
const existing = await client.listKeywords(project);
|
|
820
|
+
const existingSet = new Set(existing.map((k) => k.keyword));
|
|
821
|
+
const actuallyDeleted = keywords.filter((k) => existingSet.has(k)).length;
|
|
822
|
+
await client.deleteKeywords(project, keywords);
|
|
823
|
+
console.log(`Removed ${actuallyDeleted} key phrase(s) from "${project}".`);
|
|
824
|
+
}
|
|
749
825
|
async function listKeywords(project, format) {
|
|
750
826
|
const client = getClient2();
|
|
751
827
|
const kws = await client.listKeywords(project);
|
|
@@ -838,7 +914,63 @@ async function triggerRun(project, opts) {
|
|
|
838
914
|
if (opts?.provider) {
|
|
839
915
|
body.providers = [opts.provider];
|
|
840
916
|
}
|
|
841
|
-
|
|
917
|
+
if (opts?.location) {
|
|
918
|
+
body.location = opts.location;
|
|
919
|
+
}
|
|
920
|
+
if (opts?.allLocations) {
|
|
921
|
+
body.allLocations = true;
|
|
922
|
+
}
|
|
923
|
+
if (opts?.noLocation) {
|
|
924
|
+
body.noLocation = true;
|
|
925
|
+
}
|
|
926
|
+
const response = await client.triggerRun(project, body);
|
|
927
|
+
if (Array.isArray(response)) {
|
|
928
|
+
const locationRuns = response;
|
|
929
|
+
if (opts?.format === "json") {
|
|
930
|
+
if (opts?.wait) {
|
|
931
|
+
const settled = await Promise.all(
|
|
932
|
+
locationRuns.map(async (r) => {
|
|
933
|
+
if (!r.id || r.status === "conflict") return r;
|
|
934
|
+
const final = await pollRun(client, r.id);
|
|
935
|
+
return { ...r, ...final };
|
|
936
|
+
})
|
|
937
|
+
);
|
|
938
|
+
console.log(JSON.stringify(settled, null, 2));
|
|
939
|
+
} else {
|
|
940
|
+
console.log(JSON.stringify(locationRuns, null, 2));
|
|
941
|
+
}
|
|
942
|
+
return;
|
|
943
|
+
}
|
|
944
|
+
console.log(`Triggered ${locationRuns.length} location sweep(s) \u2014 ${locationRuns.length}\xD7 API calls:
|
|
945
|
+
`);
|
|
946
|
+
console.log(" LOCATION RUN ID STATUS");
|
|
947
|
+
console.log(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
|
|
948
|
+
for (const r of locationRuns) {
|
|
949
|
+
const loc = (r.location ?? "(unknown)").padEnd(15);
|
|
950
|
+
const id = (r.id ?? "(conflict)").padEnd(36);
|
|
951
|
+
console.log(` ${loc} ${id} ${r.status}`);
|
|
952
|
+
}
|
|
953
|
+
if (opts?.wait) {
|
|
954
|
+
const pending = locationRuns.filter((r) => r.id && r.status !== "conflict");
|
|
955
|
+
if (pending.length > 0) {
|
|
956
|
+
process.stderr.write(`Waiting for ${pending.length} run(s)`);
|
|
957
|
+
await Promise.all(
|
|
958
|
+
pending.map(async (r) => {
|
|
959
|
+
const final = await pollRun(client, r.id);
|
|
960
|
+
r.status = final.status;
|
|
961
|
+
})
|
|
962
|
+
);
|
|
963
|
+
process.stderr.write("\n");
|
|
964
|
+
console.log("\nFinal statuses:");
|
|
965
|
+
for (const r of locationRuns) {
|
|
966
|
+
const loc = (r.location ?? "(unknown)").padEnd(15);
|
|
967
|
+
console.log(` ${loc} ${r.status}`);
|
|
968
|
+
}
|
|
969
|
+
}
|
|
970
|
+
}
|
|
971
|
+
return;
|
|
972
|
+
}
|
|
973
|
+
const run = response;
|
|
842
974
|
if (opts?.wait) {
|
|
843
975
|
process.stderr.write(`Run ${run.id} started`);
|
|
844
976
|
const result = await pollRun(client, run.id);
|
|
@@ -1581,6 +1713,109 @@ async function googleInspections(project, opts) {
|
|
|
1581
1713
|
);
|
|
1582
1714
|
}
|
|
1583
1715
|
}
|
|
1716
|
+
async function googleCoverage(project, format) {
|
|
1717
|
+
const client = getClient11();
|
|
1718
|
+
const result = await client.gscCoverage(project);
|
|
1719
|
+
if (format === "json") {
|
|
1720
|
+
console.log(JSON.stringify(result, null, 2));
|
|
1721
|
+
return;
|
|
1722
|
+
}
|
|
1723
|
+
const { summary } = result;
|
|
1724
|
+
if (summary.total === 0) {
|
|
1725
|
+
console.log('No URL inspections found. Run "canonry google inspect-sitemap <project>" first.');
|
|
1726
|
+
return;
|
|
1727
|
+
}
|
|
1728
|
+
const pctColor = summary.percentage >= 80 ? "\x1B[32m" : summary.percentage >= 50 ? "\x1B[33m" : "\x1B[31m";
|
|
1729
|
+
const reset = "\x1B[0m";
|
|
1730
|
+
console.log(`
|
|
1731
|
+
Index Coverage for "${project}"
|
|
1732
|
+
`);
|
|
1733
|
+
console.log(` SUMMARY: ${pctColor}${summary.indexed} / ${summary.total} pages indexed (${summary.percentage}%)${reset}
|
|
1734
|
+
`);
|
|
1735
|
+
if (result.indexed.length > 0) {
|
|
1736
|
+
console.log(` INDEXED (${result.indexed.length}):`);
|
|
1737
|
+
for (const page of result.indexed) {
|
|
1738
|
+
const crawl = page.crawlTime ? ` (crawled: ${page.crawlTime.split("T")[0]})` : "";
|
|
1739
|
+
console.log(` ${page.url}${crawl}`);
|
|
1740
|
+
}
|
|
1741
|
+
console.log();
|
|
1742
|
+
}
|
|
1743
|
+
if (result.notIndexed.length > 0) {
|
|
1744
|
+
console.log(` NOT INDEXED (${result.notIndexed.length}):`);
|
|
1745
|
+
for (const page of result.notIndexed) {
|
|
1746
|
+
const reason = page.coverageState ? ` \u2014 ${page.coverageState}` : "";
|
|
1747
|
+
console.log(` ${page.url}${reason}`);
|
|
1748
|
+
}
|
|
1749
|
+
console.log();
|
|
1750
|
+
}
|
|
1751
|
+
if (result.deindexed.length > 0) {
|
|
1752
|
+
console.log(` DEINDEXED (${result.deindexed.length}):`);
|
|
1753
|
+
for (const page of result.deindexed) {
|
|
1754
|
+
console.log(` ${page.url} (${page.previousState} -> ${page.currentState})`);
|
|
1755
|
+
}
|
|
1756
|
+
console.log();
|
|
1757
|
+
}
|
|
1758
|
+
if (result.lastInspectedAt) {
|
|
1759
|
+
console.log(` Last inspected: ${result.lastInspectedAt}`);
|
|
1760
|
+
}
|
|
1761
|
+
}
|
|
1762
|
+
async function googleInspectSitemap(project, opts) {
|
|
1763
|
+
const client = getClient11();
|
|
1764
|
+
const run = await client.gscInspectSitemap(project, {
|
|
1765
|
+
sitemapUrl: opts.sitemapUrl
|
|
1766
|
+
});
|
|
1767
|
+
if (opts.format === "json") {
|
|
1768
|
+
console.log(JSON.stringify(run, null, 2));
|
|
1769
|
+
return;
|
|
1770
|
+
}
|
|
1771
|
+
console.log(`Sitemap inspection started (run ${run.id})`);
|
|
1772
|
+
if (opts.wait) {
|
|
1773
|
+
const timeout = 30 * 60 * 1e3;
|
|
1774
|
+
const start = Date.now();
|
|
1775
|
+
process.stderr.write("Waiting for sitemap inspection to complete");
|
|
1776
|
+
while (Date.now() - start < timeout) {
|
|
1777
|
+
await new Promise((r) => setTimeout(r, 3e3));
|
|
1778
|
+
const current = await client.getRun(run.id);
|
|
1779
|
+
process.stderr.write(".");
|
|
1780
|
+
if (current.status === "completed" || current.status === "partial" || current.status === "failed") {
|
|
1781
|
+
process.stderr.write("\n");
|
|
1782
|
+
if (current.status === "completed") {
|
|
1783
|
+
console.log("Sitemap inspection completed successfully.");
|
|
1784
|
+
} else if (current.status === "partial") {
|
|
1785
|
+
console.log("Sitemap inspection completed with some errors.");
|
|
1786
|
+
} else {
|
|
1787
|
+
console.error("Sitemap inspection failed.");
|
|
1788
|
+
}
|
|
1789
|
+
return;
|
|
1790
|
+
}
|
|
1791
|
+
}
|
|
1792
|
+
process.stderr.write("\n");
|
|
1793
|
+
console.error("Timed out waiting for sitemap inspection to complete.");
|
|
1794
|
+
process.exit(1);
|
|
1795
|
+
}
|
|
1796
|
+
}
|
|
1797
|
+
async function googleCoverageHistory(project, opts) {
|
|
1798
|
+
const client = getClient11();
|
|
1799
|
+
const rows = await client.gscCoverageHistory(project, { limit: opts.limit });
|
|
1800
|
+
if (opts.format === "json") {
|
|
1801
|
+
console.log(JSON.stringify(rows, null, 2));
|
|
1802
|
+
return;
|
|
1803
|
+
}
|
|
1804
|
+
if (rows.length === 0) {
|
|
1805
|
+
console.log("No coverage history found. Run a GSC sync or sitemap inspection first.");
|
|
1806
|
+
return;
|
|
1807
|
+
}
|
|
1808
|
+
console.log(`
|
|
1809
|
+
GSC Coverage History for "${project}" (${rows.length} snapshots):
|
|
1810
|
+
`);
|
|
1811
|
+
console.log(` ${"DATE".padEnd(12)}${"INDEXED".padEnd(10)}${"NOT INDEXED".padEnd(14)}TOP REASON`);
|
|
1812
|
+
console.log(` ${"\u2500".repeat(12)}${"\u2500".repeat(10)}${"\u2500".repeat(14)}${"\u2500".repeat(30)}`);
|
|
1813
|
+
for (const row of rows) {
|
|
1814
|
+
const topReason = Object.entries(row.reasonBreakdown).sort((a, b) => b[1] - a[1])[0];
|
|
1815
|
+
const reasonStr = topReason ? `${topReason[0]} (${topReason[1]})` : "-";
|
|
1816
|
+
console.log(` ${row.date.padEnd(12)}${String(row.indexed).padEnd(10)}${String(row.notIndexed).padEnd(14)}${reasonStr}`);
|
|
1817
|
+
}
|
|
1818
|
+
}
|
|
1584
1819
|
async function googleDeindexed(project, format) {
|
|
1585
1820
|
const client = getClient11();
|
|
1586
1821
|
const rows = await client.gscDeindexed(project);
|
|
@@ -1618,7 +1853,12 @@ Usage:
|
|
|
1618
1853
|
canonry project list List all projects
|
|
1619
1854
|
canonry project show <name> Show project details
|
|
1620
1855
|
canonry project delete <name> Delete a project
|
|
1856
|
+
canonry project add-location <name> Add a location (--label, --city, --region, --country)
|
|
1857
|
+
canonry project locations <name> List locations for a project
|
|
1858
|
+
canonry project remove-location <name> <label> Remove a location
|
|
1859
|
+
canonry project set-default-location <name> <label> Set default location
|
|
1621
1860
|
canonry keyword add <project> <kw> Add key phrases to a project
|
|
1861
|
+
canonry keyword remove <project> <kw> Remove key phrases from a project
|
|
1622
1862
|
canonry keyword list <project> List key phrases for a project
|
|
1623
1863
|
canonry keyword import <project> <file> Import key phrases from file
|
|
1624
1864
|
canonry keyword generate <project> Auto-generate key phrases (--provider, --count, --save)
|
|
@@ -1626,6 +1866,9 @@ Usage:
|
|
|
1626
1866
|
canonry competitor list <project> List competitors
|
|
1627
1867
|
canonry run <project> Trigger a run (all providers)
|
|
1628
1868
|
canonry run <project> --provider <name> Trigger a run for a specific provider
|
|
1869
|
+
canonry run <project> --location <label> Run with a specific location
|
|
1870
|
+
canonry run <project> --all-locations Run for every configured location (N\xD7 API calls)
|
|
1871
|
+
canonry run <project> --no-location Explicitly skip location context
|
|
1629
1872
|
canonry run <project> --wait Trigger and wait for completion
|
|
1630
1873
|
canonry run --all Trigger runs for all projects
|
|
1631
1874
|
canonry run show <id> Show run details and snapshots
|
|
@@ -1653,6 +1896,8 @@ Usage:
|
|
|
1653
1896
|
canonry google sync <project> Sync GSC data (--days 30, --full, --wait)
|
|
1654
1897
|
canonry google performance <project> Show GSC search performance data
|
|
1655
1898
|
canonry google inspect <project> <url> Inspect a URL via GSC
|
|
1899
|
+
canonry google inspect-sitemap <project> Bulk inspect all URLs from sitemap (--sitemap-url, --wait)
|
|
1900
|
+
canonry google coverage <project> Show index coverage summary
|
|
1656
1901
|
canonry google inspections <project> Show URL inspection history (--url <url>)
|
|
1657
1902
|
canonry google deindexed <project> Show pages that lost indexing
|
|
1658
1903
|
canonry settings Show active provider and quota settings
|
|
@@ -1684,6 +1929,9 @@ Options:
|
|
|
1684
1929
|
--language <lang> Language code (default: en)
|
|
1685
1930
|
--provider <name> Provider to use (gemini, openai, claude, local)
|
|
1686
1931
|
--format <fmt> Output format: text (default) or json
|
|
1932
|
+
--location <label> Run with a specific configured location
|
|
1933
|
+
--all-locations Run for every configured location
|
|
1934
|
+
--no-location Explicitly skip location context
|
|
1687
1935
|
--wait Wait for run to complete before returning
|
|
1688
1936
|
--all Run all projects (with 'run' command)
|
|
1689
1937
|
--include-results Include results in export
|
|
@@ -1877,9 +2125,68 @@ async function main() {
|
|
|
1877
2125
|
await deleteProject(name);
|
|
1878
2126
|
break;
|
|
1879
2127
|
}
|
|
2128
|
+
case "add-location": {
|
|
2129
|
+
const name = args[2];
|
|
2130
|
+
if (!name) {
|
|
2131
|
+
console.error("Error: project name is required");
|
|
2132
|
+
process.exit(1);
|
|
2133
|
+
}
|
|
2134
|
+
const { values: locValues } = parseArgs({
|
|
2135
|
+
args: args.slice(3),
|
|
2136
|
+
options: {
|
|
2137
|
+
label: { type: "string" },
|
|
2138
|
+
city: { type: "string" },
|
|
2139
|
+
region: { type: "string" },
|
|
2140
|
+
country: { type: "string" },
|
|
2141
|
+
timezone: { type: "string" }
|
|
2142
|
+
},
|
|
2143
|
+
allowPositionals: false
|
|
2144
|
+
});
|
|
2145
|
+
if (!locValues.label || !locValues.city || !locValues.region || !locValues.country) {
|
|
2146
|
+
console.error("Error: --label, --city, --region, and --country are all required");
|
|
2147
|
+
process.exit(1);
|
|
2148
|
+
}
|
|
2149
|
+
await addLocation(name, {
|
|
2150
|
+
label: locValues.label,
|
|
2151
|
+
city: locValues.city,
|
|
2152
|
+
region: locValues.region,
|
|
2153
|
+
country: locValues.country,
|
|
2154
|
+
timezone: locValues.timezone
|
|
2155
|
+
});
|
|
2156
|
+
break;
|
|
2157
|
+
}
|
|
2158
|
+
case "locations": {
|
|
2159
|
+
const name = args[2];
|
|
2160
|
+
if (!name) {
|
|
2161
|
+
console.error("Error: project name is required");
|
|
2162
|
+
process.exit(1);
|
|
2163
|
+
}
|
|
2164
|
+
await listLocations(name, format);
|
|
2165
|
+
break;
|
|
2166
|
+
}
|
|
2167
|
+
case "remove-location": {
|
|
2168
|
+
const name = args[2];
|
|
2169
|
+
const label = args[3];
|
|
2170
|
+
if (!name || !label) {
|
|
2171
|
+
console.error("Error: project name and location label are required");
|
|
2172
|
+
process.exit(1);
|
|
2173
|
+
}
|
|
2174
|
+
await removeLocation(name, label);
|
|
2175
|
+
break;
|
|
2176
|
+
}
|
|
2177
|
+
case "set-default-location": {
|
|
2178
|
+
const name = args[2];
|
|
2179
|
+
const label = args[3];
|
|
2180
|
+
if (!name || !label) {
|
|
2181
|
+
console.error("Error: project name and location label are required");
|
|
2182
|
+
process.exit(1);
|
|
2183
|
+
}
|
|
2184
|
+
await setDefaultLocation(name, label);
|
|
2185
|
+
break;
|
|
2186
|
+
}
|
|
1880
2187
|
default:
|
|
1881
2188
|
console.error(`Unknown project subcommand: ${subcommand ?? "(none)"}`);
|
|
1882
|
-
console.log("Available: create, update, list, show, delete");
|
|
2189
|
+
console.log("Available: create, update, list, show, delete, add-location, locations, remove-location, set-default-location");
|
|
1883
2190
|
process.exit(1);
|
|
1884
2191
|
}
|
|
1885
2192
|
break;
|
|
@@ -1897,6 +2204,17 @@ async function main() {
|
|
|
1897
2204
|
await addKeywords(project, kws);
|
|
1898
2205
|
break;
|
|
1899
2206
|
}
|
|
2207
|
+
case "remove":
|
|
2208
|
+
case "delete": {
|
|
2209
|
+
const project = args[2];
|
|
2210
|
+
const kws = args.slice(3).filter((a, i, arr) => !a.startsWith("--") && !(i > 0 && arr[i - 1].startsWith("--")));
|
|
2211
|
+
if (!project || kws.length === 0) {
|
|
2212
|
+
console.error("Error: project name and at least one key phrase required");
|
|
2213
|
+
process.exit(1);
|
|
2214
|
+
}
|
|
2215
|
+
await removeKeywords(project, kws);
|
|
2216
|
+
break;
|
|
2217
|
+
}
|
|
1900
2218
|
case "list": {
|
|
1901
2219
|
const project = args[2];
|
|
1902
2220
|
if (!project) {
|
|
@@ -1944,7 +2262,7 @@ async function main() {
|
|
|
1944
2262
|
}
|
|
1945
2263
|
default:
|
|
1946
2264
|
console.error(`Unknown keyword subcommand: ${subcommand ?? "(none)"}`);
|
|
1947
|
-
console.log("Available: add, list, import, generate");
|
|
2265
|
+
console.log("Available: add, remove, list, import, generate");
|
|
1948
2266
|
process.exit(1);
|
|
1949
2267
|
}
|
|
1950
2268
|
break;
|
|
@@ -1994,6 +2312,9 @@ async function main() {
|
|
|
1994
2312
|
provider: { type: "string" },
|
|
1995
2313
|
wait: { type: "boolean", default: false },
|
|
1996
2314
|
all: { type: "boolean", default: false },
|
|
2315
|
+
location: { type: "string" },
|
|
2316
|
+
"all-locations": { type: "boolean", default: false },
|
|
2317
|
+
"no-location": { type: "boolean", default: false },
|
|
1997
2318
|
format: { type: "string" }
|
|
1998
2319
|
},
|
|
1999
2320
|
allowPositionals: true
|
|
@@ -2018,6 +2339,9 @@ async function main() {
|
|
|
2018
2339
|
await triggerRun(project, {
|
|
2019
2340
|
provider: runParsed.values.provider,
|
|
2020
2341
|
wait: runParsed.values.wait,
|
|
2342
|
+
location: runParsed.values.location,
|
|
2343
|
+
allLocations: runParsed.values["all-locations"],
|
|
2344
|
+
noLocation: runParsed.values["no-location"],
|
|
2021
2345
|
format: runFormat
|
|
2022
2346
|
});
|
|
2023
2347
|
}
|
|
@@ -2420,6 +2744,58 @@ async function main() {
|
|
|
2420
2744
|
});
|
|
2421
2745
|
break;
|
|
2422
2746
|
}
|
|
2747
|
+
case "inspect-sitemap": {
|
|
2748
|
+
const project = args[2];
|
|
2749
|
+
if (!project) {
|
|
2750
|
+
console.error("Error: project name is required");
|
|
2751
|
+
process.exit(1);
|
|
2752
|
+
}
|
|
2753
|
+
const { values: inspSitemapValues } = parseArgs({
|
|
2754
|
+
args: args.slice(3),
|
|
2755
|
+
options: {
|
|
2756
|
+
"sitemap-url": { type: "string" },
|
|
2757
|
+
wait: { type: "boolean", default: false },
|
|
2758
|
+
format: { type: "string" }
|
|
2759
|
+
},
|
|
2760
|
+
allowPositionals: false
|
|
2761
|
+
});
|
|
2762
|
+
await googleInspectSitemap(project, {
|
|
2763
|
+
sitemapUrl: inspSitemapValues["sitemap-url"],
|
|
2764
|
+
wait: inspSitemapValues.wait ?? false,
|
|
2765
|
+
format: inspSitemapValues.format === "json" ? "json" : format
|
|
2766
|
+
});
|
|
2767
|
+
break;
|
|
2768
|
+
}
|
|
2769
|
+
case "coverage": {
|
|
2770
|
+
const project = args[2];
|
|
2771
|
+
if (!project) {
|
|
2772
|
+
console.error("Error: project name is required");
|
|
2773
|
+
process.exit(1);
|
|
2774
|
+
}
|
|
2775
|
+
await googleCoverage(project, format);
|
|
2776
|
+
break;
|
|
2777
|
+
}
|
|
2778
|
+
case "coverage-history": {
|
|
2779
|
+
const project = args[2];
|
|
2780
|
+
if (!project) {
|
|
2781
|
+
console.error("Error: project name is required");
|
|
2782
|
+
process.exit(1);
|
|
2783
|
+
}
|
|
2784
|
+
const { values: histValues } = parseArgs({
|
|
2785
|
+
args: args.slice(3),
|
|
2786
|
+
options: {
|
|
2787
|
+
limit: { type: "string" },
|
|
2788
|
+
format: { type: "string" }
|
|
2789
|
+
},
|
|
2790
|
+
allowPositionals: false
|
|
2791
|
+
});
|
|
2792
|
+
const limitNum = histValues.limit ? parseInt(histValues.limit, 10) : void 0;
|
|
2793
|
+
await googleCoverageHistory(project, {
|
|
2794
|
+
limit: limitNum != null && !Number.isNaN(limitNum) ? limitNum : void 0,
|
|
2795
|
+
format: histValues.format === "json" ? "json" : format
|
|
2796
|
+
});
|
|
2797
|
+
break;
|
|
2798
|
+
}
|
|
2423
2799
|
case "deindexed": {
|
|
2424
2800
|
const project = args[2];
|
|
2425
2801
|
if (!project) {
|
|
@@ -2431,7 +2807,7 @@ async function main() {
|
|
|
2431
2807
|
}
|
|
2432
2808
|
default:
|
|
2433
2809
|
console.error(`Unknown google subcommand: ${subcommand ?? "(none)"}`);
|
|
2434
|
-
console.log("Available: connect, disconnect, status, properties, set-property, sync, performance, inspect, inspections, deindexed");
|
|
2810
|
+
console.log("Available: connect, disconnect, status, properties, set-property, sync, performance, inspect, inspect-sitemap, coverage, coverage-history, inspections, deindexed");
|
|
2435
2811
|
process.exit(1);
|
|
2436
2812
|
}
|
|
2437
2813
|
break;
|
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.13.3",
|
|
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",
|
|
@@ -53,12 +53,12 @@
|
|
|
53
53
|
"tsx": "^4.19.0",
|
|
54
54
|
"@ainyc/canonry-api-routes": "0.0.0",
|
|
55
55
|
"@ainyc/canonry-config": "0.0.0",
|
|
56
|
-
"@ainyc/canonry-contracts": "0.0.0",
|
|
57
56
|
"@ainyc/canonry-db": "0.0.0",
|
|
58
|
-
"@ainyc/canonry-provider-gemini": "0.0.0",
|
|
59
57
|
"@ainyc/canonry-provider-claude": "0.0.0",
|
|
60
58
|
"@ainyc/canonry-provider-local": "0.0.0",
|
|
59
|
+
"@ainyc/canonry-provider-gemini": "0.0.0",
|
|
61
60
|
"@ainyc/canonry-provider-openai": "0.0.0",
|
|
61
|
+
"@ainyc/canonry-contracts": "0.0.0",
|
|
62
62
|
"@ainyc/canonry-integration-google": "0.0.0"
|
|
63
63
|
},
|
|
64
64
|
"scripts": {
|