@ainyc/canonry 5.3.1 → 5.4.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/README.md +14 -15
- package/assets/assets/{AuditHistoryPanel-D5cOFMKE.js → AuditHistoryPanel-DNSskBJN.js} +1 -1
- package/assets/assets/{BacklinksPage-BiOj8ztV.js → BacklinksPage-COtLVzT8.js} +1 -1
- package/assets/assets/{HistoryPage-DDBCwooU.js → HistoryPage-D9e6cGrq.js} +1 -1
- package/assets/assets/{MeasurementPropertyPage-CMoU2yA_.js → MeasurementPropertyPage-BSs4ba4N.js} +1 -1
- package/assets/assets/ProjectPage-BbpGgwgd.js +8 -0
- package/assets/assets/{RunRow-BLBAwIot.js → RunRow-DRjXGgeI.js} +1 -1
- package/assets/assets/{RunsPage-BVgBbE1M.js → RunsPage-BXyqLNMQ.js} +1 -1
- package/assets/assets/{SettingsPage-DYtN-1_-.js → SettingsPage-DKmzGwx3.js} +1 -1
- package/assets/assets/SiteHealthSection-DuSY6jzY.js +4 -0
- package/assets/assets/{TrafficPage-D6QT_2hU.js → TrafficPage-Bc9NGm4L.js} +1 -1
- package/assets/assets/{TrafficSourceDetailPage-BnLzF82w.js → TrafficSourceDetailPage-Bw8PCVl9.js} +1 -1
- package/assets/assets/{extract-error-message-DIzjGZxl.js → extract-error-message-rTGTNN_D.js} +1 -1
- package/assets/assets/index-CVK43vax.js +86 -0
- package/assets/assets/index-Hmnj0RO5.css +1 -0
- package/assets/assets/{react-sigma_core.esm.min-DTbIcdn4.js → react-sigma_core.esm.min-Xwhtf0bv.js} +1 -1
- package/assets/assets/{v2-overview-adapter-B_N4ilQV.js → v2-overview-adapter-BgGH6oLq.js} +1 -1
- package/assets/assets/vendor-lucide-CBIL4Nkq.js +1 -0
- package/assets/index.html +3 -3
- package/dist/{chunk-IACO5R7A.js → chunk-2P52FD5B.js} +15 -9
- package/dist/{chunk-IOP36L3C.js → chunk-67OM5KEH.js} +21 -6
- package/dist/{chunk-C7PITYL3.js → chunk-L3FG66O7.js} +2 -2
- package/dist/{chunk-3COTRCK3.js → chunk-P5YYRGFS.js} +2 -2
- package/dist/{chunk-TF6HFT3Q.js → chunk-SLOTTXIL.js} +15 -6
- package/dist/{chunk-2U5IW3G5.js → chunk-Z6RA7LWY.js} +44 -2
- package/dist/cli.js +132 -65
- package/dist/{demo-server-TXW3UX3P.js → demo-server-6QU77ZMV.js} +3 -3
- package/dist/index.js +5 -5
- package/dist/{intelligence-service-H34EOB6K.js → intelligence-service-PHCK6A35.js} +2 -2
- package/dist/mcp.js +3 -3
- package/package.json +11 -11
- package/assets/assets/ProjectPage-CrFybBls.js +0 -8
- package/assets/assets/SiteHealthSection-ElUwcAS4.js +0 -4
- package/assets/assets/index-CoQVOsWw.js +0 -86
- package/assets/assets/index-DCLmKL1s.css +0 -1
- package/assets/assets/vendor-lucide-nVpYViBH.js +0 -1
package/dist/cli.js
CHANGED
|
@@ -19,12 +19,14 @@ import {
|
|
|
19
19
|
formatUpdateNotice,
|
|
20
20
|
getCloudflareTrafficConnectionBySourceId,
|
|
21
21
|
getOrCreateAnonymousId,
|
|
22
|
+
getPrintedUpdateAvailable,
|
|
22
23
|
getTelemetryStatus,
|
|
23
24
|
isAeroToolProfile,
|
|
24
25
|
isFirstRun,
|
|
25
26
|
isLoopbackBindHost,
|
|
26
27
|
isTelemetryEnabled,
|
|
27
28
|
listAgentProviders,
|
|
29
|
+
notePrintedUpdateAvailable,
|
|
28
30
|
readCachedUpdateAvailable,
|
|
29
31
|
setGoogleAuthConfig,
|
|
30
32
|
setTelemetryPreference,
|
|
@@ -33,11 +35,11 @@ import {
|
|
|
33
35
|
trackCliCommandFinished,
|
|
34
36
|
trackEvent,
|
|
35
37
|
waitForServerRuntimeStartup
|
|
36
|
-
} from "./chunk-
|
|
38
|
+
} from "./chunk-SLOTTXIL.js";
|
|
37
39
|
import {
|
|
38
40
|
autoSyncSkills,
|
|
39
41
|
formatAutoSyncNotice
|
|
40
|
-
} from "./chunk-
|
|
42
|
+
} from "./chunk-L3FG66O7.js";
|
|
41
43
|
import {
|
|
42
44
|
CliError,
|
|
43
45
|
EXIT_SYSTEM_ERROR,
|
|
@@ -61,15 +63,16 @@ import {
|
|
|
61
63
|
runMeasurementDraftAction,
|
|
62
64
|
saveConfig,
|
|
63
65
|
saveConfigPatch,
|
|
66
|
+
shouldPrintServeSkillsNudge,
|
|
64
67
|
systemError,
|
|
65
68
|
usageError
|
|
66
|
-
} from "./chunk-
|
|
69
|
+
} from "./chunk-67OM5KEH.js";
|
|
67
70
|
import {
|
|
68
71
|
DEFAULT_DEMO_TRUSTED_PROXIES,
|
|
69
72
|
trustedProxiesProblem,
|
|
70
73
|
trustedProxyProblem
|
|
71
74
|
} from "./chunk-RB2F4D3Z.js";
|
|
72
|
-
import "./chunk-
|
|
75
|
+
import "./chunk-P5YYRGFS.js";
|
|
73
76
|
import "./chunk-AOJU5LKX.js";
|
|
74
77
|
import {
|
|
75
78
|
CLOUDFLARE_WORKER_BINDINGS,
|
|
@@ -83,8 +86,9 @@ import {
|
|
|
83
86
|
migrate,
|
|
84
87
|
projects,
|
|
85
88
|
queries,
|
|
86
|
-
renderReportHtml
|
|
87
|
-
|
|
89
|
+
renderReportHtml,
|
|
90
|
+
runs
|
|
91
|
+
} from "./chunk-2P52FD5B.js";
|
|
88
92
|
import {
|
|
89
93
|
AdsDeliverySnapshotStatuses,
|
|
90
94
|
AdsHistoricalCampaignRollupStatuses,
|
|
@@ -101,7 +105,9 @@ import {
|
|
|
101
105
|
READ_ONLY_SCOPE,
|
|
102
106
|
REPORT_PERIOD_OPTIONS,
|
|
103
107
|
ResearchRunStatuses,
|
|
108
|
+
RunKinds,
|
|
104
109
|
RunStatuses,
|
|
110
|
+
RunTriggers,
|
|
105
111
|
TrafficEventKinds,
|
|
106
112
|
TrafficSeriesGranularities,
|
|
107
113
|
USER_PASSWORD_MIN_LENGTH,
|
|
@@ -163,7 +169,7 @@ import {
|
|
|
163
169
|
snapshotProviderModeSchema,
|
|
164
170
|
visibilityReportRequestSchema,
|
|
165
171
|
winnabilityClassSchema
|
|
166
|
-
} from "./chunk-
|
|
172
|
+
} from "./chunk-Z6RA7LWY.js";
|
|
167
173
|
|
|
168
174
|
// src/cli.ts
|
|
169
175
|
import { pathToFileURL } from "url";
|
|
@@ -428,7 +434,7 @@ function parseDemoTrustedProxies(values) {
|
|
|
428
434
|
async function demoCommand(options) {
|
|
429
435
|
const { host, port } = parseDemoListenOptions(options);
|
|
430
436
|
const trustProxy = parseDemoTrustedProxies(options.trustProxy);
|
|
431
|
-
const { createDemoServer } = await import("./demo-server-
|
|
437
|
+
const { createDemoServer } = await import("./demo-server-6QU77ZMV.js");
|
|
432
438
|
const app = await createDemoServer({ trustProxy });
|
|
433
439
|
let stopping = false;
|
|
434
440
|
const stop = () => {
|
|
@@ -1818,18 +1824,18 @@ function errorMessage(err) {
|
|
|
1818
1824
|
async function discoverRun(project, opts) {
|
|
1819
1825
|
const client = getClient4();
|
|
1820
1826
|
const { angles, multiAngle } = resolveIcpAngles(opts);
|
|
1821
|
-
const
|
|
1827
|
+
const runs2 = [];
|
|
1822
1828
|
for (const angle of angles) {
|
|
1823
1829
|
try {
|
|
1824
1830
|
const start = await client.triggerDiscoveryRun(project, buildRunBody(opts, angle));
|
|
1825
|
-
|
|
1831
|
+
runs2.push({ angle, start });
|
|
1826
1832
|
} catch (err) {
|
|
1827
|
-
if (
|
|
1833
|
+
if (runs2.length > 0) {
|
|
1828
1834
|
process.stderr.write(
|
|
1829
1835
|
`
|
|
1830
1836
|
Failed to start ${angle ? `angle "${angle}"` : "discovery run"}: ${errorMessage(err)}
|
|
1831
1837
|
Sessions already started (recover with \`canonry discover show ${project} <id>\`):
|
|
1832
|
-
` +
|
|
1838
|
+
` + runs2.map((r) => ` ${r.start.sessionId}`).join("\n") + "\n"
|
|
1833
1839
|
);
|
|
1834
1840
|
}
|
|
1835
1841
|
throw err;
|
|
@@ -1837,10 +1843,10 @@ Sessions already started (recover with \`canonry discover show ${project} <id>\`
|
|
|
1837
1843
|
}
|
|
1838
1844
|
if (!opts.wait) {
|
|
1839
1845
|
if (isMachineFormat(opts.format)) {
|
|
1840
|
-
console.log(JSON.stringify(multiAngle ?
|
|
1846
|
+
console.log(JSON.stringify(multiAngle ? runs2.map((r) => r.start) : runs2[0].start, null, 2));
|
|
1841
1847
|
return;
|
|
1842
1848
|
}
|
|
1843
|
-
for (const { angle, start } of
|
|
1849
|
+
for (const { angle, start } of runs2) {
|
|
1844
1850
|
if (angle) console.log(`[${angle}]`);
|
|
1845
1851
|
if (start.consolidated) {
|
|
1846
1852
|
console.log(`Reusing in-flight discovery session: ${start.sessionId}`);
|
|
@@ -1853,20 +1859,20 @@ Sessions already started (recover with \`canonry discover show ${project} <id>\`
|
|
|
1853
1859
|
console.log(` Status: ${start.status}`);
|
|
1854
1860
|
console.log(` Tail: canonry discover show ${project} ${start.sessionId}`);
|
|
1855
1861
|
}
|
|
1856
|
-
if (
|
|
1862
|
+
if (runs2.length > 1) console.log();
|
|
1857
1863
|
}
|
|
1858
1864
|
return;
|
|
1859
1865
|
}
|
|
1860
|
-
const parallel =
|
|
1861
|
-
if (parallel) process.stderr.write(`Waiting for ${
|
|
1866
|
+
const parallel = runs2.length > 1;
|
|
1867
|
+
if (parallel) process.stderr.write(`Waiting for ${runs2.length} discovery sessions...
|
|
1862
1868
|
`);
|
|
1863
1869
|
const settled = await Promise.allSettled(
|
|
1864
|
-
|
|
1870
|
+
runs2.map((r) => pollSession(client, project, r.start.sessionId, parallel))
|
|
1865
1871
|
);
|
|
1866
1872
|
const results = [];
|
|
1867
1873
|
const failures = [];
|
|
1868
1874
|
settled.forEach((outcome, i) => {
|
|
1869
|
-
const run =
|
|
1875
|
+
const run = runs2[i];
|
|
1870
1876
|
if (outcome.status === "fulfilled") {
|
|
1871
1877
|
results.push({ angle: run.angle, session: outcome.value });
|
|
1872
1878
|
} else {
|
|
@@ -1906,7 +1912,7 @@ Sessions already started (recover with \`canonry discover show ${project} <id>\`
|
|
|
1906
1912
|
}
|
|
1907
1913
|
throw new CliError({
|
|
1908
1914
|
code: "DISCOVERY_INCOMPLETE",
|
|
1909
|
-
message: `${failures.length} of ${
|
|
1915
|
+
message: `${failures.length} of ${runs2.length} discovery session(s) did not complete`,
|
|
1910
1916
|
details: { failed: failures.map((f) => f.sessionId) }
|
|
1911
1917
|
});
|
|
1912
1918
|
}
|
|
@@ -2750,14 +2756,14 @@ async function researchBatch(project, source, opts) {
|
|
|
2750
2756
|
}
|
|
2751
2757
|
const client = getClient5();
|
|
2752
2758
|
const started = await client.startResearchBatch(project, parsed.data);
|
|
2753
|
-
const
|
|
2759
|
+
const runs2 = opts.wait ? await Promise.all(started.runs.map((run) => TERMINAL_RESEARCH_STATUSES.has(run.status) ? Promise.resolve(run) : pollResearchRun(client, project, run.id, true))) : started.runs;
|
|
2754
2760
|
if (opts.format === "jsonl") {
|
|
2755
|
-
emitJsonl(
|
|
2761
|
+
emitJsonl(runs2.map((run) => ({ project, ...run })));
|
|
2756
2762
|
} else if (opts.format === "json") {
|
|
2757
|
-
console.log(JSON.stringify({ runs }, null, 2));
|
|
2763
|
+
console.log(JSON.stringify({ runs: runs2 }, null, 2));
|
|
2758
2764
|
} else {
|
|
2759
|
-
console.log(`Research saved for ${
|
|
2760
|
-
for (const run of
|
|
2765
|
+
console.log(`Research saved for ${runs2.length} destinations (${runs2.reduce((count, run) => count + run.totalQueries, 0)} queries).`);
|
|
2766
|
+
for (const run of runs2) {
|
|
2761
2767
|
if (opts.wait) printDetail(project, run);
|
|
2762
2768
|
else printStarted(project, run);
|
|
2763
2769
|
}
|
|
@@ -2766,24 +2772,24 @@ async function researchBatch(project, source, opts) {
|
|
|
2766
2772
|
async function researchList(project, opts) {
|
|
2767
2773
|
const client = getClient5();
|
|
2768
2774
|
const result = await client.listResearchRuns(project, opts.limit === void 0 && opts.cursor === void 0 ? void 0 : { limit: opts.limit, cursor: opts.cursor });
|
|
2769
|
-
const { runs } = result;
|
|
2775
|
+
const { runs: runs2 } = result;
|
|
2770
2776
|
if (opts.format === "json") {
|
|
2771
2777
|
console.log(JSON.stringify(result, null, 2));
|
|
2772
2778
|
return;
|
|
2773
2779
|
}
|
|
2774
2780
|
if (opts.format === "jsonl") {
|
|
2775
|
-
emitJsonl(
|
|
2781
|
+
emitJsonl(runs2.map((run) => ({ project, ...run })));
|
|
2776
2782
|
return;
|
|
2777
2783
|
}
|
|
2778
|
-
if (
|
|
2784
|
+
if (runs2.length === 0) {
|
|
2779
2785
|
console.log(`No saved research runs for "${project}".`);
|
|
2780
2786
|
return;
|
|
2781
2787
|
}
|
|
2782
|
-
console.log(`Research history for "${project}" (${
|
|
2788
|
+
console.log(`Research history for "${project}" (${runs2.length}):
|
|
2783
2789
|
`);
|
|
2784
2790
|
console.log(" ID STATUS QUERIES PROVIDER / MODEL SCOPE CREATED");
|
|
2785
2791
|
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\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");
|
|
2786
|
-
for (const run of
|
|
2792
|
+
for (const run of runs2) {
|
|
2787
2793
|
const model = run.resolvedModel ? `${run.provider} / ${run.resolvedModel}` : run.provider;
|
|
2788
2794
|
console.log(` ${run.id.padEnd(36)} ${run.status.padEnd(10)} ${String(run.totalQueries).padStart(7)} ${model.slice(0, 32).padEnd(32)} ${formatScope(run.scope).slice(0, 24).padEnd(24)} ${run.createdAt}`);
|
|
2789
2795
|
}
|
|
@@ -11535,9 +11541,9 @@ async function loadLatestRunForExport(client, project) {
|
|
|
11535
11541
|
} catch (err) {
|
|
11536
11542
|
if (!isEndpointMissing(err)) throw err;
|
|
11537
11543
|
}
|
|
11538
|
-
const
|
|
11539
|
-
if (
|
|
11540
|
-
const latestRun =
|
|
11544
|
+
const runs2 = await client.listRuns(project);
|
|
11545
|
+
if (runs2.length === 0) return null;
|
|
11546
|
+
const latestRun = runs2.reduce(
|
|
11541
11547
|
(current, candidate) => candidate.createdAt > current.createdAt ? candidate : current
|
|
11542
11548
|
);
|
|
11543
11549
|
return client.getRun(latestRun.id);
|
|
@@ -11633,14 +11639,14 @@ async function showStatus(project, format) {
|
|
|
11633
11639
|
const projectData = await client.getProject(project);
|
|
11634
11640
|
const latest = await getLatestRunSummary(client, project);
|
|
11635
11641
|
if (isMachineFormat(format)) {
|
|
11636
|
-
let
|
|
11642
|
+
let runs2 = [];
|
|
11637
11643
|
try {
|
|
11638
|
-
|
|
11644
|
+
runs2 = await client.listRuns(project);
|
|
11639
11645
|
} catch {
|
|
11640
11646
|
}
|
|
11641
11647
|
console.log(JSON.stringify({
|
|
11642
11648
|
project: projectData,
|
|
11643
|
-
runs,
|
|
11649
|
+
runs: runs2,
|
|
11644
11650
|
latestRun: latest.run,
|
|
11645
11651
|
totalRuns: latest.totalRuns
|
|
11646
11652
|
}, null, 2));
|
|
@@ -11663,7 +11669,9 @@ async function showStatus(project, format) {
|
|
|
11663
11669
|
console.log(`
|
|
11664
11670
|
Total runs: ${latest.totalRuns}`);
|
|
11665
11671
|
} else {
|
|
11666
|
-
|
|
11672
|
+
const projectArg = /^[\w.-]+$/.test(project) ? project : `'${project.replaceAll("'", `'\\''`)}'`;
|
|
11673
|
+
console.log(`
|
|
11674
|
+
No runs yet. Capture Page Health with "canonry technical-aeo run ${projectArg}", or run an AI Visibility sweep after adding a provider.`);
|
|
11667
11675
|
}
|
|
11668
11676
|
}
|
|
11669
11677
|
async function getLatestRunSummary(client, project) {
|
|
@@ -11671,15 +11679,15 @@ async function getLatestRunSummary(client, project) {
|
|
|
11671
11679
|
return await client.getLatestRun(project);
|
|
11672
11680
|
} catch (err) {
|
|
11673
11681
|
if (!isEndpointMissing(err)) throw err;
|
|
11674
|
-
const
|
|
11675
|
-
if (
|
|
11682
|
+
const runs2 = await client.listRuns(project);
|
|
11683
|
+
if (runs2.length === 0) {
|
|
11676
11684
|
return { totalRuns: 0, run: null };
|
|
11677
11685
|
}
|
|
11678
|
-
const latestRun =
|
|
11686
|
+
const latestRun = runs2.reduce(
|
|
11679
11687
|
(current, candidate) => candidate.createdAt > current.createdAt ? candidate : current
|
|
11680
11688
|
);
|
|
11681
11689
|
return {
|
|
11682
|
-
totalRuns:
|
|
11690
|
+
totalRuns: runs2.length,
|
|
11683
11691
|
run: latestRun
|
|
11684
11692
|
};
|
|
11685
11693
|
}
|
|
@@ -12110,6 +12118,7 @@ var PROJECT_CLI_COMMANDS = [
|
|
|
12110
12118
|
{
|
|
12111
12119
|
path: ["project", "create"],
|
|
12112
12120
|
usage: "canonry project create <name> [--domain <domain>] [--owned-domain <domain>...] [--alias <name>...] [--country <code>] [--language <lang>] [--display-name <name>] [--provider <name>...] [--provider-model provider=model...] [--format json]",
|
|
12121
|
+
help: "Create a project. Pass --domain for the public site to scan. Provider credentials are not required for Page Health.",
|
|
12113
12122
|
options: {
|
|
12114
12123
|
domain: { type: "string", short: "d" },
|
|
12115
12124
|
"owned-domain": multiStringOption(),
|
|
@@ -12643,8 +12652,8 @@ async function cancelRun(project, runId, format) {
|
|
|
12643
12652
|
const client = getClient23();
|
|
12644
12653
|
let targetId = runId;
|
|
12645
12654
|
if (!targetId) {
|
|
12646
|
-
const
|
|
12647
|
-
const activeRuns =
|
|
12655
|
+
const runs2 = await client.listRuns(project);
|
|
12656
|
+
const activeRuns = runs2.filter((r) => r.status === "queued" || r.status === "running");
|
|
12648
12657
|
if (activeRuns.length > 1) {
|
|
12649
12658
|
const candidates = activeRuns.map(({ id, kind, status }) => ({ id, kind, status }));
|
|
12650
12659
|
throw new CliError({
|
|
@@ -12698,23 +12707,23 @@ async function showRun(id, format) {
|
|
|
12698
12707
|
}
|
|
12699
12708
|
async function listRuns(project, opts) {
|
|
12700
12709
|
const client = getClient23();
|
|
12701
|
-
const
|
|
12710
|
+
const runs2 = await client.listRuns(project, opts?.limit, opts?.kind, opts?.status);
|
|
12702
12711
|
if (opts?.format === "json") {
|
|
12703
|
-
console.log(JSON.stringify(
|
|
12712
|
+
console.log(JSON.stringify(runs2, null, 2));
|
|
12704
12713
|
return;
|
|
12705
12714
|
} else if (opts?.format === "jsonl") {
|
|
12706
|
-
emitJsonl(
|
|
12715
|
+
emitJsonl(runs2.map((run) => ({ project, ...run })));
|
|
12707
12716
|
return;
|
|
12708
12717
|
}
|
|
12709
|
-
if (
|
|
12718
|
+
if (runs2.length === 0) {
|
|
12710
12719
|
console.log(`No runs found for "${project}".`);
|
|
12711
12720
|
return;
|
|
12712
12721
|
}
|
|
12713
|
-
console.log(`Runs for "${project}" (${
|
|
12722
|
+
console.log(`Runs for "${project}" (${runs2.length}):
|
|
12714
12723
|
`);
|
|
12715
12724
|
console.log(" ID STATUS KIND TRIGGER CREATED");
|
|
12716
12725
|
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\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");
|
|
12717
|
-
for (const run of
|
|
12726
|
+
for (const run of runs2) {
|
|
12718
12727
|
console.log(
|
|
12719
12728
|
` ${run.id} ${run.status.padEnd(10)} ${run.kind.padEnd(18)} ${run.trigger.padEnd(9)} ${run.createdAt}`
|
|
12720
12729
|
);
|
|
@@ -14907,7 +14916,7 @@ async function bootstrapCommand(opts) {
|
|
|
14907
14916
|
console.log("Providers: none (Page Health works now; add one later to enable AI Visibility).");
|
|
14908
14917
|
}
|
|
14909
14918
|
if (generatedApiKey) {
|
|
14910
|
-
console.log(`API key: ${generatedApiKey}`);
|
|
14919
|
+
console.log(`API key (for the CLI, MCP, and agents): ${generatedApiKey}`);
|
|
14911
14920
|
}
|
|
14912
14921
|
}
|
|
14913
14922
|
|
|
@@ -15232,7 +15241,7 @@ async function initCommand(opts) {
|
|
|
15232
15241
|
throw new CliError({
|
|
15233
15242
|
code: "INIT_JSON_REQUIRES_NON_INTERACTIVE",
|
|
15234
15243
|
message: "--format json requires non-interactive provider configuration via flags or environment variables.",
|
|
15235
|
-
displayMessage:
|
|
15244
|
+
displayMessage: '--format json requires provider flags or environment variables. For provider-free first-run setup, use "canonry bootstrap" instead.',
|
|
15236
15245
|
details: {
|
|
15237
15246
|
required: ["provider flags or environment variables"]
|
|
15238
15247
|
}
|
|
@@ -15306,7 +15315,7 @@ async function initCommand(opts) {
|
|
|
15306
15315
|
throw new CliError({
|
|
15307
15316
|
code: "INIT_PROVIDER_REQUIRED",
|
|
15308
15317
|
message: "At least one provider is required.",
|
|
15309
|
-
displayMessage:
|
|
15318
|
+
displayMessage: '\nAt least one provider is required. For provider-free first-run setup, use "canonry bootstrap" instead.',
|
|
15310
15319
|
details: {
|
|
15311
15320
|
required: ["provider"]
|
|
15312
15321
|
}
|
|
@@ -15501,6 +15510,9 @@ function encodeLegacySetupState(state) {
|
|
|
15501
15510
|
return flags.length > 0 ? flags.sort().join("|") : "none";
|
|
15502
15511
|
}
|
|
15503
15512
|
|
|
15513
|
+
// src/commands/serve.ts
|
|
15514
|
+
import { and, asc, eq as eq2, ne } from "drizzle-orm";
|
|
15515
|
+
|
|
15504
15516
|
// src/server-shutdown.ts
|
|
15505
15517
|
async function closeWithIdleSweep(app, intervalMs = 250) {
|
|
15506
15518
|
const sweep = setInterval(() => app.server.closeIdleConnections(), intervalMs);
|
|
@@ -15710,6 +15722,47 @@ function detectCanonryAgentPlugin(opts = {}) {
|
|
|
15710
15722
|
function shouldWarnAboutRemoteSetup(host) {
|
|
15711
15723
|
return !isLoopbackBindHost(host);
|
|
15712
15724
|
}
|
|
15725
|
+
function readServeOpenState(db) {
|
|
15726
|
+
try {
|
|
15727
|
+
const rows = db.select({
|
|
15728
|
+
id: projects.id,
|
|
15729
|
+
name: projects.name,
|
|
15730
|
+
createdAt: projects.createdAt
|
|
15731
|
+
}).from(projects).orderBy(asc(projects.createdAt), asc(projects.name)).all();
|
|
15732
|
+
if (rows.length === 0) return { projectCount: 0, hasSiteAudit: false };
|
|
15733
|
+
let scanned;
|
|
15734
|
+
try {
|
|
15735
|
+
const audits = db.select({
|
|
15736
|
+
projectId: runs.projectId,
|
|
15737
|
+
status: runs.status
|
|
15738
|
+
}).from(runs).where(and(
|
|
15739
|
+
eq2(runs.kind, RunKinds["site-audit"]),
|
|
15740
|
+
ne(runs.trigger, RunTriggers.probe)
|
|
15741
|
+
)).all();
|
|
15742
|
+
scanned = new Set(
|
|
15743
|
+
audits.filter((run) => run.status === RunStatuses.completed || run.status === RunStatuses.partial).map((run) => run.projectId)
|
|
15744
|
+
);
|
|
15745
|
+
} catch {
|
|
15746
|
+
return { projectCount: rows.length, firstProjectName: rows[0]?.name, hasSiteAudit: true };
|
|
15747
|
+
}
|
|
15748
|
+
const firstUnscanned = rows.find((row) => !scanned.has(row.id));
|
|
15749
|
+
if (firstUnscanned) {
|
|
15750
|
+
return { projectCount: rows.length, firstProjectName: firstUnscanned.name, hasSiteAudit: false };
|
|
15751
|
+
}
|
|
15752
|
+
return { projectCount: rows.length, firstProjectName: rows[0]?.name, hasSiteAudit: true };
|
|
15753
|
+
} catch {
|
|
15754
|
+
return { projectCount: 0, hasSiteAudit: false };
|
|
15755
|
+
}
|
|
15756
|
+
}
|
|
15757
|
+
function buildServeOpenLine(input) {
|
|
15758
|
+
if (input.projectCount === 0) {
|
|
15759
|
+
return `Open ${input.url}/setup to map your site and run your first Page Health scan.`;
|
|
15760
|
+
}
|
|
15761
|
+
if (!input.hasSiteAudit && input.firstProjectName) {
|
|
15762
|
+
return `Open ${input.url}/setup?onboarding=site-health&setupProject=${encodeURIComponent(input.firstProjectName)} to run your first Page Health scan.`;
|
|
15763
|
+
}
|
|
15764
|
+
return `Open ${input.url}`;
|
|
15765
|
+
}
|
|
15713
15766
|
async function serveCommand(format = "text") {
|
|
15714
15767
|
const config = loadConfig();
|
|
15715
15768
|
const port = resolveServePort(process.env.CANONRY_PORT, config.port);
|
|
@@ -15750,8 +15803,6 @@ async function serveCommand(format = "text") {
|
|
|
15750
15803
|
let listening = false;
|
|
15751
15804
|
try {
|
|
15752
15805
|
await app.listen({ host, port });
|
|
15753
|
-
await waitForServerRuntimeStartup(app);
|
|
15754
|
-
listening = true;
|
|
15755
15806
|
let shuttingDown = false;
|
|
15756
15807
|
const shutdown = (signal) => {
|
|
15757
15808
|
if (shuttingDown) return;
|
|
@@ -15770,24 +15821,29 @@ Received ${signal}, stopping server...`);
|
|
|
15770
15821
|
process.on("SIGTERM", () => shutdown("SIGTERM"));
|
|
15771
15822
|
process.on("SIGINT", () => shutdown("SIGINT"));
|
|
15772
15823
|
const url = operatorHttpUrl(host, port);
|
|
15773
|
-
if (isMachineFormat(format)) {
|
|
15774
|
-
console.log(JSON.stringify({
|
|
15775
|
-
started: true,
|
|
15776
|
-
host,
|
|
15777
|
-
port,
|
|
15778
|
-
url
|
|
15779
|
-
}, null, 2));
|
|
15780
|
-
} else {
|
|
15824
|
+
if (!isMachineFormat(format)) {
|
|
15781
15825
|
console.log(`
|
|
15782
15826
|
Canonry server running at ${url}`);
|
|
15783
|
-
console.log(
|
|
15827
|
+
console.log(buildServeOpenLine({ url, ...readServeOpenState(db) }));
|
|
15784
15828
|
if (shouldWarnAboutRemoteSetup(host)) {
|
|
15785
15829
|
console.log("First-run dashboard password setup is unauthenticated only on loopback; complete setup from this machine first or use a bearer cnry_... key.");
|
|
15786
15830
|
}
|
|
15787
15831
|
console.log("Press Ctrl+C to stop.\n");
|
|
15788
15832
|
const nudge = getMissingUserSkillsNudge(process.env.HOME, getAgentPluginState());
|
|
15789
|
-
if (nudge)
|
|
15833
|
+
if (shouldPrintServeSkillsNudge(nudge, getPrintedUpdateAvailable())) {
|
|
15834
|
+
process.stderr.write(`${nudge.message}
|
|
15790
15835
|
`);
|
|
15836
|
+
}
|
|
15837
|
+
}
|
|
15838
|
+
await waitForServerRuntimeStartup(app);
|
|
15839
|
+
listening = true;
|
|
15840
|
+
if (isMachineFormat(format)) {
|
|
15841
|
+
console.log(JSON.stringify({
|
|
15842
|
+
started: true,
|
|
15843
|
+
host,
|
|
15844
|
+
port,
|
|
15845
|
+
url
|
|
15846
|
+
}, null, 2));
|
|
15791
15847
|
}
|
|
15792
15848
|
setTelemetrySource("cli-server");
|
|
15793
15849
|
const providerNames = Object.keys(config.providers ?? {}).filter(
|
|
@@ -15972,6 +16028,7 @@ var SYSTEM_CLI_COMMANDS = [
|
|
|
15972
16028
|
{
|
|
15973
16029
|
path: ["init"],
|
|
15974
16030
|
usage: "canonry init [--force] [--gemini-key <key>] [--openai-key <key>] [--claude-key <key>] [--perplexity-key <key>] [--local-url <url>] [--local-model <name>] [--local-key <key>] [--google-client-id <id>] [--google-client-secret <key>] [--skip-skills] [--skip-mcp] [--skills-dir <path>] [--format json]",
|
|
16031
|
+
help: 'Optional interactive provider and OAuth setup. First-run Page Health does not need this: use "canonry bootstrap", then "canonry serve". At least one provider is required here. --format json needs provider flags or environment variables.',
|
|
15975
16032
|
options: {
|
|
15976
16033
|
force: { type: "boolean", short: "f", default: false },
|
|
15977
16034
|
"gemini-key": stringOption(),
|
|
@@ -16676,6 +16733,7 @@ var TECHNICAL_AEO_CLI_COMMANDS_BASE = [
|
|
|
16676
16733
|
{
|
|
16677
16734
|
path: ["technical-aeo", "run"],
|
|
16678
16735
|
usage: "canonry technical-aeo run <project> [--sitemap-url <url>] [--max-pages <n>] [--max-edges <n>] [--max-depth <n>] [--check-dead-links] [--wait] [--format json]",
|
|
16736
|
+
help: "Start a Site Health crawl. No answer-engine provider is required. --wait polls for up to 15 minutes. Dead-link checking is off unless --check-dead-links is set.",
|
|
16679
16737
|
options: {
|
|
16680
16738
|
"sitemap-url": stringOption(),
|
|
16681
16739
|
limit: stringOption(),
|
|
@@ -19235,9 +19293,17 @@ var REGISTERED_CLI_COMMANDS = [
|
|
|
19235
19293
|
var NUDGE_EXEMPT_ROOTS = /* @__PURE__ */ new Set([
|
|
19236
19294
|
"init",
|
|
19237
19295
|
"serve",
|
|
19296
|
+
"start",
|
|
19297
|
+
"stop",
|
|
19238
19298
|
"bootstrap",
|
|
19239
19299
|
"settings",
|
|
19240
19300
|
"telemetry",
|
|
19301
|
+
"project",
|
|
19302
|
+
"technical-aeo",
|
|
19303
|
+
"site-health",
|
|
19304
|
+
"doctor",
|
|
19305
|
+
"demo",
|
|
19306
|
+
"status",
|
|
19241
19307
|
"unknown"
|
|
19242
19308
|
]);
|
|
19243
19309
|
function buildSetupNudgeLine(input) {
|
|
@@ -19247,7 +19313,7 @@ function buildSetupNudgeLine(input) {
|
|
|
19247
19313
|
const setupState = input.getSetupState();
|
|
19248
19314
|
if (!setupState) return null;
|
|
19249
19315
|
if (setupState.provider_count > 0) return null;
|
|
19250
|
-
return "\n\u2192
|
|
19316
|
+
return "\n\u2192 AI Visibility needs an answer-engine provider. Page Health does not.\n Add one in the dashboard after `canonry serve`, or:\n canonry settings provider gemini --api-key <key>\n";
|
|
19251
19317
|
}
|
|
19252
19318
|
|
|
19253
19319
|
// src/cli.ts
|
|
@@ -19403,6 +19469,7 @@ async function runCli(args = process.argv.slice(2)) {
|
|
|
19403
19469
|
}
|
|
19404
19470
|
if (!isHelpRequest && command !== "telemetry") {
|
|
19405
19471
|
const update = readCachedUpdateAvailable();
|
|
19472
|
+
notePrintedUpdateAvailable(update);
|
|
19406
19473
|
if (update) {
|
|
19407
19474
|
process.stderr.write(formatUpdateNotice(update, { format, interactive: Boolean(process.stderr.isTTY) }));
|
|
19408
19475
|
}
|
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
import {
|
|
5
5
|
layoutSiteCrawlGraphInput,
|
|
6
6
|
persistSiteCrawlGraphLayout
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-P5YYRGFS.js";
|
|
8
8
|
import {
|
|
9
9
|
PACKAGE_VERSION
|
|
10
10
|
} from "./chunk-AOJU5LKX.js";
|
|
@@ -83,7 +83,7 @@ import {
|
|
|
83
83
|
siteCrawlPages,
|
|
84
84
|
siteCrawlSnapshots,
|
|
85
85
|
trafficSources
|
|
86
|
-
} from "./chunk-
|
|
86
|
+
} from "./chunk-2P52FD5B.js";
|
|
87
87
|
import {
|
|
88
88
|
RunKinds,
|
|
89
89
|
SiteCrawlFetchStates,
|
|
@@ -104,7 +104,7 @@ import {
|
|
|
104
104
|
measurementPlanV2Schema,
|
|
105
105
|
placementLinkDecision,
|
|
106
106
|
siteAuditPageFactorSchema
|
|
107
|
-
} from "./chunk-
|
|
107
|
+
} from "./chunk-Z6RA7LWY.js";
|
|
108
108
|
|
|
109
109
|
// src/demo-server.ts
|
|
110
110
|
import { dirname, join as join2 } from "path";
|
package/dist/index.js
CHANGED
|
@@ -3,14 +3,14 @@ import {
|
|
|
3
3
|
createGoogleMarketingCredentialStore,
|
|
4
4
|
createGoogleMarketingRuntime,
|
|
5
5
|
createServer
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-SLOTTXIL.js";
|
|
7
7
|
import {
|
|
8
8
|
loadConfig
|
|
9
|
-
} from "./chunk-
|
|
10
|
-
import "./chunk-
|
|
9
|
+
} from "./chunk-67OM5KEH.js";
|
|
10
|
+
import "./chunk-P5YYRGFS.js";
|
|
11
11
|
import "./chunk-AOJU5LKX.js";
|
|
12
|
-
import "./chunk-
|
|
13
|
-
import "./chunk-
|
|
12
|
+
import "./chunk-2P52FD5B.js";
|
|
13
|
+
import "./chunk-Z6RA7LWY.js";
|
|
14
14
|
export {
|
|
15
15
|
GoogleMarketingRuntimeError,
|
|
16
16
|
createGoogleMarketingCredentialStore,
|
package/dist/mcp.js
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import {
|
|
2
2
|
autoSyncSkills
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-L3FG66O7.js";
|
|
4
4
|
import {
|
|
5
5
|
createApiClient,
|
|
6
6
|
createCanonryMcpServer
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-67OM5KEH.js";
|
|
8
8
|
import "./chunk-AOJU5LKX.js";
|
|
9
9
|
import {
|
|
10
10
|
isReadOnlyKey,
|
|
11
11
|
updateCheckEnvOptOut
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-Z6RA7LWY.js";
|
|
13
13
|
|
|
14
14
|
// src/mcp/cli.ts
|
|
15
15
|
import { randomUUID } from "crypto";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ainyc/canonry",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.4.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Self-hosted AI visibility (AEO) platform: track how ChatGPT, Claude, Gemini, and Perplexity cite your domain, join it with Search Console, GA4, server-side traffic, and paid media, and fix what you find through agent tools (CLI, REST, MCP). Local SQLite.",
|
|
6
6
|
"keywords": [
|
|
@@ -87,31 +87,31 @@
|
|
|
87
87
|
"tsup": "^8.5.1",
|
|
88
88
|
"tsx": "^4.19.0",
|
|
89
89
|
"@ainyc/canonry-web": "0.0.0",
|
|
90
|
-
"@ainyc/canonry-api-client": "0.0.0",
|
|
91
90
|
"@ainyc/canonry-config": "0.0.0",
|
|
92
91
|
"@ainyc/canonry-contracts": "0.0.0",
|
|
93
92
|
"@ainyc/canonry-api-routes": "0.0.0",
|
|
94
|
-
"@ainyc/canonry-integration-bing": "0.0.0",
|
|
95
93
|
"@ainyc/canonry-db": "0.0.0",
|
|
94
|
+
"@ainyc/canonry-api-client": "0.0.0",
|
|
96
95
|
"@ainyc/canonry-integration-cloud-run": "0.0.0",
|
|
97
96
|
"@ainyc/canonry-integration-cloudflare-queue": "0.0.0",
|
|
97
|
+
"@ainyc/canonry-integration-bing": "0.0.0",
|
|
98
|
+
"@ainyc/canonry-integration-cloudflare-worker": "0.0.0",
|
|
98
99
|
"@ainyc/canonry-integration-commoncrawl": "0.0.0",
|
|
100
|
+
"@ainyc/canonry-integration-google-ads": "0.0.0",
|
|
101
|
+
"@ainyc/canonry-integration-google-business-profile": "0.0.0",
|
|
99
102
|
"@ainyc/canonry-integration-google": "0.0.0",
|
|
100
|
-
"@ainyc/canonry-integration-cloudflare-worker": "0.0.0",
|
|
101
103
|
"@ainyc/canonry-integration-google-places": "0.0.0",
|
|
102
|
-
"@ainyc/canonry-integration-google-business-profile": "0.0.0",
|
|
103
|
-
"@ainyc/canonry-integration-google-ads": "0.0.0",
|
|
104
104
|
"@ainyc/canonry-integration-google-tag-manager": "0.0.0",
|
|
105
|
-
"@ainyc/canonry-integration-traffic": "0.0.0",
|
|
106
105
|
"@ainyc/canonry-integration-openai-ads": "0.0.0",
|
|
107
106
|
"@ainyc/canonry-integration-wordpress": "0.0.0",
|
|
108
|
-
"@ainyc/canonry-
|
|
109
|
-
"@ainyc/canonry-provider-claude": "0.0.0",
|
|
107
|
+
"@ainyc/canonry-integration-traffic": "0.0.0",
|
|
110
108
|
"@ainyc/canonry-intelligence": "0.0.0",
|
|
109
|
+
"@ainyc/canonry-provider-claude": "0.0.0",
|
|
111
110
|
"@ainyc/canonry-provider-gemini": "0.0.0",
|
|
112
|
-
"@ainyc/canonry-provider-
|
|
111
|
+
"@ainyc/canonry-provider-cdp": "0.0.0",
|
|
112
|
+
"@ainyc/canonry-provider-perplexity": "0.0.0",
|
|
113
113
|
"@ainyc/canonry-provider-local": "0.0.0",
|
|
114
|
-
"@ainyc/canonry-provider-
|
|
114
|
+
"@ainyc/canonry-provider-openai": "0.0.0"
|
|
115
115
|
},
|
|
116
116
|
"scripts": {
|
|
117
117
|
"build": "pnpm run build:cli && pnpm run build:web",
|