@canonry/canonry 4.172.0 → 4.172.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (31) hide show
  1. package/assets/agent-workspace/skills/aero/references/reporting.md +8 -4
  2. package/assets/agent-workspace/skills/canonry/references/aeo-analysis.md +1 -1
  3. package/assets/agent-workspace/skills/canonry/references/canonry-cli.md +4 -3
  4. package/assets/assets/{AuditHistoryPanel-DdZeCGyB.js → AuditHistoryPanel-DnqySUw3.js} +1 -1
  5. package/assets/assets/{BacklinksPage-C3cA1uZG.js → BacklinksPage-CbcHWD-G.js} +1 -1
  6. package/assets/assets/{HistoryPage-ILldZ0uo.js → HistoryPage-BYFSyxuB.js} +1 -1
  7. package/assets/assets/{MeasurementPropertyPage-DdGD-pSU.js → MeasurementPropertyPage-BBnXQPIv.js} +1 -1
  8. package/assets/assets/ProjectPage-Cq5bHpmk.js +9 -0
  9. package/assets/assets/{RunRow-BQACorl6.js → RunRow-lfyHktTf.js} +1 -1
  10. package/assets/assets/{RunsPage-BAt4nfFQ.js → RunsPage-ngnP0Y_D.js} +1 -1
  11. package/assets/assets/{SettingsPage-C8jJCoe8.js → SettingsPage-DEg74T20.js} +1 -1
  12. package/assets/assets/{SiteHealthSection-K8UY4Jnr.js → SiteHealthSection-C6ycXwbt.js} +3 -3
  13. package/assets/assets/{TrafficPage-GuuYfJor.js → TrafficPage-hrJ1IDqA.js} +1 -1
  14. package/assets/assets/{TrafficSourceDetailPage-BUpxbbyO.js → TrafficSourceDetailPage-fu7nPl3E.js} +1 -1
  15. package/assets/assets/{extract-error-message-DhnfPYL6.js → extract-error-message-dcdO9njP.js} +1 -1
  16. package/assets/assets/index-D1mXm81Z.css +1 -0
  17. package/assets/assets/{index-DgNO-ho5.js → index-DpQ_-QC_.js} +27 -27
  18. package/assets/assets/{react-sigma_core.esm.min-B_Td5ND2.js → react-sigma_core.esm.min-DZGxGBSe.js} +1 -1
  19. package/assets/index.html +2 -2
  20. package/dist/{chunk-HJ7W2LXI.js → chunk-EGGQSFQL.js} +4758 -4678
  21. package/dist/{chunk-O226BLC7.js → chunk-PXTSQ67Z.js} +712 -292
  22. package/dist/{chunk-5KGN224W.js → chunk-TI3SZAVI.js} +4 -4
  23. package/dist/{chunk-RR4KSDOD.js → chunk-U5JTZM66.js} +2 -2
  24. package/dist/{chunk-IIFDS3K2.js → chunk-YXDCVM5U.js} +8 -5
  25. package/dist/cli.js +72 -27
  26. package/dist/index.js +4 -4
  27. package/dist/{intelligence-service-KT6K4ODY.js → intelligence-service-H7756PBD.js} +2 -2
  28. package/dist/mcp.js +3 -3
  29. package/package.json +10 -10
  30. package/assets/assets/ProjectPage-BPbmNgA9.js +0 -9
  31. package/assets/assets/index-BsQGKWA6.css +0 -1
@@ -9,7 +9,7 @@ import {
9
9
  loadConfig,
10
10
  loadConfigRaw,
11
11
  saveConfigPatch
12
- } from "./chunk-IIFDS3K2.js";
12
+ } from "./chunk-YXDCVM5U.js";
13
13
  import {
14
14
  CC_CACHE_DIR,
15
15
  DUCKDB_SPEC,
@@ -145,7 +145,7 @@ import {
145
145
  siteCrawlSnapshots,
146
146
  toAlertView,
147
147
  usageCounters
148
- } from "./chunk-O226BLC7.js";
148
+ } from "./chunk-PXTSQ67Z.js";
149
149
  import {
150
150
  AGENT_MEMORY_VALUE_MAX_BYTES,
151
151
  AGENT_PROVIDER_IDS,
@@ -282,7 +282,7 @@ import {
282
282
  validationError,
283
283
  winnabilityClassLabel,
284
284
  withRetry
285
- } from "./chunk-HJ7W2LXI.js";
285
+ } from "./chunk-EGGQSFQL.js";
286
286
 
287
287
  // src/telemetry.ts
288
288
  import crypto from "crypto";
@@ -11829,7 +11829,7 @@ function readStoredGroundingSources(rawResponse) {
11829
11829
  return result;
11830
11830
  }
11831
11831
  async function backfillInsightsCommand(project, opts) {
11832
- const { IntelligenceService: IntelligenceService2 } = await import("./intelligence-service-KT6K4ODY.js");
11832
+ const { IntelligenceService: IntelligenceService2 } = await import("./intelligence-service-H7756PBD.js");
11833
11833
  const config = loadConfig();
11834
11834
  const db = createClient(config.database);
11835
11835
  migrate(db);
@@ -5,11 +5,11 @@ import {
5
5
  installSkills,
6
6
  loadConfigRaw,
7
7
  saveConfigPatch
8
- } from "./chunk-IIFDS3K2.js";
8
+ } from "./chunk-YXDCVM5U.js";
9
9
  import {
10
10
  SKILL_MANIFEST_FILENAME,
11
11
  SkillsClients
12
- } from "./chunk-HJ7W2LXI.js";
12
+ } from "./chunk-EGGQSFQL.js";
13
13
 
14
14
  // src/skills-autosync.ts
15
15
  import fs from "fs";
@@ -91,7 +91,7 @@ import {
91
91
  trafficConnectWordpressRequestSchema,
92
92
  trafficEventKindSchema,
93
93
  trafficSeriesGranularitySchema
94
- } from "./chunk-HJ7W2LXI.js";
94
+ } from "./chunk-EGGQSFQL.js";
95
95
 
96
96
  // src/config.ts
97
97
  import fs from "fs";
@@ -8274,7 +8274,8 @@ var ApiClient = class {
8274
8274
  lastRuns: opts.lastRuns,
8275
8275
  groupBy: opts.groupBy,
8276
8276
  month: opts.month,
8277
- shareOfVoice: opts.shareOfVoice ? "1" : void 0
8277
+ shareOfVoice: opts.shareOfVoice ? "1" : void 0,
8278
+ queryClass: opts.queryClass
8278
8279
  }
8279
8280
  })
8280
8281
  );
@@ -9999,7 +10000,7 @@ var canonryMcpTools = [
9999
10000
  defineTool({
10000
10001
  name: "canonry_visibility_stats",
10001
10002
  title: "Get aggregated mention/citation stats",
10002
- 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), `lastRuns`, or `month=YYYY-MM` (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). Set `shareOfVoice=true` for pooled project-vs-tracked-competitor brand-mention share across the same attributed snapshot set.',
10003
+ 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), `lastRuns`, or `month=YYYY-MM` (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). Set `shareOfVoice=true` for project-vs-tracked-competitor brand-mention share across the same attributed snapshot set \u2014 scoped to NON-BRAND queries by default, because a branded query names the project (it is mentioned on nearly all of them and a competitor cannot be), so a pooled figure reports brand recall as category placement. Pass `queryClass="branded"` for the recall figure; the response echoes which class it served.',
10003
10004
  access: "read",
10004
10005
  tier: "monitoring",
10005
10006
  inputSchema: z3.object({
@@ -10009,7 +10010,8 @@ var canonryMcpTools = [
10009
10010
  lastRuns: z3.number().int().positive().optional().describe("Aggregate only the most recent N answer-visibility runs. Mutually exclusive with since/until/month."),
10010
10011
  month: z3.string().optional().describe("Aggregate one calendar month (YYYY-MM), expanded to that month's inclusive UTC bounds. Mutually exclusive with since/until/lastRuns."),
10011
10012
  groupBy: z3.enum(["provider"]).optional().describe('Set to "provider" for a per-provider breakdown.'),
10012
- shareOfVoice: z3.boolean().optional().describe("Include pooled project-vs-tracked-competitor brand-mention share across the same window.")
10013
+ shareOfVoice: z3.boolean().optional().describe("Include project-vs-tracked-competitor brand-mention share across the same window (non-brand queries unless queryClass says otherwise)."),
10014
+ queryClass: z3.enum(["branded", "non-brand"]).optional().describe('Query class for shareOfVoice. Defaults to non-brand. There is no "all": branded and non-brand never share a denominator.')
10013
10015
  }),
10014
10016
  annotations: readAnnotations(),
10015
10017
  openApiOperations: ["GET /api/v1/projects/{name}/visibility-stats"],
@@ -10019,7 +10021,8 @@ var canonryMcpTools = [
10019
10021
  lastRuns: input.lastRuns,
10020
10022
  groupBy: input.groupBy,
10021
10023
  month: input.month,
10022
- shareOfVoice: input.shareOfVoice
10024
+ shareOfVoice: input.shareOfVoice,
10025
+ queryClass: input.queryClass
10023
10026
  })
10024
10027
  }),
10025
10028
  defineTool({
package/dist/cli.js CHANGED
@@ -26,11 +26,11 @@ import {
26
26
  showFirstRunNotice,
27
27
  trackCliCommandFinished,
28
28
  trackEvent
29
- } from "./chunk-5KGN224W.js";
29
+ } from "./chunk-TI3SZAVI.js";
30
30
  import {
31
31
  autoSyncSkills,
32
32
  formatAutoSyncNotice
33
- } from "./chunk-RR4KSDOD.js";
33
+ } from "./chunk-U5JTZM66.js";
34
34
  import {
35
35
  CliError,
36
36
  EXIT_SYSTEM_ERROR,
@@ -55,7 +55,7 @@ import {
55
55
  saveConfigPatch,
56
56
  systemError,
57
57
  usageError
58
- } from "./chunk-IIFDS3K2.js";
58
+ } from "./chunk-YXDCVM5U.js";
59
59
  import {
60
60
  CLOUDFLARE_WORKER_BINDINGS,
61
61
  CLOUDFLARE_WORKER_GENERATED_MARKER,
@@ -69,7 +69,7 @@ import {
69
69
  projects,
70
70
  queries,
71
71
  renderReportHtml
72
- } from "./chunk-O226BLC7.js";
72
+ } from "./chunk-PXTSQ67Z.js";
73
73
  import {
74
74
  AdsDeliverySnapshotStatuses,
75
75
  AdsHistoricalCampaignRollupStatuses,
@@ -137,7 +137,7 @@ import {
137
137
  providerQuotaPolicySchema,
138
138
  resolveProviderInput,
139
139
  winnabilityClassSchema
140
- } from "./chunk-HJ7W2LXI.js";
140
+ } from "./chunk-EGGQSFQL.js";
141
141
 
142
142
  // src/cli.ts
143
143
  import { pathToFileURL } from "url";
@@ -4019,7 +4019,7 @@ async function gaTraffic(project, opts) {
4019
4019
  `);
4020
4020
  console.log(` Total Sessions: ${result.totalSessions}`);
4021
4021
  console.log(` Organic Sessions: ${result.totalOrganicSessions}`);
4022
- console.log(` Total Users: ${result.totalUsers}`);
4022
+ console.log(` Total Users: ${result.totalUsers ?? "unavailable for this range"}`);
4023
4023
  if (result.aiSessionsDeduped > 0) {
4024
4024
  const share = result.totalSessions > 0 ? Math.round(result.aiSessionsDeduped / result.totalSessions * 100) : 0;
4025
4025
  console.log(` AI Sessions (deduped): ${result.aiSessionsDeduped} (${share}% of total)`);
@@ -4276,6 +4276,11 @@ async function gaCoverage(project, format) {
4276
4276
  );
4277
4277
  }
4278
4278
  }
4279
+ function windowLine(traffic) {
4280
+ if (!traffic.windowStart || !traffic.windowEnd) return null;
4281
+ const span = traffic.windowDays === null ? "" : ` (${traffic.windowDays} days)`;
4282
+ return ` Window: ${traffic.windowStart} to ${traffic.windowEnd}${span}`;
4283
+ }
4279
4284
  async function gaSocialReferralSummary(project, opts) {
4280
4285
  const client = getClient7();
4281
4286
  const traffic = await client.gaTraffic(project);
@@ -4287,12 +4292,18 @@ async function gaSocialReferralSummary(project, opts) {
4287
4292
  socialUsers: traffic.socialUsers,
4288
4293
  totalSessions: traffic.totalSessions,
4289
4294
  socialSharePct: traffic.socialSharePct,
4295
+ windowStart: traffic.windowStart,
4296
+ windowEnd: traffic.windowEnd,
4297
+ windowDays: traffic.windowDays,
4290
4298
  topSources: traffic.socialReferrals.slice(0, 5).map((r) => ({ source: r.source, sessions: r.sessions, channel: r.channelGroup })),
4291
4299
  trend
4292
4300
  }, null, 2));
4293
4301
  return;
4294
4302
  }
4295
4303
  console.log(`Social Traffic Summary for "${project}"
4304
+ `);
4305
+ const trendWindow = windowLine(traffic);
4306
+ if (trendWindow) console.log(`${trendWindow}
4296
4307
  `);
4297
4308
  console.log(` Sessions: ${traffic.socialSessions} (${traffic.socialSharePct}% of ${traffic.totalSessions} total)`);
4298
4309
  console.log(` Users: ${traffic.socialUsers}`);
@@ -4320,11 +4331,17 @@ async function gaSocialReferralSummary(project, opts) {
4320
4331
  socialUsers: traffic.socialUsers,
4321
4332
  totalSessions: traffic.totalSessions,
4322
4333
  socialSharePct: traffic.socialSharePct,
4334
+ windowStart: traffic.windowStart,
4335
+ windowEnd: traffic.windowEnd,
4336
+ windowDays: traffic.windowDays,
4323
4337
  topSources: traffic.socialReferrals.slice(0, 5).map((r) => ({ source: r.source, sessions: r.sessions, channel: r.channelGroup }))
4324
4338
  }, null, 2));
4325
4339
  return;
4326
4340
  }
4327
4341
  console.log(`Social Traffic Summary for "${project}"
4342
+ `);
4343
+ const socialWindow = windowLine(traffic);
4344
+ if (socialWindow) console.log(`${socialWindow}
4328
4345
  `);
4329
4346
  console.log(` Sessions: ${traffic.socialSessions} (${traffic.socialSharePct}% of ${traffic.totalSessions} total)`);
4330
4347
  console.log(` Users: ${traffic.socialUsers}`);
@@ -4382,6 +4399,9 @@ async function gaAttribution(project, opts) {
4382
4399
  aiReferrals: traffic.aiReferrals,
4383
4400
  aiReferralLandingPages: traffic.aiReferralLandingPages,
4384
4401
  socialReferrals: traffic.socialReferrals,
4402
+ windowStart: traffic.windowStart,
4403
+ windowEnd: traffic.windowEnd,
4404
+ windowDays: traffic.windowDays,
4385
4405
  trend
4386
4406
  }, null, 2));
4387
4407
  return;
@@ -4391,9 +4411,12 @@ async function gaAttribution(project, opts) {
4391
4411
  return;
4392
4412
  }
4393
4413
  console.log(`GA4 Attribution Overview for "${project}"
4414
+ `);
4415
+ const trendWindow = windowLine(traffic);
4416
+ if (trendWindow) console.log(`${trendWindow}
4394
4417
  `);
4395
4418
  console.log(` Total Sessions: ${traffic.totalSessions}`);
4396
- console.log(` Total Users: ${traffic.totalUsers}`);
4419
+ console.log(` Total Users: ${traffic.totalUsers ?? "unavailable for this range"}`);
4397
4420
  console.log();
4398
4421
  console.log(" CHANNEL BREAKDOWN 7d trend 30d trend");
4399
4422
  console.log(` Organic Search: ${String(traffic.channelBreakdown.organic.sessions).padEnd(6)} (${traffic.channelBreakdown.organic.sharePctDisplay.padStart(4)}) ${fmtTrend(trend.organic.trend7dPct).padEnd(12)} ${fmtTrend(trend.organic.trend30dPct)}`);
@@ -4415,12 +4438,9 @@ async function gaAttribution(project, opts) {
4415
4438
  const m = trend.socialBiggestMover;
4416
4439
  console.log(` Social Mover: ${m.source} (${m.changePct >= 0 ? "+" : ""}${m.changePct}%, ${m.sessionsPrev7d}\u2192${m.sessions7d} sessions/7d)`);
4417
4440
  }
4418
- if (traffic.periodStart && traffic.periodEnd) {
4419
- console.log(`
4420
- Period: ${traffic.periodStart} to ${traffic.periodEnd}`);
4421
- }
4422
4441
  if (traffic.lastSyncedAt) {
4423
- console.log(` Last synced: ${traffic.lastSyncedAt}`);
4442
+ console.log(`
4443
+ Last synced: ${traffic.lastSyncedAt}`);
4424
4444
  }
4425
4445
  return;
4426
4446
  }
@@ -4463,6 +4483,9 @@ async function gaAttribution(project, opts) {
4463
4483
  aiReferrals: traffic.aiReferrals,
4464
4484
  aiReferralLandingPages: traffic.aiReferralLandingPages,
4465
4485
  socialReferrals: traffic.socialReferrals,
4486
+ windowStart: traffic.windowStart,
4487
+ windowEnd: traffic.windowEnd,
4488
+ windowDays: traffic.windowDays,
4466
4489
  periodStart: traffic.periodStart,
4467
4490
  periodEnd: traffic.periodEnd
4468
4491
  }, null, 2));
@@ -4473,9 +4496,12 @@ async function gaAttribution(project, opts) {
4473
4496
  return;
4474
4497
  }
4475
4498
  console.log(`GA4 Attribution Overview for "${project}"
4499
+ `);
4500
+ const attributionWindow = windowLine(traffic);
4501
+ if (attributionWindow) console.log(`${attributionWindow}
4476
4502
  `);
4477
4503
  console.log(` Total Sessions: ${traffic.totalSessions}`);
4478
- console.log(` Total Users: ${traffic.totalUsers}`);
4504
+ console.log(` Total Users: ${traffic.totalUsers ?? "unavailable for this range"}`);
4479
4505
  console.log();
4480
4506
  console.log(" CHANNEL BREAKDOWN");
4481
4507
  console.log(` Organic Search: ${traffic.channelBreakdown.organic.sessions} sessions (${traffic.channelBreakdown.organic.sharePctDisplay})`);
@@ -4513,12 +4539,9 @@ async function gaAttribution(project, opts) {
4513
4539
  console.log(` ${ref.source.padEnd(25)} ${String(ref.sessions).padEnd(8)} sessions (${chanLabel})`);
4514
4540
  }
4515
4541
  }
4516
- if (traffic.periodStart && traffic.periodEnd) {
4517
- console.log(`
4518
- Period: ${traffic.periodStart} to ${traffic.periodEnd}`);
4519
- }
4520
4542
  if (traffic.lastSyncedAt) {
4521
- console.log(` Last synced: ${traffic.lastSyncedAt}`);
4543
+ console.log(`
4544
+ Last synced: ${traffic.lastSyncedAt}`);
4522
4545
  }
4523
4546
  }
4524
4547
 
@@ -13057,14 +13080,14 @@ async function showAllOverviews(opts) {
13057
13080
  console.log(`
13058
13081
  Overviews (${overviews.length} project${overviews.length === 1 ? "" : "s"}):
13059
13082
  `);
13060
- const cols = { project: 20, mention: 10, cited: 10, share: 18, queries: 10 };
13061
- console.log(` ${cell("Project", cols.project)}${cell("Mention", cols.mention)}${cell("Cited", cols.cited)}${cell("Share", cols.share)}${cell("Queries", cols.queries)}Latest run`);
13083
+ const cols = { project: 20, mention: 10, cited: 10, share: 42, queries: 10 };
13084
+ console.log(` ${cell("Project", cols.project)}${cell("Mention", cols.mention)}${cell("Cited", cols.cited)}${cell("Mention share \xB7 scope", cols.share)}${cell("Queries", cols.queries)}Latest run`);
13062
13085
  for (const ov of overviews) {
13063
13086
  const project = ov.project.displayName || ov.project.name;
13064
13087
  const queries2 = `${ov.queryCounts.citedQueries}/${ov.queryCounts.totalQueries}`;
13065
13088
  const latest = ov.latestRun.run?.finishedAt ?? ov.latestRun.run?.createdAt ?? "\u2014";
13066
13089
  console.log(
13067
- ` ${cell(project, cols.project)}${cell(ov.scores.mention.value, cols.mention)}${cell(ov.scores.visibility.value, cols.cited)}${cell(ov.scores.mentionShare.value, cols.share)}${cell(queries2, cols.queries)}${latest}`
13090
+ ` ${cell(project, cols.project)}${cell(ov.scores.mention.value, cols.mention)}${cell(ov.scores.visibility.value, cols.cited)}${cell(`${ov.scores.mentionShare.value} \xB7 ${ov.scores.mentionShare.scope} queries`, cols.share)}${cell(queries2, cols.queries)}${latest}`
13068
13091
  );
13069
13092
  }
13070
13093
  console.log();
@@ -16100,7 +16123,8 @@ async function showVisibilityStats(project, opts) {
16100
16123
  month: opts.month,
16101
16124
  lastRuns: opts.lastRuns,
16102
16125
  groupBy: opts.byProvider ? "provider" : void 0,
16103
- shareOfVoice: opts.shareOfVoice
16126
+ shareOfVoice: opts.shareOfVoice,
16127
+ queryClass: opts.queryClass
16104
16128
  });
16105
16129
  if (opts.format === "jsonl") {
16106
16130
  emitJsonl(data.queries.map((q) => ({ project: data.project, runCount: data.window.runCount, ...q })));
@@ -16126,6 +16150,9 @@ async function showVisibilityCompare(project, opts) {
16126
16150
  printVisibilityCompare(data);
16127
16151
  }
16128
16152
  function periodCell(p) {
16153
+ if (p.availability === "no-competitive-frame") {
16154
+ return `unavailable: no competitive frame (${p.numerator} observed)`;
16155
+ }
16129
16156
  if (p.point === null || p.ciLow === null || p.ciHigh === null) return "no data";
16130
16157
  const p1 = (v) => formatRatio(v);
16131
16158
  return `${p1(p.point)} [${p1(p.ciLow)}, ${p1(p.ciHigh)}]`;
@@ -16144,6 +16171,11 @@ function verdictCell(m) {
16144
16171
  return "model unknown";
16145
16172
  }
16146
16173
  }
16174
+ function metricQueryClassLabel(metric) {
16175
+ if (metric.queryClass === "non-brand") return "non-brand queries";
16176
+ if (metric.queryClass === "pooled") return "pooled queries; classification unavailable";
16177
+ return "all queries";
16178
+ }
16147
16179
  function printVisibilityCompare(data) {
16148
16180
  console.log(`AEO month over month: ${data.project} ${data.from.month} -> ${data.to.month}`);
16149
16181
  const b = data.basket;
@@ -16160,7 +16192,7 @@ function printVisibilityCompare(data) {
16160
16192
  }
16161
16193
  console.log("");
16162
16194
  const rows = data.metrics.map((m) => ({
16163
- label: `${m.label}${m.driftRobust ? " *" : ""}`,
16195
+ label: `${m.label} \xB7 ${metricQueryClassLabel(m)}${m.driftRobust ? " *" : ""}`,
16164
16196
  to: periodCell(m.to),
16165
16197
  from: periodCell(m.from),
16166
16198
  verdict: verdictCell(m)
@@ -16266,10 +16298,14 @@ function printVisibilityStats(data) {
16266
16298
  const sov = data.shareOfVoice;
16267
16299
  if (sov) {
16268
16300
  console.log("");
16269
- const pctStr = sov.percent === null ? "\u2014 (no competitors configured)" : `${sov.percent}%`;
16301
+ const pctStr = sov.percent !== null ? `${sov.percent}%` : sov.competitorCount === 0 ? "\u2014 (no competitors configured)" : sov.snapshotsWithAnswerText === 0 ? "\u2014 (no answer text in scope)" : "\u2014 (no brands mentioned in scope)";
16302
+ const scope = sov.queryClass === "pooled" ? "pooled queries \xB7 classification unavailable" : `${sov.queryClass} queries`;
16270
16303
  console.log(
16271
- `Share of voice: ${pctStr} (you ${sov.projectMentions} vs competitors ${sov.competitorMentions} brand mentions across ${sov.snapshotsWithAnswerText} answers)`
16304
+ `Share of voice (${scope}): ${pctStr} (you ${sov.projectMentions} vs competitors ${sov.competitorMentions} brand mentions across ${sov.snapshotsWithAnswerText} answers)`
16272
16305
  );
16306
+ if (sov.queryClass === "non-brand") {
16307
+ console.log(" branded queries excluded on purpose \u2014 re-run with --query-class branded for brand recall");
16308
+ }
16273
16309
  for (const c of sov.perCompetitor.slice(0, 8)) {
16274
16310
  console.log(` ${c.domain}: ${c.mentions}`);
16275
16311
  }
@@ -16277,7 +16313,14 @@ function printVisibilityStats(data) {
16277
16313
  }
16278
16314
 
16279
16315
  // src/cli-commands/visibility-stats.ts
16280
- var USAGE5 = "canonry visibility-stats <project> [--since <iso>] [--until <iso>] [--month <YYYY-MM>] [--last-runs <n>] [--by-provider] [--share-of-voice] [--format json|jsonl]";
16316
+ var USAGE5 = "canonry visibility-stats <project> [--since <iso>] [--until <iso>] [--month <YYYY-MM>] [--last-runs <n>] [--by-provider] [--share-of-voice] [--query-class branded|non-brand] [--format json|jsonl]";
16317
+ function parseQueryClass(value) {
16318
+ if (value === void 0 || value === "") return void 0;
16319
+ if (value !== "branded" && value !== "non-brand") {
16320
+ throw new Error(`--query-class must be "branded" or "non-brand" (got "${value}")`);
16321
+ }
16322
+ return value;
16323
+ }
16281
16324
  var COMPARE_USAGE = "canonry visibility-compare <project> --from <YYYY-MM> --to <YYYY-MM> [--format json]";
16282
16325
  var VISIBILITY_STATS_CLI_COMMANDS = [
16283
16326
  {
@@ -16289,7 +16332,8 @@ var VISIBILITY_STATS_CLI_COMMANDS = [
16289
16332
  month: stringOption(),
16290
16333
  "last-runs": stringOption(),
16291
16334
  "by-provider": { type: "boolean", default: false },
16292
- "share-of-voice": { type: "boolean", default: false }
16335
+ "share-of-voice": { type: "boolean", default: false },
16336
+ "query-class": stringOption()
16293
16337
  },
16294
16338
  run: async (input) => {
16295
16339
  const project = requireProject(input, "visibility-stats", USAGE5);
@@ -16304,6 +16348,7 @@ var VISIBILITY_STATS_CLI_COMMANDS = [
16304
16348
  }),
16305
16349
  byProvider: getBoolean(input.values, "by-provider"),
16306
16350
  shareOfVoice: getBoolean(input.values, "share-of-voice"),
16351
+ queryClass: parseQueryClass(getString(input.values, "query-class")),
16307
16352
  format: input.format
16308
16353
  });
16309
16354
  }
package/dist/index.js CHANGED
@@ -3,12 +3,12 @@ import {
3
3
  createGoogleMarketingCredentialStore,
4
4
  createGoogleMarketingRuntime,
5
5
  createServer
6
- } from "./chunk-5KGN224W.js";
6
+ } from "./chunk-TI3SZAVI.js";
7
7
  import {
8
8
  loadConfig
9
- } from "./chunk-IIFDS3K2.js";
10
- import "./chunk-O226BLC7.js";
11
- import "./chunk-HJ7W2LXI.js";
9
+ } from "./chunk-YXDCVM5U.js";
10
+ import "./chunk-PXTSQ67Z.js";
11
+ import "./chunk-EGGQSFQL.js";
12
12
  export {
13
13
  GoogleMarketingRuntimeError,
14
14
  createGoogleMarketingCredentialStore,
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  IntelligenceService
3
- } from "./chunk-O226BLC7.js";
4
- import "./chunk-HJ7W2LXI.js";
3
+ } from "./chunk-PXTSQ67Z.js";
4
+ import "./chunk-EGGQSFQL.js";
5
5
  export {
6
6
  IntelligenceService
7
7
  };
package/dist/mcp.js CHANGED
@@ -1,15 +1,15 @@
1
1
  import {
2
2
  autoSyncSkills
3
- } from "./chunk-RR4KSDOD.js";
3
+ } from "./chunk-U5JTZM66.js";
4
4
  import {
5
5
  CliError,
6
6
  PACKAGE_VERSION,
7
7
  canonryMcpTools,
8
8
  createApiClient
9
- } from "./chunk-IIFDS3K2.js";
9
+ } from "./chunk-YXDCVM5U.js";
10
10
  import {
11
11
  isReadOnlyKey
12
- } from "./chunk-HJ7W2LXI.js";
12
+ } from "./chunk-EGGQSFQL.js";
13
13
 
14
14
  // src/mcp/cli.ts
15
15
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@canonry/canonry",
3
- "version": "4.172.0",
3
+ "version": "4.172.2",
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",
@@ -72,29 +72,29 @@
72
72
  "tsx": "^4.19.0",
73
73
  "@ainyc/canonry-api-client": "0.0.0",
74
74
  "@ainyc/canonry-api-routes": "0.0.0",
75
+ "@ainyc/canonry-contracts": "0.0.0",
75
76
  "@ainyc/canonry-config": "0.0.0",
76
77
  "@ainyc/canonry-db": "0.0.0",
77
- "@ainyc/canonry-contracts": "0.0.0",
78
78
  "@ainyc/canonry-integration-bing": "0.0.0",
79
- "@ainyc/canonry-integration-openai-ads": "0.0.0",
80
79
  "@ainyc/canonry-integration-cloud-run": "0.0.0",
80
+ "@ainyc/canonry-integration-openai-ads": "0.0.0",
81
81
  "@ainyc/canonry-integration-cloudflare-queue": "0.0.0",
82
82
  "@ainyc/canonry-integration-commoncrawl": "0.0.0",
83
83
  "@ainyc/canonry-integration-cloudflare-worker": "0.0.0",
84
- "@ainyc/canonry-integration-google-ads": "0.0.0",
85
- "@ainyc/canonry-integration-google-business-profile": "0.0.0",
86
84
  "@ainyc/canonry-integration-google": "0.0.0",
85
+ "@ainyc/canonry-integration-google-ads": "0.0.0",
87
86
  "@ainyc/canonry-integration-google-places": "0.0.0",
87
+ "@ainyc/canonry-integration-google-business-profile": "0.0.0",
88
88
  "@ainyc/canonry-integration-google-tag-manager": "0.0.0",
89
- "@ainyc/canonry-integration-traffic": "0.0.0",
90
89
  "@ainyc/canonry-integration-wordpress": "0.0.0",
91
90
  "@ainyc/canonry-intelligence": "0.0.0",
92
- "@ainyc/canonry-provider-cdp": "0.0.0",
93
- "@ainyc/canonry-provider-gemini": "0.0.0",
91
+ "@ainyc/canonry-integration-traffic": "0.0.0",
94
92
  "@ainyc/canonry-provider-local": "0.0.0",
93
+ "@ainyc/canonry-provider-gemini": "0.0.0",
94
+ "@ainyc/canonry-provider-cdp": "0.0.0",
95
95
  "@ainyc/canonry-provider-openai": "0.0.0",
96
- "@ainyc/canonry-provider-perplexity": "0.0.0",
97
- "@ainyc/canonry-provider-claude": "0.0.0"
96
+ "@ainyc/canonry-provider-claude": "0.0.0",
97
+ "@ainyc/canonry-provider-perplexity": "0.0.0"
98
98
  },
99
99
  "scripts": {
100
100
  "build": "tsx scripts/copy-agent-assets.ts && tsup && tsx build-web.ts",