@ainyc/canonry 4.115.1 → 4.117.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.
Files changed (27) hide show
  1. package/README.md +0 -1
  2. package/assets/agent-workspace/skills/aero/references/reporting.md +10 -0
  3. package/assets/agent-workspace/skills/canonry/references/canonry-cli.md +6 -0
  4. package/assets/assets/{BacklinksPage-yUb8oJuq.js → BacklinksPage-Bkafm10m.js} +1 -1
  5. package/assets/assets/{ChartPrimitives-CdQM3YDG.js → ChartPrimitives-NV_GgqFn.js} +1 -1
  6. package/assets/assets/ProjectPage-0-NnRxys.js +7 -0
  7. package/assets/assets/{RunRow-BU_x7EcP.js → RunRow-df0d24S6.js} +1 -1
  8. package/assets/assets/{RunsPage-CFIBWaO7.js → RunsPage-CU6-4YTM.js} +1 -1
  9. package/assets/assets/{SettingsPage-PyMryUad.js → SettingsPage-BKw6B6cd.js} +1 -1
  10. package/assets/assets/{TrafficPage-471ypAdQ.js → TrafficPage-CzpiYHKj.js} +1 -1
  11. package/assets/assets/{TrafficSourceDetailPage-CI7TEQge.js → TrafficSourceDetailPage-CC5nuqM1.js} +1 -1
  12. package/assets/assets/{arrow-left-D2N9u-0i.js → arrow-left-CbQcW2pL.js} +1 -1
  13. package/assets/assets/{extract-error-message-CAdsqKp3.js → extract-error-message-CvqIZ-le.js} +1 -1
  14. package/assets/assets/index-LjcWHaNZ.js +210 -0
  15. package/assets/assets/{trash-2-UgQrN5Np.js → trash-2-3J2u0woR.js} +1 -1
  16. package/assets/index.html +1 -1
  17. package/dist/{chunk-Z3OGDQHB.js → chunk-FVVKNMZW.js} +514 -52
  18. package/dist/{chunk-6LOKMEL3.js → chunk-IAJ5TQ4S.js} +1438 -1234
  19. package/dist/{chunk-CW4JISBL.js → chunk-PJATAPZW.js} +37 -1
  20. package/dist/{chunk-B2SNXXAJ.js → chunk-ZZEA774R.js} +4 -4
  21. package/dist/cli.js +98 -5
  22. package/dist/index.js +4 -4
  23. package/dist/{intelligence-service-4AWB2V7U.js → intelligence-service-J7G4CMI5.js} +2 -2
  24. package/dist/mcp.js +2 -2
  25. package/package.json +6 -6
  26. package/assets/assets/ProjectPage-CHj9fvTs.js +0 -7
  27. package/assets/assets/index-CoL5HENE.js +0 -210
@@ -25,7 +25,7 @@ import {
25
25
  trafficConnectVercelRequestSchema,
26
26
  trafficConnectWordpressRequestSchema,
27
27
  trafficEventKindSchema
28
- } from "./chunk-6LOKMEL3.js";
28
+ } from "./chunk-IAJ5TQ4S.js";
29
29
 
30
30
  // src/config.ts
31
31
  import fs from "fs";
@@ -1578,6 +1578,18 @@ var getApiV1ProjectsByNameVisibilityStats = (options) => {
1578
1578
  ...options
1579
1579
  });
1580
1580
  };
1581
+ var getApiV1ProjectsByNameVisibilityCompare = (options) => {
1582
+ return (options.client ?? client).get({
1583
+ security: [
1584
+ {
1585
+ scheme: "bearer",
1586
+ type: "http"
1587
+ }
1588
+ ],
1589
+ url: "/api/v1/projects/{name}/visibility-compare",
1590
+ ...options
1591
+ });
1592
+ };
1581
1593
  var getApiV1ProjectsByNameSnapshotsDiff = (options) => {
1582
1594
  return (options.client ?? client).get({
1583
1595
  security: [
@@ -5171,6 +5183,15 @@ var ApiClient = class {
5171
5183
  })
5172
5184
  );
5173
5185
  }
5186
+ async getVisibilityCompare(project, from, to) {
5187
+ return this.invoke(
5188
+ () => getApiV1ProjectsByNameVisibilityCompare({
5189
+ client: this.heyClient,
5190
+ path: { name: project },
5191
+ query: { from, to }
5192
+ })
5193
+ );
5194
+ }
5174
5195
  // ── Backlinks — workspace-level ────────────────────────────────────────
5175
5196
  async backlinksStatus() {
5176
5197
  return this.invoke(() => getApiV1BacklinksStatus({ client: this.heyClient }));
@@ -5915,6 +5936,21 @@ var canonryMcpTools = [
5915
5936
  shareOfVoice: input.shareOfVoice
5916
5937
  })
5917
5938
  }),
5939
+ defineTool({
5940
+ name: "canonry_visibility_compare",
5941
+ title: "Compare AEO visibility month over month",
5942
+ description: "Statistically honest month-over-month AEO comparison in ONE call \u2014 use this instead of hand-computing deltas from two visibility-stats calls. Share of voice (`mention-share-of-voice`, `driftRobust: true`) is less exposed to broad model-wide naming propensity than absolute rates, but it never overrides model continuity. The response restricts to common query/provider pairs, then includes only providers with exactly one known, identical configured model id in both months. `continuity` surfaces every provider, its model evidence, and whether it was excluded for a changed, mixed mid-month, or unknown model. When no provider remains, metrics return `model-discontinuous` or `model-unknown`, never a directional call. A silent upstream version bump under an unchanged configured id remains undetectable. `from` must be a month strictly before `to`.",
5943
+ access: "read",
5944
+ tier: "monitoring",
5945
+ inputSchema: z2.object({
5946
+ project: projectNameSchema,
5947
+ from: z2.string().describe('Earlier calendar month (YYYY-MM), the baseline. Must be strictly before "to".'),
5948
+ to: z2.string().describe('Later calendar month (YYYY-MM), compared against "from".')
5949
+ }),
5950
+ annotations: readAnnotations(),
5951
+ openApiOperations: ["GET /api/v1/projects/{name}/visibility-compare"],
5952
+ handler: (client2, input) => client2.getVisibilityCompare(input.project, input.from, input.to)
5953
+ }),
5918
5954
  defineTool({
5919
5955
  name: "canonry_content_targets",
5920
5956
  title: "Get content targets",
@@ -10,7 +10,7 @@ import {
10
10
  loadConfig,
11
11
  loadConfigRaw,
12
12
  saveConfigPatch
13
- } from "./chunk-CW4JISBL.js";
13
+ } from "./chunk-PJATAPZW.js";
14
14
  import {
15
15
  CC_CACHE_DIR,
16
16
  DUCKDB_SPEC,
@@ -115,7 +115,7 @@ import {
115
115
  siteAuditPages,
116
116
  siteAuditSnapshots,
117
117
  usageCounters
118
- } from "./chunk-Z3OGDQHB.js";
118
+ } from "./chunk-FVVKNMZW.js";
119
119
  import {
120
120
  AGENT_MEMORY_VALUE_MAX_BYTES,
121
121
  AGENT_PROVIDER_IDS,
@@ -178,7 +178,7 @@ import {
178
178
  validationError,
179
179
  winnabilityClassLabel,
180
180
  withRetry
181
- } from "./chunk-6LOKMEL3.js";
181
+ } from "./chunk-IAJ5TQ4S.js";
182
182
 
183
183
  // src/telemetry.ts
184
184
  import crypto from "crypto";
@@ -6515,7 +6515,7 @@ function readStoredGroundingSources(rawResponse) {
6515
6515
  return result;
6516
6516
  }
6517
6517
  async function backfillInsightsCommand(project, opts) {
6518
- const { IntelligenceService: IntelligenceService2 } = await import("./intelligence-service-4AWB2V7U.js");
6518
+ const { IntelligenceService: IntelligenceService2 } = await import("./intelligence-service-J7G4CMI5.js");
6519
6519
  const config = loadConfig();
6520
6520
  const db = createClient(config.database);
6521
6521
  migrate(db);
package/dist/cli.js CHANGED
@@ -29,7 +29,7 @@ import {
29
29
  setTelemetrySource,
30
30
  showFirstRunNotice,
31
31
  trackEvent
32
- } from "./chunk-B2SNXXAJ.js";
32
+ } from "./chunk-ZZEA774R.js";
33
33
  import {
34
34
  CliError,
35
35
  EXIT_SYSTEM_ERROR,
@@ -46,7 +46,7 @@ import {
46
46
  saveConfig,
47
47
  saveConfigPatch,
48
48
  usageError
49
- } from "./chunk-CW4JISBL.js";
49
+ } from "./chunk-PJATAPZW.js";
50
50
  import {
51
51
  apiKeys,
52
52
  createClient,
@@ -54,7 +54,7 @@ import {
54
54
  projects,
55
55
  queries,
56
56
  renderReportHtml
57
- } from "./chunk-Z3OGDQHB.js";
57
+ } from "./chunk-FVVKNMZW.js";
58
58
  import {
59
59
  BacklinkSources,
60
60
  CcReleaseSyncStatuses,
@@ -80,7 +80,7 @@ import {
80
80
  providerQuotaPolicySchema,
81
81
  resolveProviderInput,
82
82
  winnabilityClassSchema
83
- } from "./chunk-6LOKMEL3.js";
83
+ } from "./chunk-IAJ5TQ4S.js";
84
84
 
85
85
  // src/cli.ts
86
86
  import { pathToFileURL } from "url";
@@ -4698,7 +4698,8 @@ function formatEventLine(event) {
4698
4698
  event.evidenceType,
4699
4699
  event.sourceDomain,
4700
4700
  event.landingPathNormalized,
4701
- `${event.hits} hits`
4701
+ `${event.hits} hits`,
4702
+ `(paid ${event.paidHits} \xB7 organic ${event.organicHits} \xB7 unclassified ${event.unknownHits})`
4702
4703
  ].join(" ");
4703
4704
  }
4704
4705
  }
@@ -4743,6 +4744,9 @@ async function trafficEvents(project, opts) {
4743
4744
  console.log(` Crawler hits total (window): ${result.totals.crawlerHits}`);
4744
4745
  console.log(` AI user-fetch hits (window): ${result.totals.aiUserFetchHits}`);
4745
4746
  console.log(` AI referral sessions (window): ${result.totals.aiReferralHits}`);
4747
+ console.log(` paid: ${result.totals.aiReferralPaidHits}`);
4748
+ console.log(` organic: ${result.totals.aiReferralOrganicHits}`);
4749
+ console.log(` unclassified: ${result.totals.aiReferralUnknownHits} (ingested before paid/organic classification)`);
4746
4750
  console.log("");
4747
4751
  if (result.events.length === 0) {
4748
4752
  console.log("No events in this window.");
@@ -11837,6 +11841,78 @@ async function showVisibilityStats(project, opts) {
11837
11841
  function pct3(rate) {
11838
11842
  return rate === null ? "\u2014" : formatRatio(rate);
11839
11843
  }
11844
+ async function showVisibilityCompare(project, opts) {
11845
+ if (!opts.from || !opts.to) throw new Error("visibility-compare requires --from <YYYY-MM> and --to <YYYY-MM>");
11846
+ const client = createApiClient();
11847
+ const data = await client.getVisibilityCompare(project, opts.from, opts.to);
11848
+ if (isMachineFormat(opts.format)) {
11849
+ console.log(JSON.stringify(data, null, 2));
11850
+ return;
11851
+ }
11852
+ printVisibilityCompare(data);
11853
+ }
11854
+ function periodCell(p) {
11855
+ if (p.point === null || p.ciLow === null || p.ciHigh === null) return "no data";
11856
+ const p1 = (v) => formatRatio(v);
11857
+ return `${p1(p.point)} [${p1(p.ciLow)}, ${p1(p.ciHigh)}]`;
11858
+ }
11859
+ function verdictCell(m) {
11860
+ switch (m.verdict) {
11861
+ case "within-noise":
11862
+ return "within noise";
11863
+ case "insufficient-data":
11864
+ return "no data";
11865
+ case "moved":
11866
+ return `moved ${m.direction === "down" ? "down" : m.direction === "up" ? "up" : ""}`.trim();
11867
+ case "model-discontinuous":
11868
+ return "model discontinuity";
11869
+ case "model-unknown":
11870
+ return "model unknown";
11871
+ }
11872
+ }
11873
+ function printVisibilityCompare(data) {
11874
+ console.log(`AEO month over month: ${data.project} ${data.from.month} -> ${data.to.month}`);
11875
+ const b = data.basket;
11876
+ const excl = [];
11877
+ if (b.excludedFromOnly > 0) excl.push(`${b.excludedFromOnly} only in ${data.from.month}`);
11878
+ if (b.excludedToOnly > 0) excl.push(`${b.excludedToOnly} only in ${data.to.month}`);
11879
+ if (b.excludedProviders.length > 0) excl.push(`engines dropped: ${b.excludedProviders.join(", ")}`);
11880
+ console.log(`Basket: ${b.queryCount} quer${b.queryCount === 1 ? "y" : "ies"}, ${b.providers.length} engine(s)${excl.length ? ` (excluded: ${excl.join("; ")})` : ""}`);
11881
+ const sweeps = `Sweeps: ${data.from.month} ${data.from.runCount}, ${data.to.month} ${data.to.runCount}`;
11882
+ const low = data.from.lowRunCount || data.to.lowRunCount;
11883
+ console.log(low ? `${sweeps} (below the 5-sweep floor \u2014 intervals are wide, a "moved" verdict is unlikely to be reachable)` : sweeps);
11884
+ if (data.continuity.status !== "comparable") {
11885
+ console.log(`Continuity: ${data.continuity.status.replace("-", " ")} \u2014 no directional call is made.`);
11886
+ }
11887
+ console.log("");
11888
+ const rows = data.metrics.map((m) => ({
11889
+ label: `${m.label}${m.driftRobust ? " *" : ""}`,
11890
+ to: periodCell(m.to),
11891
+ from: periodCell(m.from),
11892
+ verdict: verdictCell(m)
11893
+ }));
11894
+ rows.push({
11895
+ label: "Queries named (count)",
11896
+ to: `${data.queriesMentioned.to.count} of ${data.queriesMentioned.to.of}`,
11897
+ from: `${data.queriesMentioned.from.count} of ${data.queriesMentioned.from.of}`,
11898
+ verdict: ""
11899
+ });
11900
+ const w = (sel, head) => Math.max(head.length, ...rows.map((r) => sel(r).length));
11901
+ const lw = w((r) => r.label, "Metric");
11902
+ const tw = w((r) => r.to, data.to.month);
11903
+ const fw = w((r) => r.from, data.from.month);
11904
+ console.log(` ${"Metric".padEnd(lw)} ${data.to.month.padEnd(tw)} ${data.from.month.padEnd(fw)} Verdict`);
11905
+ for (const r of rows) {
11906
+ console.log(` ${r.label.padEnd(lw)} ${r.to.padEnd(tw)} ${r.from.padEnd(fw)} ${r.verdict}`);
11907
+ }
11908
+ console.log("");
11909
+ console.log(" * share of voice is less exposed to broad model-wide naming propensity; model continuity is still required.");
11910
+ for (const provider of data.continuity.providers) {
11911
+ if (provider.status !== "included") {
11912
+ console.log(` Excluded for model continuity: ${provider.provider} (${provider.fromModels.join("/") || "?"} -> ${provider.toModels.join("/") || "?"}; ${provider.status.replace("-", " ")})`);
11913
+ }
11914
+ }
11915
+ }
11840
11916
  function citedCell(c) {
11841
11917
  return `${c.cited}/${c.total}`;
11842
11918
  }
@@ -11928,6 +12004,7 @@ function printVisibilityStats(data) {
11928
12004
 
11929
12005
  // src/cli-commands/visibility-stats.ts
11930
12006
  var USAGE4 = "canonry visibility-stats <project> [--since <iso>] [--until <iso>] [--month <YYYY-MM>] [--last-runs <n>] [--by-provider] [--share-of-voice] [--format json|jsonl]";
12007
+ var COMPARE_USAGE = "canonry visibility-compare <project> --from <YYYY-MM> --to <YYYY-MM> [--format json]";
11931
12008
  var VISIBILITY_STATS_CLI_COMMANDS = [
11932
12009
  {
11933
12010
  path: ["visibility-stats"],
@@ -11956,6 +12033,22 @@ var VISIBILITY_STATS_CLI_COMMANDS = [
11956
12033
  format: input.format
11957
12034
  });
11958
12035
  }
12036
+ },
12037
+ {
12038
+ path: ["visibility-compare"],
12039
+ usage: COMPARE_USAGE,
12040
+ options: {
12041
+ from: stringOption(),
12042
+ to: stringOption()
12043
+ },
12044
+ run: async (input) => {
12045
+ const project = requireProject(input, "visibility-compare", COMPARE_USAGE);
12046
+ await showVisibilityCompare(project, {
12047
+ from: getString(input.values, "from"),
12048
+ to: getString(input.values, "to"),
12049
+ format: input.format
12050
+ });
12051
+ }
11959
12052
  }
11960
12053
  ];
11961
12054
 
package/dist/index.js CHANGED
@@ -1,11 +1,11 @@
1
1
  import {
2
2
  createServer
3
- } from "./chunk-B2SNXXAJ.js";
3
+ } from "./chunk-ZZEA774R.js";
4
4
  import {
5
5
  loadConfig
6
- } from "./chunk-CW4JISBL.js";
7
- import "./chunk-Z3OGDQHB.js";
8
- import "./chunk-6LOKMEL3.js";
6
+ } from "./chunk-PJATAPZW.js";
7
+ import "./chunk-FVVKNMZW.js";
8
+ import "./chunk-IAJ5TQ4S.js";
9
9
  export {
10
10
  createServer,
11
11
  loadConfig
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  IntelligenceService
3
- } from "./chunk-Z3OGDQHB.js";
4
- import "./chunk-6LOKMEL3.js";
3
+ } from "./chunk-FVVKNMZW.js";
4
+ import "./chunk-IAJ5TQ4S.js";
5
5
  export {
6
6
  IntelligenceService
7
7
  };
package/dist/mcp.js CHANGED
@@ -3,10 +3,10 @@ import {
3
3
  PACKAGE_VERSION,
4
4
  canonryMcpTools,
5
5
  createApiClient
6
- } from "./chunk-CW4JISBL.js";
6
+ } from "./chunk-PJATAPZW.js";
7
7
  import {
8
8
  isReadOnlyKey
9
- } from "./chunk-6LOKMEL3.js";
9
+ } from "./chunk-IAJ5TQ4S.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.115.1",
3
+ "version": "4.117.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",
@@ -66,22 +66,22 @@
66
66
  "tsup": "^8.5.1",
67
67
  "tsx": "^4.19.0",
68
68
  "@ainyc/canonry-api-client": "0.0.0",
69
+ "@ainyc/canonry-api-routes": "0.0.0",
69
70
  "@ainyc/canonry-config": "0.0.0",
70
71
  "@ainyc/canonry-contracts": "0.0.0",
71
- "@ainyc/canonry-api-routes": "0.0.0",
72
72
  "@ainyc/canonry-db": "0.0.0",
73
73
  "@ainyc/canonry-integration-bing": "0.0.0",
74
- "@ainyc/canonry-integration-cloud-run": "0.0.0",
74
+ "@ainyc/canonry-integration-openai-ads": "0.0.0",
75
75
  "@ainyc/canonry-integration-commoncrawl": "0.0.0",
76
+ "@ainyc/canonry-integration-cloud-run": "0.0.0",
76
77
  "@ainyc/canonry-integration-google": "0.0.0",
77
- "@ainyc/canonry-integration-openai-ads": "0.0.0",
78
78
  "@ainyc/canonry-integration-google-business-profile": "0.0.0",
79
79
  "@ainyc/canonry-integration-google-places": "0.0.0",
80
80
  "@ainyc/canonry-integration-traffic": "0.0.0",
81
+ "@ainyc/canonry-integration-wordpress": "0.0.0",
82
+ "@ainyc/canonry-provider-cdp": "0.0.0",
81
83
  "@ainyc/canonry-intelligence": "0.0.0",
82
84
  "@ainyc/canonry-provider-claude": "0.0.0",
83
- "@ainyc/canonry-provider-cdp": "0.0.0",
84
- "@ainyc/canonry-integration-wordpress": "0.0.0",
85
85
  "@ainyc/canonry-provider-gemini": "0.0.0",
86
86
  "@ainyc/canonry-provider-openai": "0.0.0",
87
87
  "@ainyc/canonry-provider-perplexity": "0.0.0",