@ainyc/canonry 4.84.0 → 4.86.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/assets/agent-workspace/skills/aero/references/regression-playbook.md +2 -0
- package/assets/agent-workspace/skills/canonry/references/canonry-cli.md +22 -1
- package/assets/assets/{BacklinksPage-OrSg_iPA.js → BacklinksPage-BNrvc-gV.js} +1 -1
- package/assets/assets/{ChartPrimitives-DPBhAT_r.js → ChartPrimitives-BlIkdUdy.js} +1 -1
- package/assets/assets/{ProjectPage-CpMcEmtw.js → ProjectPage-CAyx_xNr.js} +2 -2
- package/assets/assets/{RunRow-2Rty0BAH.js → RunRow-CAPnKzi7.js} +1 -1
- package/assets/assets/{RunsPage-B3ahqf8s.js → RunsPage-idnuzKBn.js} +1 -1
- package/assets/assets/{SettingsPage-BIjeI85q.js → SettingsPage-Bka67uJq.js} +1 -1
- package/assets/assets/{TrafficPage-DjGoj691.js → TrafficPage-C_o-rA5o.js} +1 -1
- package/assets/assets/{TrafficSourceDetailPage-BgKG-2q3.js → TrafficSourceDetailPage-D_jvoSTV.js} +1 -1
- package/assets/assets/{arrow-left-Cf7wmru1.js → arrow-left-B-JfzARi.js} +1 -1
- package/assets/assets/{extract-error-message-CANxezte.js → extract-error-message-BhPbjIX6.js} +1 -1
- package/assets/assets/{index-CGlPx_cu.js → index-uPSrDA8e.js} +77 -77
- package/assets/assets/{trash-2-6nHJZrvy.js → trash-2-BbRvn40h.js} +1 -1
- package/assets/index.html +1 -1
- package/dist/{chunk-BNF3HXBW.js → chunk-23HGQV22.js} +1460 -1149
- package/dist/{chunk-VJBO4VIK.js → chunk-DLBQU3VG.js} +712 -423
- package/dist/{chunk-Y3O3HBMN.js → chunk-LLJPZKHG.js} +94 -1
- package/dist/{chunk-M3IYKTSF.js → chunk-SELXBOAP.js} +19 -4
- package/dist/cli.js +210 -20
- package/dist/index.js +4 -4
- package/dist/{intelligence-service-PDIAMP5I.js → intelligence-service-ZHUJKZRO.js} +2 -2
- package/dist/mcp.js +2 -2
- package/package.json +10 -10
|
@@ -23,7 +23,7 @@ import {
|
|
|
23
23
|
trafficConnectVercelRequestSchema,
|
|
24
24
|
trafficConnectWordpressRequestSchema,
|
|
25
25
|
trafficEventKindSchema
|
|
26
|
-
} from "./chunk-
|
|
26
|
+
} from "./chunk-23HGQV22.js";
|
|
27
27
|
|
|
28
28
|
// src/config.ts
|
|
29
29
|
import fs from "fs";
|
|
@@ -1538,6 +1538,18 @@ var getApiV1ProjectsByNameAnalyticsSources = (options) => {
|
|
|
1538
1538
|
...options
|
|
1539
1539
|
});
|
|
1540
1540
|
};
|
|
1541
|
+
var getApiV1ProjectsByNameVisibilityStats = (options) => {
|
|
1542
|
+
return (options.client ?? client).get({
|
|
1543
|
+
security: [
|
|
1544
|
+
{
|
|
1545
|
+
scheme: "bearer",
|
|
1546
|
+
type: "http"
|
|
1547
|
+
}
|
|
1548
|
+
],
|
|
1549
|
+
url: "/api/v1/projects/{name}/visibility-stats",
|
|
1550
|
+
...options
|
|
1551
|
+
});
|
|
1552
|
+
};
|
|
1541
1553
|
var getApiV1ProjectsByNameSnapshotsDiff = (options) => {
|
|
1542
1554
|
return (options.client ?? client).get({
|
|
1543
1555
|
security: [
|
|
@@ -3442,6 +3454,18 @@ var getApiV1ProjectsByNameDiscoverSessionsById = (options) => {
|
|
|
3442
3454
|
...options
|
|
3443
3455
|
});
|
|
3444
3456
|
};
|
|
3457
|
+
var getApiV1ProjectsByNameDiscoverSessionsByIdHarvest = (options) => {
|
|
3458
|
+
return (options.client ?? client).get({
|
|
3459
|
+
security: [
|
|
3460
|
+
{
|
|
3461
|
+
scheme: "bearer",
|
|
3462
|
+
type: "http"
|
|
3463
|
+
}
|
|
3464
|
+
],
|
|
3465
|
+
url: "/api/v1/projects/{name}/discover/sessions/{id}/harvest",
|
|
3466
|
+
...options
|
|
3467
|
+
});
|
|
3468
|
+
};
|
|
3445
3469
|
var getApiV1ProjectsByNameDiscoverSessionsByIdPromote = (options) => {
|
|
3446
3470
|
return (options.client ?? client).get({
|
|
3447
3471
|
security: [
|
|
@@ -4738,6 +4762,19 @@ var ApiClient = class {
|
|
|
4738
4762
|
})
|
|
4739
4763
|
);
|
|
4740
4764
|
}
|
|
4765
|
+
async getDiscoveryHarvest(project, sessionId, opts) {
|
|
4766
|
+
return this.invoke(
|
|
4767
|
+
() => getApiV1ProjectsByNameDiscoverSessionsByIdHarvest({
|
|
4768
|
+
client: this.heyClient,
|
|
4769
|
+
path: { name: project, id: sessionId },
|
|
4770
|
+
query: {
|
|
4771
|
+
minProbeHits: opts?.minProbeHits !== void 0 ? String(opts.minProbeHits) : void 0,
|
|
4772
|
+
// The server treats anchor=false as "disable"; omit otherwise.
|
|
4773
|
+
anchor: opts?.anchor === false ? "false" : void 0
|
|
4774
|
+
}
|
|
4775
|
+
})
|
|
4776
|
+
);
|
|
4777
|
+
}
|
|
4741
4778
|
async previewDiscoveryPromote(project, sessionId) {
|
|
4742
4779
|
return this.invoke(
|
|
4743
4780
|
() => getApiV1ProjectsByNameDiscoverSessionsByIdPromote({
|
|
@@ -5062,6 +5099,20 @@ var ApiClient = class {
|
|
|
5062
5099
|
() => getApiV1ProjectsByNameCitationsVisibility({ client: this.heyClient, path: { name: project } })
|
|
5063
5100
|
);
|
|
5064
5101
|
}
|
|
5102
|
+
async getVisibilityStats(project, opts = {}) {
|
|
5103
|
+
return this.invoke(
|
|
5104
|
+
() => getApiV1ProjectsByNameVisibilityStats({
|
|
5105
|
+
client: this.heyClient,
|
|
5106
|
+
path: { name: project },
|
|
5107
|
+
query: {
|
|
5108
|
+
since: opts.since,
|
|
5109
|
+
until: opts.until,
|
|
5110
|
+
lastRuns: opts.lastRuns,
|
|
5111
|
+
groupBy: opts.groupBy
|
|
5112
|
+
}
|
|
5113
|
+
})
|
|
5114
|
+
);
|
|
5115
|
+
}
|
|
5065
5116
|
// ── Backlinks — workspace-level ────────────────────────────────────────
|
|
5066
5117
|
async backlinksStatus() {
|
|
5067
5118
|
return this.invoke(() => getApiV1BacklinksStatus({ client: this.heyClient }));
|
|
@@ -5468,6 +5519,12 @@ var discoverySessionIdInputSchema = z2.object({
|
|
|
5468
5519
|
project: projectNameSchema,
|
|
5469
5520
|
sessionId: z2.string().min(1).describe("Discovery session ID returned by canonry_discover_run_start.")
|
|
5470
5521
|
});
|
|
5522
|
+
var discoveryHarvestInputSchema = z2.object({
|
|
5523
|
+
project: projectNameSchema,
|
|
5524
|
+
sessionId: z2.string().min(1).describe("Discovery session ID returned by canonry_discover_run_start."),
|
|
5525
|
+
minProbeHits: z2.number().int().positive().optional().describe("Recurrence floor \u2014 a candidate must have appeared in at least this many distinct probes to be admitted. Default 1."),
|
|
5526
|
+
anchor: z2.boolean().optional().describe("Apply the subject-anchor filter that drops off-topic acronym collisions. Default true; pass false for new-subject discovery on a well-scoped project.")
|
|
5527
|
+
});
|
|
5471
5528
|
var discoveryPromoteInputSchema = z2.object({
|
|
5472
5529
|
project: projectNameSchema,
|
|
5473
5530
|
sessionId: z2.string().min(1).describe("Discovery session ID returned by canonry_discover_run_start."),
|
|
@@ -5768,6 +5825,28 @@ var canonryMcpTools = [
|
|
|
5768
5825
|
openApiOperations: ["GET /api/v1/projects/{name}/citations/visibility"],
|
|
5769
5826
|
handler: (client2, input) => client2.getCitationVisibility(input.project)
|
|
5770
5827
|
}),
|
|
5828
|
+
defineTool({
|
|
5829
|
+
name: "canonry_visibility_stats",
|
|
5830
|
+
title: "Get aggregated mention/citation stats",
|
|
5831
|
+
description: 'Per-query mention (answer-text) and citation (source-list) counts WITH a sample size, pooled across many answer-visibility runs (probe-excluded) \u2014 the data to compute a confidence-aware (Wilson) proportion or detect drift without fetching every run. Tri-state aware: `checked` (the n for the mention proportion) counts only snapshots where answerMentioned was recorded; `null` ("not checked") is excluded, never counted as not-mentioned. Returns per-query `total`/`checked`/`mentioned`/`cited` + derived `mentionRate` (mentioned/checked) and `citedRate` (cited/total), `firstObserved`/`lastObserved`, and pooled `totals`. Window with `since`/`until` (ISO) OR `lastRuns` (mutually exclusive); with none set, EVERY completed/partial run is pooled (`window.runCount` says how many) \u2014 pass `lastRuns` for a recent sample. Set `groupBy=provider` for a per-provider breakdown whose counts sum to the pooled counts (`groupBy` is omitted from the response otherwise).',
|
|
5832
|
+
access: "read",
|
|
5833
|
+
tier: "monitoring",
|
|
5834
|
+
inputSchema: z2.object({
|
|
5835
|
+
project: projectNameSchema,
|
|
5836
|
+
since: z2.string().optional().describe("Inclusive lower bound on run createdAt (ISO 8601). A date-only value (YYYY-MM-DD) is the start of that UTC day. Mutually exclusive with lastRuns."),
|
|
5837
|
+
until: z2.string().optional().describe("Inclusive upper bound on run createdAt (ISO 8601). A date-only value (YYYY-MM-DD) covers the whole UTC day (through 23:59:59.999). Mutually exclusive with lastRuns."),
|
|
5838
|
+
lastRuns: z2.number().int().positive().optional().describe("Aggregate only the most recent N answer-visibility runs. Mutually exclusive with since/until."),
|
|
5839
|
+
groupBy: z2.enum(["provider"]).optional().describe('Set to "provider" for a per-provider breakdown.')
|
|
5840
|
+
}),
|
|
5841
|
+
annotations: readAnnotations(),
|
|
5842
|
+
openApiOperations: ["GET /api/v1/projects/{name}/visibility-stats"],
|
|
5843
|
+
handler: (client2, input) => client2.getVisibilityStats(input.project, {
|
|
5844
|
+
since: input.since,
|
|
5845
|
+
until: input.until,
|
|
5846
|
+
lastRuns: input.lastRuns,
|
|
5847
|
+
groupBy: input.groupBy
|
|
5848
|
+
})
|
|
5849
|
+
}),
|
|
5771
5850
|
defineTool({
|
|
5772
5851
|
name: "canonry_content_targets",
|
|
5773
5852
|
title: "Get content targets",
|
|
@@ -6701,6 +6780,20 @@ var canonryMcpTools = [
|
|
|
6701
6780
|
openApiOperations: ["GET /api/v1/projects/{name}/discover/sessions/{id}"],
|
|
6702
6781
|
handler: (client2, input) => client2.getDiscoverySession(input.project, input.sessionId)
|
|
6703
6782
|
}),
|
|
6783
|
+
defineTool({
|
|
6784
|
+
name: "canonry_discover_harvest",
|
|
6785
|
+
title: "Harvest discovery search queries",
|
|
6786
|
+
description: `Read the search queries the answer engine actually issued (Gemini's grounding fan-out) back out of a session's stored probes, gate them for buyer-intent + novelty, and return the survivors as candidate seeds ranked by how many distinct probes issued each one. These are a THIRD signal \u2014 issued retrieval queries \u2014 distinct from mention (answer text) and cited (source list); they carry no demand of their own. Read-only and derived: nothing is probed, tracked, or promoted. Use it to surface "queries the model searched for that you aren't tracking yet"; the operator/agent then decides what to add via canonry_query_add. minProbeHits raises the recurrence floor; anchor=false disables the subject filter. stats carries the raw count and per-reason rejection tally.`,
|
|
6787
|
+
access: "read",
|
|
6788
|
+
tier: "discovery",
|
|
6789
|
+
inputSchema: discoveryHarvestInputSchema,
|
|
6790
|
+
annotations: readAnnotations(),
|
|
6791
|
+
openApiOperations: ["GET /api/v1/projects/{name}/discover/sessions/{id}/harvest"],
|
|
6792
|
+
handler: (client2, input) => client2.getDiscoveryHarvest(input.project, input.sessionId, {
|
|
6793
|
+
minProbeHits: input.minProbeHits,
|
|
6794
|
+
anchor: input.anchor
|
|
6795
|
+
})
|
|
6796
|
+
}),
|
|
6704
6797
|
defineTool({
|
|
6705
6798
|
name: "canonry_discover_promote_preview",
|
|
6706
6799
|
title: "Preview discovery promotion",
|
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
loadConfig,
|
|
10
10
|
loadConfigRaw,
|
|
11
11
|
saveConfigPatch
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-LLJPZKHG.js";
|
|
13
13
|
import {
|
|
14
14
|
CC_CACHE_DIR,
|
|
15
15
|
DUCKDB_SPEC,
|
|
@@ -104,7 +104,7 @@ import {
|
|
|
104
104
|
siteAuditPages,
|
|
105
105
|
siteAuditSnapshots,
|
|
106
106
|
usageCounters
|
|
107
|
-
} from "./chunk-
|
|
107
|
+
} from "./chunk-DLBQU3VG.js";
|
|
108
108
|
import {
|
|
109
109
|
AGENT_MEMORY_VALUE_MAX_BYTES,
|
|
110
110
|
AGENT_PROVIDER_IDS,
|
|
@@ -160,7 +160,7 @@ import {
|
|
|
160
160
|
validationError,
|
|
161
161
|
winnabilityClassLabel,
|
|
162
162
|
withRetry
|
|
163
|
-
} from "./chunk-
|
|
163
|
+
} from "./chunk-23HGQV22.js";
|
|
164
164
|
|
|
165
165
|
// src/telemetry.ts
|
|
166
166
|
import crypto from "crypto";
|
|
@@ -6289,7 +6289,7 @@ function readStoredGroundingSources(rawResponse) {
|
|
|
6289
6289
|
return result;
|
|
6290
6290
|
}
|
|
6291
6291
|
async function backfillInsightsCommand(project, opts) {
|
|
6292
|
-
const { IntelligenceService: IntelligenceService2 } = await import("./intelligence-service-
|
|
6292
|
+
const { IntelligenceService: IntelligenceService2 } = await import("./intelligence-service-ZHUJKZRO.js");
|
|
6293
6293
|
const config = loadConfig();
|
|
6294
6294
|
const db = createClient(config.database);
|
|
6295
6295
|
migrate(db);
|
|
@@ -10877,6 +10877,21 @@ async function createServer(opts) {
|
|
|
10877
10877
|
app.log.error({ runId: input.runId, err }, "Discovery run failed");
|
|
10878
10878
|
});
|
|
10879
10879
|
},
|
|
10880
|
+
// Read issued search queries (fan-out) back out of a stored probe payload.
|
|
10881
|
+
// Discovery is Gemini-only today, so the Gemini extractor handles every
|
|
10882
|
+
// probe; the provider arg lets a future multi-provider discovery dispatch.
|
|
10883
|
+
harvestSearchQueries: ({ rawResponse }) => extractSearchQueriesFromRaw(rawResponse),
|
|
10884
|
+
// Embed seam for the harvest's semantic novelty pass — the same Gemini
|
|
10885
|
+
// embedder the discovery seed pipeline uses. Resolved at call time so a
|
|
10886
|
+
// provider key set after boot is picked up; rejects (→ route degrades to
|
|
10887
|
+
// exact-match novelty) when no Gemini key is configured.
|
|
10888
|
+
embedQueries: (queriesToEmbed) => {
|
|
10889
|
+
const cfg = registry.get("gemini")?.config;
|
|
10890
|
+
if (!cfg?.apiKey) {
|
|
10891
|
+
return Promise.reject(new Error("Gemini API key not configured; harvest semantic novelty unavailable"));
|
|
10892
|
+
}
|
|
10893
|
+
return embedQueries(queriesToEmbed, { apiKey: cfg.apiKey, baseUrl: cfg.baseUrl });
|
|
10894
|
+
},
|
|
10880
10895
|
onSiteAuditRequested: (runId, projectId, auditOpts) => {
|
|
10881
10896
|
runSiteAudit(runId, projectId, auditOpts);
|
|
10882
10897
|
},
|
package/dist/cli.js
CHANGED
|
@@ -27,7 +27,7 @@ import {
|
|
|
27
27
|
setTelemetrySource,
|
|
28
28
|
showFirstRunNotice,
|
|
29
29
|
trackEvent
|
|
30
|
-
} from "./chunk-
|
|
30
|
+
} from "./chunk-SELXBOAP.js";
|
|
31
31
|
import {
|
|
32
32
|
CliError,
|
|
33
33
|
EXIT_SYSTEM_ERROR,
|
|
@@ -44,7 +44,7 @@ import {
|
|
|
44
44
|
saveConfig,
|
|
45
45
|
saveConfigPatch,
|
|
46
46
|
usageError
|
|
47
|
-
} from "./chunk-
|
|
47
|
+
} from "./chunk-LLJPZKHG.js";
|
|
48
48
|
import {
|
|
49
49
|
apiKeys,
|
|
50
50
|
createClient,
|
|
@@ -52,7 +52,7 @@ import {
|
|
|
52
52
|
projects,
|
|
53
53
|
queries,
|
|
54
54
|
renderReportHtml
|
|
55
|
-
} from "./chunk-
|
|
55
|
+
} from "./chunk-DLBQU3VG.js";
|
|
56
56
|
import {
|
|
57
57
|
BacklinkSources,
|
|
58
58
|
CcReleaseSyncStatuses,
|
|
@@ -70,13 +70,14 @@ import {
|
|
|
70
70
|
formatGbpMetricLabel,
|
|
71
71
|
formatIsoDate,
|
|
72
72
|
formatMicros,
|
|
73
|
+
formatRatio,
|
|
73
74
|
formatRunErrorOneLine,
|
|
74
75
|
normalizeProjectAliases,
|
|
75
76
|
notificationEventSchema,
|
|
76
77
|
providerQuotaPolicySchema,
|
|
77
78
|
resolveProviderInput,
|
|
78
79
|
winnabilityClassSchema
|
|
79
|
-
} from "./chunk-
|
|
80
|
+
} from "./chunk-23HGQV22.js";
|
|
80
81
|
|
|
81
82
|
// src/cli.ts
|
|
82
83
|
import { pathToFileURL } from "url";
|
|
@@ -1831,6 +1832,39 @@ async function discoverShow(project, sessionId, opts) {
|
|
|
1831
1832
|
}
|
|
1832
1833
|
printSessionDetail(session);
|
|
1833
1834
|
}
|
|
1835
|
+
async function discoverHarvest(project, sessionId, opts) {
|
|
1836
|
+
const client = getClient4();
|
|
1837
|
+
const harvest = await client.getDiscoveryHarvest(project, sessionId, {
|
|
1838
|
+
minProbeHits: opts.minProbeHits,
|
|
1839
|
+
anchor: opts.anchor
|
|
1840
|
+
});
|
|
1841
|
+
if (opts.format === "json") {
|
|
1842
|
+
console.log(JSON.stringify(harvest, null, 2));
|
|
1843
|
+
return;
|
|
1844
|
+
}
|
|
1845
|
+
if (opts.format === "jsonl") {
|
|
1846
|
+
const context = { project, sessionId, provider: harvest.provider };
|
|
1847
|
+
emitJsonl(harvest.candidates.map((c) => ({ ...context, ...c })));
|
|
1848
|
+
return;
|
|
1849
|
+
}
|
|
1850
|
+
const r = harvest.stats.rejected;
|
|
1851
|
+
console.log(`Harvested issued search queries \u2014 session ${harvest.sessionId} (${harvest.provider})`);
|
|
1852
|
+
console.log(
|
|
1853
|
+
` ${harvest.stats.admitted} admitted of ${harvest.stats.rawCandidates} raw \xB7 floor=${harvest.minProbeHits} \xB7 anchor=${harvest.anchorApplied ? "on" : "off"} \xB7 novelty=${harvest.semanticNoveltyApplied ? "semantic" : "exact-only"}`
|
|
1854
|
+
);
|
|
1855
|
+
console.log(
|
|
1856
|
+
` rejected: ${r.belowFloor} below-floor \xB7 ${r.length} length \xB7 ${r.navigational} navigational \xB7 ${r.duplicate} already-tracked \xB7 ${r.semanticDuplicate} synonym \xB7 ${r.offAnchor} off-subject`
|
|
1857
|
+
);
|
|
1858
|
+
if (harvest.candidates.length === 0) {
|
|
1859
|
+
console.log(" (no candidates \u2014 nothing to track from this session)");
|
|
1860
|
+
return;
|
|
1861
|
+
}
|
|
1862
|
+
console.log("");
|
|
1863
|
+
console.log(" HITS QUERY");
|
|
1864
|
+
for (const candidate of harvest.candidates) {
|
|
1865
|
+
console.log(` ${String(candidate.probeHits).padStart(4)} ${candidate.query}`);
|
|
1866
|
+
}
|
|
1867
|
+
}
|
|
1834
1868
|
async function discoverPromotePreview(project, sessionId, opts) {
|
|
1835
1869
|
const client = getClient4();
|
|
1836
1870
|
const preview = await client.previewDiscoveryPromote(project, sessionId);
|
|
@@ -2155,6 +2189,32 @@ var DISCOVER_CLI_COMMANDS = [
|
|
|
2155
2189
|
});
|
|
2156
2190
|
}
|
|
2157
2191
|
},
|
|
2192
|
+
{
|
|
2193
|
+
path: ["discover", "harvest"],
|
|
2194
|
+
usage: "canonry discover harvest <project> <session-id> [--min-probe-hits <n>] [--no-anchor] [--format json|jsonl]",
|
|
2195
|
+
options: {
|
|
2196
|
+
"min-probe-hits": stringOption(),
|
|
2197
|
+
"no-anchor": { type: "boolean", default: false }
|
|
2198
|
+
},
|
|
2199
|
+
run: async (input) => {
|
|
2200
|
+
const usage = "canonry discover harvest <project> <session-id> [--min-probe-hits <n>] [--no-anchor] [--format json|jsonl]";
|
|
2201
|
+
const project = requireProject(input, "discover.harvest", usage);
|
|
2202
|
+
const sessionId = requirePositional(input, 1, {
|
|
2203
|
+
command: "discover.harvest",
|
|
2204
|
+
usage,
|
|
2205
|
+
message: "session ID is required"
|
|
2206
|
+
});
|
|
2207
|
+
await discoverHarvest(project, sessionId, {
|
|
2208
|
+
minProbeHits: parseIntegerOption(input, "min-probe-hits", {
|
|
2209
|
+
command: "discover.harvest",
|
|
2210
|
+
usage,
|
|
2211
|
+
message: "--min-probe-hits must be an integer"
|
|
2212
|
+
}),
|
|
2213
|
+
anchor: !getBoolean(input.values, "no-anchor"),
|
|
2214
|
+
format: input.format
|
|
2215
|
+
});
|
|
2216
|
+
}
|
|
2217
|
+
},
|
|
2158
2218
|
{
|
|
2159
2219
|
path: ["discover", "promote", "preview"],
|
|
2160
2220
|
usage: "canonry discover promote preview <project> <session-id> [--format json]",
|
|
@@ -2868,7 +2928,7 @@ async function gaSocialReferralSummary(project, opts) {
|
|
|
2868
2928
|
console.log(` Sessions: ${traffic.socialSessions} (${traffic.socialSharePct}% of ${traffic.totalSessions} total)`);
|
|
2869
2929
|
console.log(` Users: ${traffic.socialUsers}`);
|
|
2870
2930
|
console.log();
|
|
2871
|
-
const fmtTrend = (
|
|
2931
|
+
const fmtTrend = (pct4) => pct4 === null ? "n/a" : `${pct4 >= 0 ? "+" : ""}${pct4}%`;
|
|
2872
2932
|
console.log(` 7d trend: ${fmtTrend(trend.trend7dPct)} (${trend.socialSessions7d} vs ${trend.socialSessionsPrev7d})`);
|
|
2873
2933
|
console.log(` 30d trend: ${fmtTrend(trend.trend30dPct)} (${trend.socialSessions30d} vs ${trend.socialSessionsPrev30d})`);
|
|
2874
2934
|
if (trend.biggestMover) {
|
|
@@ -2911,7 +2971,7 @@ async function gaSocialReferralSummary(project, opts) {
|
|
|
2911
2971
|
async function gaAttribution(project, opts) {
|
|
2912
2972
|
const client = getClient6();
|
|
2913
2973
|
const traffic = await client.gaTraffic(project);
|
|
2914
|
-
const fmtTrend = (
|
|
2974
|
+
const fmtTrend = (pct4) => pct4 === null ? "n/a" : `${pct4 >= 0 ? "+" : ""}${pct4}%`;
|
|
2915
2975
|
if (opts?.trend) {
|
|
2916
2976
|
const trend = await client.gaAttributionTrend(project);
|
|
2917
2977
|
if (isMachineFormat(opts.format)) {
|
|
@@ -3475,9 +3535,9 @@ async function gbpPlaces(project, opts) {
|
|
|
3475
3535
|
console.log(` ${p.locationName} [${p.tier}] ${amenities}`);
|
|
3476
3536
|
}
|
|
3477
3537
|
}
|
|
3478
|
-
function fmtDelta(
|
|
3479
|
-
if (
|
|
3480
|
-
return `${
|
|
3538
|
+
function fmtDelta(pct4) {
|
|
3539
|
+
if (pct4 === null) return "n/a";
|
|
3540
|
+
return `${pct4 >= 0 ? "+" : ""}${pct4}%`;
|
|
3481
3541
|
}
|
|
3482
3542
|
async function gbpSummary(project, opts) {
|
|
3483
3543
|
const client = getClient7();
|
|
@@ -6951,14 +7011,14 @@ function printMetrics(data) {
|
|
|
6951
7011
|
console.log(`
|
|
6952
7012
|
Citation Rate Trends (${data.window})`);
|
|
6953
7013
|
console.log("\u2500".repeat(50));
|
|
6954
|
-
const
|
|
6955
|
-
console.log(` Overall: ${
|
|
7014
|
+
const pct4 = (n) => `${(n * 100).toFixed(1)}%`;
|
|
7015
|
+
console.log(` Overall: ${pct4(data.overall.citationRate)} (${data.overall.cited}/${data.overall.total})`);
|
|
6956
7016
|
console.log(` Trend: ${data.trend}`);
|
|
6957
7017
|
if (Object.keys(data.byProvider).length > 0) {
|
|
6958
7018
|
console.log(`
|
|
6959
7019
|
By Provider:`);
|
|
6960
7020
|
for (const [provider, metric] of Object.entries(data.byProvider)) {
|
|
6961
|
-
console.log(` ${provider.padEnd(10)} ${
|
|
7021
|
+
console.log(` ${provider.padEnd(10)} ${pct4(metric.citationRate).padStart(6)} (${metric.cited}/${metric.total})`);
|
|
6962
7022
|
}
|
|
6963
7023
|
}
|
|
6964
7024
|
if (data.buckets.length > 0) {
|
|
@@ -6967,7 +7027,7 @@ Citation Rate Trends (${data.window})`);
|
|
|
6967
7027
|
for (const bucket of data.buckets) {
|
|
6968
7028
|
const start = bucket.startDate.slice(0, 10);
|
|
6969
7029
|
const bar = bucket.total > 0 ? "\u2588".repeat(Math.round(bucket.citationRate * 20)) : "";
|
|
6970
|
-
console.log(` ${start} ${
|
|
7030
|
+
console.log(` ${start} ${pct4(bucket.citationRate).padStart(6)} ${bar}`);
|
|
6971
7031
|
}
|
|
6972
7032
|
}
|
|
6973
7033
|
const providersInBuckets = [...new Set(data.buckets.flatMap((b) => Object.keys(b.byProvider ?? {})))].sort();
|
|
@@ -6981,7 +7041,7 @@ Citation Rate Trends (${data.window})`);
|
|
|
6981
7041
|
if (!metric) continue;
|
|
6982
7042
|
const start = bucket.startDate.slice(0, 10);
|
|
6983
7043
|
const bar = metric.total > 0 ? "\u2588".repeat(Math.round(metric.citationRate * 20)) : "";
|
|
6984
|
-
console.log(` ${start} ${
|
|
7044
|
+
console.log(` ${start} ${pct4(metric.citationRate).padStart(6)} ${bar}`);
|
|
6985
7045
|
}
|
|
6986
7046
|
}
|
|
6987
7047
|
}
|
|
@@ -7019,9 +7079,9 @@ Source Origin Breakdown`);
|
|
|
7019
7079
|
return;
|
|
7020
7080
|
}
|
|
7021
7081
|
for (const cat of data.overall) {
|
|
7022
|
-
const
|
|
7082
|
+
const pct4 = `${(cat.percentage * 100).toFixed(1)}%`;
|
|
7023
7083
|
const domains = cat.topDomains.slice(0, 3).map((d) => d.domain).join(", ");
|
|
7024
|
-
console.log(` ${cat.label.padEnd(20)} ${
|
|
7084
|
+
console.log(` ${cat.label.padEnd(20)} ${pct4.padStart(6)} (${cat.count}) ${domains}`);
|
|
7025
7085
|
}
|
|
7026
7086
|
}
|
|
7027
7087
|
|
|
@@ -9455,8 +9515,8 @@ function printMentionShareBreakdown(mentionShare) {
|
|
|
9455
9515
|
const youPct = (breakdown.projectMentionSnapshots / total * 100).toFixed(1);
|
|
9456
9516
|
console.log(` you${" ".repeat(28)} ${breakdown.projectMentionSnapshots} mentions (${youPct}% of combined)`);
|
|
9457
9517
|
for (const row of breakdown.perCompetitor.slice(0, 3)) {
|
|
9458
|
-
const
|
|
9459
|
-
console.log(` ${row.domain.padEnd(30)} ${row.mentionSnapshots} mentions (${
|
|
9518
|
+
const pct4 = (row.mentionSnapshots / total * 100).toFixed(1);
|
|
9519
|
+
console.log(` ${row.domain.padEnd(30)} ${row.mentionSnapshots} mentions (${pct4}% of combined)`);
|
|
9460
9520
|
}
|
|
9461
9521
|
if (breakdown.perCompetitor.length > 3) {
|
|
9462
9522
|
console.log(` + ${breakdown.perCompetitor.length - 3} more competitor${breakdown.perCompetitor.length - 3 === 1 ? "" : "s"} (--format json for full breakdown)`);
|
|
@@ -11266,6 +11326,135 @@ var TECHNICAL_AEO_CLI_COMMANDS = [
|
|
|
11266
11326
|
}
|
|
11267
11327
|
];
|
|
11268
11328
|
|
|
11329
|
+
// src/commands/visibility-stats.ts
|
|
11330
|
+
async function showVisibilityStats(project, opts) {
|
|
11331
|
+
const client = createApiClient();
|
|
11332
|
+
const data = await client.getVisibilityStats(project, {
|
|
11333
|
+
since: opts.since,
|
|
11334
|
+
until: opts.until,
|
|
11335
|
+
lastRuns: opts.lastRuns,
|
|
11336
|
+
groupBy: opts.byProvider ? "provider" : void 0
|
|
11337
|
+
});
|
|
11338
|
+
if (opts.format === "jsonl") {
|
|
11339
|
+
emitJsonl(data.queries.map((q) => ({ project: data.project, runCount: data.window.runCount, ...q })));
|
|
11340
|
+
return;
|
|
11341
|
+
}
|
|
11342
|
+
if (opts.format === "json") {
|
|
11343
|
+
console.log(JSON.stringify(data, null, 2));
|
|
11344
|
+
return;
|
|
11345
|
+
}
|
|
11346
|
+
printVisibilityStats(data);
|
|
11347
|
+
}
|
|
11348
|
+
function pct3(rate) {
|
|
11349
|
+
return rate === null ? "\u2014" : formatRatio(rate);
|
|
11350
|
+
}
|
|
11351
|
+
function citedCell(c) {
|
|
11352
|
+
return `${c.cited}/${c.total}`;
|
|
11353
|
+
}
|
|
11354
|
+
function mentionedCell(c) {
|
|
11355
|
+
return `${c.mentioned}/${c.checked}`;
|
|
11356
|
+
}
|
|
11357
|
+
function printVisibilityStats(data) {
|
|
11358
|
+
const w = data.window;
|
|
11359
|
+
const windowParts = [`${w.runCount} run(s)`];
|
|
11360
|
+
if (w.lastRuns !== null) windowParts.push(`last ${w.lastRuns}`);
|
|
11361
|
+
if (w.since !== null) windowParts.push(`since ${w.since}`);
|
|
11362
|
+
if (w.until !== null) windowParts.push(`until ${w.until}`);
|
|
11363
|
+
console.log("Visibility stats (cited = source list, mentioned = answer text)");
|
|
11364
|
+
console.log(`Window: ${windowParts.join(" \xB7 ")}`);
|
|
11365
|
+
console.log('Cited = cited/total snapshots \xB7 Mentioned = mentioned/checked (checked excludes "not checked")');
|
|
11366
|
+
console.log("");
|
|
11367
|
+
if (data.queries.length === 0) {
|
|
11368
|
+
console.log("No answer-visibility snapshots in this window \u2014 run a sweep first (canonry run <project>).");
|
|
11369
|
+
return;
|
|
11370
|
+
}
|
|
11371
|
+
const rows = data.queries.map((q) => ({
|
|
11372
|
+
label: q.query,
|
|
11373
|
+
cited: citedCell(q),
|
|
11374
|
+
citedPct: pct3(q.citedRate),
|
|
11375
|
+
ment: mentionedCell(q),
|
|
11376
|
+
mentPct: pct3(q.mentionRate)
|
|
11377
|
+
}));
|
|
11378
|
+
const queryWidth = Math.max(7, ...rows.map((r) => r.label.length));
|
|
11379
|
+
const citedWidth = Math.max(7, ...rows.map((r) => r.cited.length));
|
|
11380
|
+
const mentWidth = Math.max(9, ...rows.map((r) => r.ment.length));
|
|
11381
|
+
const header = [
|
|
11382
|
+
"Query".padEnd(queryWidth),
|
|
11383
|
+
"Cited".padEnd(citedWidth),
|
|
11384
|
+
"Cited%".padStart(7),
|
|
11385
|
+
"Mentioned".padEnd(mentWidth),
|
|
11386
|
+
"Ment%".padStart(7)
|
|
11387
|
+
].join(" ");
|
|
11388
|
+
console.log(header);
|
|
11389
|
+
console.log("\u2500".repeat(header.length));
|
|
11390
|
+
for (const r of rows) {
|
|
11391
|
+
console.log(
|
|
11392
|
+
[
|
|
11393
|
+
r.label.padEnd(queryWidth),
|
|
11394
|
+
r.cited.padEnd(citedWidth),
|
|
11395
|
+
r.citedPct.padStart(7),
|
|
11396
|
+
r.ment.padEnd(mentWidth),
|
|
11397
|
+
r.mentPct.padStart(7)
|
|
11398
|
+
].join(" ")
|
|
11399
|
+
);
|
|
11400
|
+
}
|
|
11401
|
+
console.log("\u2500".repeat(header.length));
|
|
11402
|
+
console.log(
|
|
11403
|
+
[
|
|
11404
|
+
"TOTAL".padEnd(queryWidth),
|
|
11405
|
+
citedCell(data.totals).padEnd(citedWidth),
|
|
11406
|
+
pct3(data.totals.citedRate).padStart(7),
|
|
11407
|
+
mentionedCell(data.totals).padEnd(mentWidth),
|
|
11408
|
+
pct3(data.totals.mentionRate).padStart(7)
|
|
11409
|
+
].join(" ")
|
|
11410
|
+
);
|
|
11411
|
+
if (data.groupBy === "provider" && data.byProvider && data.byProvider.length > 0) {
|
|
11412
|
+
console.log("");
|
|
11413
|
+
console.log("By provider (pooled across queries):");
|
|
11414
|
+
const provWidth = Math.max(8, ...data.byProvider.map((p) => p.provider.length));
|
|
11415
|
+
for (const p of data.byProvider) {
|
|
11416
|
+
console.log(
|
|
11417
|
+
[
|
|
11418
|
+
` ${p.provider}`.padEnd(provWidth + 2),
|
|
11419
|
+
citedCell(p).padEnd(citedWidth),
|
|
11420
|
+
pct3(p.citedRate).padStart(7),
|
|
11421
|
+
mentionedCell(p).padEnd(mentWidth),
|
|
11422
|
+
pct3(p.mentionRate).padStart(7)
|
|
11423
|
+
].join(" ")
|
|
11424
|
+
);
|
|
11425
|
+
}
|
|
11426
|
+
}
|
|
11427
|
+
}
|
|
11428
|
+
|
|
11429
|
+
// src/cli-commands/visibility-stats.ts
|
|
11430
|
+
var USAGE4 = "canonry visibility-stats <project> [--since <iso>] [--until <iso>] [--last-runs <n>] [--by-provider] [--format json|jsonl]";
|
|
11431
|
+
var VISIBILITY_STATS_CLI_COMMANDS = [
|
|
11432
|
+
{
|
|
11433
|
+
path: ["visibility-stats"],
|
|
11434
|
+
usage: USAGE4,
|
|
11435
|
+
options: {
|
|
11436
|
+
since: stringOption(),
|
|
11437
|
+
until: stringOption(),
|
|
11438
|
+
"last-runs": stringOption(),
|
|
11439
|
+
"by-provider": { type: "boolean", default: false }
|
|
11440
|
+
},
|
|
11441
|
+
run: async (input) => {
|
|
11442
|
+
const project = requireProject(input, "visibility-stats", USAGE4);
|
|
11443
|
+
await showVisibilityStats(project, {
|
|
11444
|
+
since: getString(input.values, "since"),
|
|
11445
|
+
until: getString(input.values, "until"),
|
|
11446
|
+
lastRuns: parseIntegerOption(input, "last-runs", {
|
|
11447
|
+
command: "visibility-stats",
|
|
11448
|
+
usage: USAGE4,
|
|
11449
|
+
message: "--last-runs must be an integer"
|
|
11450
|
+
}),
|
|
11451
|
+
byProvider: getBoolean(input.values, "by-provider"),
|
|
11452
|
+
format: input.format
|
|
11453
|
+
});
|
|
11454
|
+
}
|
|
11455
|
+
}
|
|
11456
|
+
];
|
|
11457
|
+
|
|
11269
11458
|
// src/cli-commands/wordpress.ts
|
|
11270
11459
|
import fs11 from "fs";
|
|
11271
11460
|
|
|
@@ -12850,6 +13039,7 @@ var REGISTERED_CLI_COMMANDS = [
|
|
|
12850
13039
|
...GBP_CLI_COMMANDS,
|
|
12851
13040
|
...TRAFFIC_CLI_COMMANDS,
|
|
12852
13041
|
...INTELLIGENCE_CLI_COMMANDS,
|
|
13042
|
+
...VISIBILITY_STATS_CLI_COMMANDS,
|
|
12853
13043
|
...CONTENT_CLI_COMMANDS,
|
|
12854
13044
|
...AGENT_CLI_COMMANDS,
|
|
12855
13045
|
...DISCOVER_CLI_COMMANDS,
|
|
@@ -12861,7 +13051,7 @@ var REGISTERED_CLI_COMMANDS = [
|
|
|
12861
13051
|
|
|
12862
13052
|
// src/cli.ts
|
|
12863
13053
|
import { createRequire as createRequire2 } from "module";
|
|
12864
|
-
var
|
|
13054
|
+
var USAGE5 = `
|
|
12865
13055
|
cnry \u2014 AEO monitoring CLI ('canonry' also works)
|
|
12866
13056
|
|
|
12867
13057
|
Usage: cnry <command> [options]
|
|
@@ -12926,7 +13116,7 @@ function extractFormat(cmdArgs) {
|
|
|
12926
13116
|
}
|
|
12927
13117
|
async function runCli(args = process.argv.slice(2)) {
|
|
12928
13118
|
if (args.length === 0 || args[0] === "--help" || args[0] === "-h") {
|
|
12929
|
-
console.log(
|
|
13119
|
+
console.log(USAGE5);
|
|
12930
13120
|
return 0;
|
|
12931
13121
|
}
|
|
12932
13122
|
if (args.includes("--version") || args.includes("-v")) {
|
package/dist/index.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import {
|
|
2
2
|
createServer
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-SELXBOAP.js";
|
|
4
4
|
import {
|
|
5
5
|
loadConfig
|
|
6
|
-
} from "./chunk-
|
|
7
|
-
import "./chunk-
|
|
8
|
-
import "./chunk-
|
|
6
|
+
} from "./chunk-LLJPZKHG.js";
|
|
7
|
+
import "./chunk-DLBQU3VG.js";
|
|
8
|
+
import "./chunk-23HGQV22.js";
|
|
9
9
|
export {
|
|
10
10
|
createServer,
|
|
11
11
|
loadConfig
|
package/dist/mcp.js
CHANGED
|
@@ -3,10 +3,10 @@ import {
|
|
|
3
3
|
PACKAGE_VERSION,
|
|
4
4
|
canonryMcpTools,
|
|
5
5
|
createApiClient
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-LLJPZKHG.js";
|
|
7
7
|
import {
|
|
8
8
|
isReadOnlyKey
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-23HGQV22.js";
|
|
10
10
|
|
|
11
11
|
// src/mcp/cli.ts
|
|
12
12
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ainyc/canonry",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.86.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Agent-first open-source AEO operating platform - track how answer engines cite your domain",
|
|
6
6
|
"license": "FSL-1.1-ALv2",
|
|
@@ -63,26 +63,26 @@
|
|
|
63
63
|
"tsup": "^8.5.1",
|
|
64
64
|
"tsx": "^4.19.0",
|
|
65
65
|
"@ainyc/canonry-api-client": "0.0.0",
|
|
66
|
-
"@ainyc/canonry-db": "0.0.0",
|
|
67
66
|
"@ainyc/canonry-api-routes": "0.0.0",
|
|
68
|
-
"@ainyc/canonry-contracts": "0.0.0",
|
|
69
67
|
"@ainyc/canonry-config": "0.0.0",
|
|
68
|
+
"@ainyc/canonry-contracts": "0.0.0",
|
|
69
|
+
"@ainyc/canonry-db": "0.0.0",
|
|
70
70
|
"@ainyc/canonry-integration-bing": "0.0.0",
|
|
71
|
-
"@ainyc/canonry-integration-cloud-run": "0.0.0",
|
|
72
71
|
"@ainyc/canonry-integration-openai-ads": "0.0.0",
|
|
72
|
+
"@ainyc/canonry-integration-cloud-run": "0.0.0",
|
|
73
73
|
"@ainyc/canonry-integration-commoncrawl": "0.0.0",
|
|
74
74
|
"@ainyc/canonry-integration-google": "0.0.0",
|
|
75
75
|
"@ainyc/canonry-integration-google-business-profile": "0.0.0",
|
|
76
76
|
"@ainyc/canonry-integration-google-places": "0.0.0",
|
|
77
|
-
"@ainyc/canonry-intelligence": "0.0.0",
|
|
78
77
|
"@ainyc/canonry-integration-traffic": "0.0.0",
|
|
79
|
-
"@ainyc/canonry-
|
|
80
|
-
"@ainyc/canonry-provider-cdp": "0.0.0",
|
|
78
|
+
"@ainyc/canonry-intelligence": "0.0.0",
|
|
81
79
|
"@ainyc/canonry-integration-wordpress": "0.0.0",
|
|
82
|
-
"@ainyc/canonry-provider-
|
|
83
|
-
"@ainyc/canonry-provider-
|
|
80
|
+
"@ainyc/canonry-provider-cdp": "0.0.0",
|
|
81
|
+
"@ainyc/canonry-provider-claude": "0.0.0",
|
|
84
82
|
"@ainyc/canonry-provider-local": "0.0.0",
|
|
85
|
-
"@ainyc/canonry-provider-
|
|
83
|
+
"@ainyc/canonry-provider-gemini": "0.0.0",
|
|
84
|
+
"@ainyc/canonry-provider-perplexity": "0.0.0",
|
|
85
|
+
"@ainyc/canonry-provider-openai": "0.0.0"
|
|
86
86
|
},
|
|
87
87
|
"scripts": {
|
|
88
88
|
"build": "tsx scripts/copy-agent-assets.ts && tsup && tsx build-web.ts",
|