@canonry/canonry 5.20.4 → 5.22.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 (32) hide show
  1. package/assets/agent-workspace/skills/aero/references/portfolio-analysis.md +1 -1
  2. package/assets/agent-workspace/skills/aero/references/reporting.md +9 -4
  3. package/assets/agent-workspace/skills/canonry/references/canonry-cli.md +4 -1
  4. package/assets/assets/{AuditHistoryPanel-BSh3Oezj.js → AuditHistoryPanel-teTDC-4-.js} +1 -1
  5. package/assets/assets/{BacklinksPage-DQ59dhCx.js → BacklinksPage-Bqm7bido.js} +1 -1
  6. package/assets/assets/{HistoryPage-BBvgid3o.js → HistoryPage-IcqwPBmt.js} +1 -1
  7. package/assets/assets/{MeasurementPropertyPage-Dmb18JbT.js → MeasurementPropertyPage-BLpptT3_.js} +1 -1
  8. package/assets/assets/{ProjectPage-CPg0q2Dy.js → ProjectPage-nn2Y9H-m.js} +1 -1
  9. package/assets/assets/{RunRow-BK8sZCID.js → RunRow-S_SCHr0o.js} +1 -1
  10. package/assets/assets/{RunsPage-CIcVBTdP.js → RunsPage-DFiif626.js} +1 -1
  11. package/assets/assets/{SettingsPage-Bc3aR-gz.js → SettingsPage-CitZ6FAS.js} +1 -1
  12. package/assets/assets/{SiteHealthSection-FF14aIXT.js → SiteHealthSection-C2dsyNGY.js} +3 -3
  13. package/assets/assets/{TrafficPage-C_qoeGDl.js → TrafficPage-lY8na5Pg.js} +1 -1
  14. package/assets/assets/{TrafficSourceDetailPage-B3i_B2MI.js → TrafficSourceDetailPage-BTykoVGT.js} +1 -1
  15. package/assets/assets/{extract-error-message-BisUn6nN.js → extract-error-message-r0Gpc7mv.js} +1 -1
  16. package/assets/assets/{index-Dht7JNX5.js → index-DwlO8KfE.js} +21 -21
  17. package/assets/assets/{react-sigma_core.esm.min-tWhS09SS.js → react-sigma_core.esm.min-DDrDxbO1.js} +1 -1
  18. package/assets/assets/{v2-overview-adapter-CAoeWKQJ.js → v2-overview-adapter-OsQiglXU.js} +1 -1
  19. package/assets/index.html +1 -1
  20. package/dist/{chunk-TWLJRAWA.js → chunk-3LCR6WU6.js} +2 -2
  21. package/dist/{chunk-JJPZ4OQ2.js → chunk-DDL2XSNM.js} +8 -4
  22. package/dist/{chunk-PXVJ3P5G.js → chunk-GLLY2GEV.js} +8 -5
  23. package/dist/{chunk-NSKFW3NF.js → chunk-P5VXVFQW.js} +1095 -457
  24. package/dist/{chunk-TOSPZ7I5.js → chunk-S5OSY3PI.js} +78 -5
  25. package/dist/{chunk-P73YBGZP.js → chunk-XFHXKLNT.js} +23 -12
  26. package/dist/{chunk-CVUR3O5G.js → chunk-YTSXQUJ3.js} +3 -3
  27. package/dist/cli.js +76 -16
  28. package/dist/{demo-server-FH2K6TCD.js → demo-server-HULNEORN.js} +4 -4
  29. package/dist/index.js +6 -6
  30. package/dist/{intelligence-service-QHSR2H7F.js → intelligence-service-CXNBKRHV.js} +2 -2
  31. package/dist/mcp.js +4 -4
  32. package/package.json +12 -12
@@ -13572,7 +13572,7 @@ var visibilityCompareVerdictSchema = z41.enum([
13572
13572
  var visibilityCompareDirectionSchema = z41.enum(["up", "down", "flat"]);
13573
13573
  var visibilityCompareMetricPeriodSchema = z41.object({
13574
13574
  /** Why this period can or cannot produce a proportion. Raw numerator counts remain visible when the frame is missing. */
13575
- availability: z41.enum(["available", "no-observations", "no-competitive-frame"]),
13575
+ availability: z41.enum(["available", "no-observations", "no-competitive-frame", "classification-unavailable"]),
13576
13576
  /** The proportion in `[0,1]`, rounded to 4 dp; `null` when `denominator === 0` (undefined over no data). */
13577
13577
  point: z41.number().nullable(),
13578
13578
  /** Wilson 95% lower bound `[0,1]`; `null` when `denominator === 0`. */
@@ -13582,14 +13582,34 @@ var visibilityCompareMetricPeriodSchema = z41.object({
13582
13582
  /** Successes (mentions / citations / project-brand mentions), preserved even when the competitive frame is unavailable. */
13583
13583
  numerator: z41.number().int(),
13584
13584
  /** Sample size the proportion is over (checked snapshots / total / project+competitor brand mentions). */
13585
- denominator: z41.number().int()
13585
+ denominator: z41.number().int(),
13586
+ /**
13587
+ * Observations missing this metric's own signal, excluded from its
13588
+ * denominator: an unknown mention for a class mention rate, incomplete
13589
+ * source capture for a class cited rate, and, on frames that record capture
13590
+ * completeness (Advanced), for the pooled cited rate and cited share of voice.
13591
+ */
13592
+ excludedUnknown: z41.number().int().nonnegative().optional()
13586
13593
  });
13587
13594
  var visibilityCompareMetricKeySchema = z41.enum([
13588
13595
  "mention-share-of-voice",
13589
13596
  "cited-share-of-voice",
13590
13597
  "mention-rate",
13591
- "cited-rate"
13598
+ "cited-rate",
13599
+ "mention-rate-branded",
13600
+ "cited-rate-branded",
13601
+ "mention-rate-non-brand",
13602
+ "cited-rate-non-brand"
13592
13603
  ]);
13604
+ var VISIBILITY_COMPARE_CLASS_METRIC_KEYS = [
13605
+ "mention-rate-branded",
13606
+ "cited-rate-branded",
13607
+ "mention-rate-non-brand",
13608
+ "cited-rate-non-brand"
13609
+ ];
13610
+ function isVisibilityCompareClassMetric(key) {
13611
+ return VISIBILITY_COMPARE_CLASS_METRIC_KEYS.includes(key);
13612
+ }
13593
13613
  var visibilityCompareMetricSchema = z41.object({
13594
13614
  key: visibilityCompareMetricKeySchema,
13595
13615
  /** Human label ("Named share of voice", "Cited rate", …). */
@@ -13598,7 +13618,7 @@ var visibilityCompareMetricSchema = z41.object({
13598
13618
  * Query class behind this metric. `all` is an intentional all-query rate;
13599
13619
  * `pooled` means no usable project identity existed for the requested split.
13600
13620
  */
13601
- queryClass: z41.enum(["all", "non-brand", "pooled"]),
13621
+ queryClass: z41.enum(["all", "branded", "non-brand", "pooled"]),
13602
13622
  /**
13603
13623
  * `true` for share of voice, which is less exposed to broad model-wide naming
13604
13624
  * propensity than an absolute rate. It does not bypass model continuity: no
@@ -13681,12 +13701,33 @@ var visibilityCompareQueriesMentionedSchema = z41.object({
13681
13701
  from: z41.object({ count: z41.number().int(), of: z41.number().int() }),
13682
13702
  to: z41.object({ count: z41.number().int(), of: z41.number().int() })
13683
13703
  });
13704
+ var visibilityCompareSelectionSchema = z41.object({
13705
+ scope: z41.enum(["project", "group", "market", "property"]).optional(),
13706
+ scopeKey: z41.string().min(1).optional(),
13707
+ marketKey: z41.string().min(1).optional(),
13708
+ provider: z41.string().min(1).optional(),
13709
+ location: z41.string().min(1).optional()
13710
+ });
13711
+ var visibilityCompareClassComparisonSchema = z41.object({
13712
+ from: visibilityComparePeriodWindowSchema,
13713
+ to: visibilityComparePeriodWindowSchema,
13714
+ basket: visibilityCompareBasketSchema,
13715
+ continuity: visibilityCompareContinuitySchema,
13716
+ modelChanges: z41.array(visibilityCompareModelChangeSchema)
13717
+ });
13684
13718
  var visibilityCompareDtoSchema = z41.object({
13685
13719
  project: z41.string(),
13720
+ selection: visibilityCompareSelectionSchema.optional(),
13721
+ /** Frozen Advanced cohort used by the additive class metrics; legacy project metrics retain their original frame. */
13722
+ classComparison: visibilityCompareClassComparisonSchema.optional(),
13686
13723
  from: visibilityComparePeriodWindowSchema,
13687
13724
  to: visibilityComparePeriodWindowSchema,
13688
13725
  basket: visibilityCompareBasketSchema,
13689
- /** Ordered: mention SoV (primary), cited SoV, mention rate (level), cited rate. */
13726
+ /**
13727
+ * Ordered: mention SoV (primary), cited SoV, mention rate (level), cited rate,
13728
+ * then the class rates (`mention-rate-branded`, `cited-rate-branded`,
13729
+ * `mention-rate-non-brand`, `cited-rate-non-brand`). Read metrics by `key`.
13730
+ */
13690
13731
  metrics: z41.array(visibilityCompareMetricSchema),
13691
13732
  queriesMentioned: visibilityCompareQueriesMentionedSchema,
13692
13733
  byProvider: z41.array(visibilityCompareProviderRowSchema),
@@ -15010,12 +15051,27 @@ var checkCategorySchema = z50.enum([
15010
15051
  "agent"
15011
15052
  ]);
15012
15053
  var CheckCategories = checkCategorySchema.enum;
15054
+ var checkNotificationPolicySchema = z50.enum(["health", "silent"]);
15055
+ var CheckNotificationPolicies = checkNotificationPolicySchema.enum;
15056
+ var reportMonthSchema = z50.string().regex(/^[1-9]\d{3}-(0[1-9]|1[0-2])$/, "Expected YYYY-MM");
15057
+ function reportMonthsForDoctor(reportMonth, now = /* @__PURE__ */ new Date()) {
15058
+ if (reportMonth !== void 0) return [reportMonthSchema.parse(reportMonth)];
15059
+ const current = now.toISOString().slice(0, 7);
15060
+ if (now.getUTCDate() > 3) return [current];
15061
+ const previous = new Date(Date.parse(calendarMonthBounds(current).since) - 1).toISOString().slice(0, 7);
15062
+ return [previous, current];
15063
+ }
15064
+ function gradedReportMonths(months, now = /* @__PURE__ */ new Date()) {
15065
+ const current = now.toISOString().slice(0, 7);
15066
+ return new Set(months.length > 1 ? months.filter((month) => month !== current) : months);
15067
+ }
15013
15068
  var checkResultSchema = z50.object({
15014
15069
  id: z50.string(),
15015
15070
  category: checkCategorySchema,
15016
15071
  scope: checkScopeSchema,
15017
15072
  title: z50.string(),
15018
15073
  status: checkStatusSchema,
15074
+ notificationPolicy: checkNotificationPolicySchema.optional().describe("Health checks page by default. Silent report advisories remain visible but never affect health alert state."),
15019
15075
  code: z50.string().describe('Stable machine-readable code (e.g. "google.token.refresh-failed"). Use this for filtering and remediation logic.'),
15020
15076
  summary: z50.string(),
15021
15077
  remediation: z50.string().nullable().optional().describe('Operator-facing next step. Null when status is "ok" or no specific remediation applies.'),
@@ -15025,6 +15081,7 @@ var checkResultSchema = z50.object({
15025
15081
  var doctorReportSchema = z50.object({
15026
15082
  scope: checkScopeSchema,
15027
15083
  project: z50.string().nullable().describe('Project name when scope is "project", null otherwise.'),
15084
+ reportMonths: z50.array(reportMonthSchema).optional().describe("Calendar months evaluated by project report readiness checks."),
15028
15085
  generatedAt: z50.string().describe("ISO-8601 timestamp when this doctor run started."),
15029
15086
  durationMs: z50.number().int().nonnegative(),
15030
15087
  summary: z50.object({
@@ -15056,6 +15113,15 @@ function summarizeCheckResults(results) {
15056
15113
  }
15057
15114
  return summary;
15058
15115
  }
15116
+ function groupIsoDateRanges(dates) {
15117
+ const ranges = [];
15118
+ for (const date of [...new Set(dates)].sort()) {
15119
+ const previous = ranges.at(-1);
15120
+ if (previous && shiftIsoCalendarDate(previous.end, 1) === date) previous.end = date;
15121
+ else ranges.push({ start: date, end: date });
15122
+ }
15123
+ return ranges;
15124
+ }
15059
15125
 
15060
15126
  // ../contracts/src/index-coverage.ts
15061
15127
  function deriveIndexCoverage(input) {
@@ -20115,6 +20181,8 @@ export {
20115
20181
  windowCutoff,
20116
20182
  resolveDateRange,
20117
20183
  visibilityStatsDtoSchema,
20184
+ isVisibilityCompareClassMetric,
20185
+ visibilityCompareSelectionSchema,
20118
20186
  visibilityCompareDtoSchema,
20119
20187
  calendarMonthBounds,
20120
20188
  resultsExportDtoSchema,
@@ -20186,8 +20254,13 @@ export {
20186
20254
  CheckStatuses,
20187
20255
  CheckScopes,
20188
20256
  CheckCategories,
20257
+ CheckNotificationPolicies,
20258
+ reportMonthSchema,
20259
+ reportMonthsForDoctor,
20260
+ gradedReportMonths,
20189
20261
  doctorReportSchema,
20190
20262
  summarizeCheckResults,
20263
+ groupIsoDateRanges,
20191
20264
  deriveIndexCoverage,
20192
20265
  normalizeQueryText,
20193
20266
  citationVisibilityResponseSchema,
@@ -13,19 +13,19 @@ import {
13
13
  resolveOperatorApiKeyIds,
14
14
  runWithUsageTags,
15
15
  saveConfigPatch
16
- } from "./chunk-PXVJ3P5G.js";
16
+ } from "./chunk-GLLY2GEV.js";
17
17
  import {
18
18
  deleteSiteCrawlGraphLayout,
19
19
  persistSiteCrawlGraphLayout,
20
20
  prepareSiteCrawlGraphLayout
21
- } from "./chunk-TWLJRAWA.js";
21
+ } from "./chunk-3LCR6WU6.js";
22
22
  import {
23
23
  CanonryMcpToolNames,
24
24
  CliError,
25
25
  PACKAGE_VERSION,
26
26
  canonryMcpTools,
27
27
  isMachineFormat
28
- } from "./chunk-JJPZ4OQ2.js";
28
+ } from "./chunk-DDL2XSNM.js";
29
29
  import {
30
30
  CC_CACHE_DIR,
31
31
  DUCKDB_SPEC,
@@ -172,6 +172,7 @@ import {
172
172
  runChecks,
173
173
  runFills,
174
174
  runs,
175
+ scheduledHealthCheckIds,
175
176
  schedules,
176
177
  serializeUserSessionCookie,
177
178
  siteAuditPages,
@@ -186,7 +187,7 @@ import {
186
187
  siteLivenessState,
187
188
  toAlertView,
188
189
  usageCounters
189
- } from "./chunk-NSKFW3NF.js";
190
+ } from "./chunk-P5VXVFQW.js";
190
191
  import {
191
192
  AGENT_MEMORY_VALUE_MAX_BYTES,
192
193
  AGENT_NONE,
@@ -201,6 +202,7 @@ import {
201
202
  CANONRY_NPM_PACKAGE_URL,
202
203
  CITED_URL_CAPTURE_VERSION,
203
204
  CcReleaseSyncStatuses,
205
+ CheckNotificationPolicies,
204
206
  DEFAULT_VIEWER_RESEARCH_DAILY_RUN_LIMIT,
205
207
  DiscoveryCompetitorTypes,
206
208
  GOOGLE_ADS_CAMPAIGN_METRICS_MAX_CAMPAIGNS,
@@ -303,6 +305,7 @@ import {
303
305
  hostMatchesAnyDomain,
304
306
  hostMatchesDomain,
305
307
  hostOf,
308
+ inclusiveDayCount,
306
309
  isAgentProviderId,
307
310
  isBrowserProvider,
308
311
  isGhostTelemetryEvent,
@@ -331,6 +334,7 @@ import {
331
334
  providerError,
332
335
  providerSupportsLocationContext,
333
336
  registrableDomain,
337
+ reportMonthsForDoctor,
334
338
  resolveProviderModel,
335
339
  resolveSnapshotRequestQueries,
336
340
  retryAfterDelayMs,
@@ -353,7 +357,7 @@ import {
353
357
  visibilityReportRequestSchema,
354
358
  winnabilityClassLabel,
355
359
  withRetry
356
- } from "./chunk-TOSPZ7I5.js";
360
+ } from "./chunk-S5OSY3PI.js";
357
361
 
358
362
  // src/runtime-context.ts
359
363
  function cliRuntimeContext(env = process.env, stdio = process) {
@@ -6648,7 +6652,7 @@ function nonBlank(value) {
6648
6652
  return trimmed ? trimmed : void 0;
6649
6653
  }
6650
6654
  function resolveBuildCommit(env = process.env) {
6651
- const embedded = true ? "c87b5bdf06eeeab4fafa7742f07c1c91149c0b70" : void 0;
6655
+ const embedded = true ? "120bbd89c1dedb8df5c2850da43ac2e71ccd3cdc" : void 0;
6652
6656
  return nonBlank(embedded) ?? nonBlank(env.CANONRY_COMMIT);
6653
6657
  }
6654
6658
  function resolveInstanceIdentity(env = process.env) {
@@ -12235,7 +12239,7 @@ function readStoredGroundingSources(rawResponse) {
12235
12239
  return result2;
12236
12240
  }
12237
12241
  async function backfillInsightsCommand(project, opts) {
12238
- const { IntelligenceService: IntelligenceService2 } = await import("./intelligence-service-QHSR2H7F.js");
12242
+ const { IntelligenceService: IntelligenceService2 } = await import("./intelligence-service-CXNBKRHV.js");
12239
12243
  const config = loadConfig();
12240
12244
  const db = createClient(config.database);
12241
12245
  migrate(db);
@@ -13436,11 +13440,16 @@ function startSiteLivenessLoop(deps, intervalMs = SITE_LIVENESS_INTERVAL_MS) {
13436
13440
 
13437
13441
  // src/data-refresh.ts
13438
13442
  var log16 = createLogger("DataRefresh");
13439
- async function refreshAllIntegrations(client, projectName) {
13443
+ function gaRefreshDays(now = /* @__PURE__ */ new Date()) {
13444
+ const [reportMonth] = reportMonthsForDoctor(void 0, now);
13445
+ const reach = inclusiveDayCount(`${reportMonth}-01`, now.toISOString().slice(0, 10)) ?? 0;
13446
+ return Math.max(30, reach);
13447
+ }
13448
+ async function refreshAllIntegrations(client, projectName, now = /* @__PURE__ */ new Date()) {
13440
13449
  const integrations = [
13441
13450
  { name: "gsc", run: () => client.gscSync(projectName, {}) },
13442
13451
  { name: "bing", run: () => client.bingInspectSitemap(projectName, {}) },
13443
- { name: "ga", run: () => client.gaSync(projectName, { days: 30 }) },
13452
+ { name: "ga", run: () => client.gaSync(projectName, { days: gaRefreshDays(now) }) },
13444
13453
  { name: "gbp", run: () => client.triggerGbpSync(projectName, {}) },
13445
13454
  // `ads` remains the OpenAI / ChatGPT Ads integration. For scheduled
13446
13455
  // refreshes, Google providers have explicit names and fan out only here.
@@ -13581,13 +13590,15 @@ var Notifier = class {
13581
13590
  return 0;
13582
13591
  }
13583
13592
  };
13584
- const graded = report.checks.filter((c) => c.status === "fail" || c.status === "warn" || c.status === "ok");
13593
+ const healthChecks = report.checks.filter((c) => c.notificationPolicy !== CheckNotificationPolicies.silent);
13594
+ if (healthChecks.length === 0 && report.checks.length > 0) return null;
13595
+ const graded = healthChecks.filter((c) => c.status === "fail" || c.status === "warn" || c.status === "ok");
13585
13596
  const failing = graded.filter((c) => c.status !== "ok").sort((a, b) => rank(b.status) - rank(a.status) || categoryRank(b.category) - categoryRank(a.category) || a.id.localeCompare(b.id));
13586
13597
  const worst = failing.at(0) ?? null;
13587
13598
  const noSignal = graded.length === 0;
13588
13599
  const status = noSignal ? "warn" : worst ? worst.status : "ok";
13589
13600
  const code = noSignal ? "health.no-signal" : worst?.code ?? "health.ok";
13590
- const summary = noSignal ? `No health check produced a result (${report.checks.length} skipped) \u2014 health is unknown, not confirmed.` : worst?.summary ?? `All ${graded.length} health check(s) passing.`;
13601
+ const summary = noSignal ? `No health check produced a result (${healthChecks.length} skipped) \u2014 health is unknown, not confirmed.` : worst?.summary ?? `All ${graded.length} health check(s) passing.`;
13591
13602
  const previous = this.db.select().from(doctorHealthState).where(eq17(doctorHealthState.projectId, projectId)).get();
13592
13603
  const previousStatus = previous?.status ?? null;
13593
13604
  const failingSignature = failing.map((c) => `${c.status}:${c.code}`).join(",");
@@ -19493,7 +19504,7 @@ async function createServer(opts) {
19493
19504
  onDoctorRequested: (projectName) => {
19494
19505
  void (async () => {
19495
19506
  try {
19496
- const report = await schedulerClient.runDoctor({ project: projectName });
19507
+ const report = await schedulerClient.runDoctor({ project: projectName, checkIds: scheduledHealthCheckIds() });
19497
19508
  const project = opts.db.select().from(projects).where(eq27(projects.name, projectName)).get();
19498
19509
  if (!project) {
19499
19510
  app.log.warn({ projectName }, "doctor schedule fired for an unknown project");
@@ -4,14 +4,14 @@ import {
4
4
  installSkills,
5
5
  loadConfigRaw,
6
6
  saveConfigPatch
7
- } from "./chunk-PXVJ3P5G.js";
7
+ } from "./chunk-GLLY2GEV.js";
8
8
  import {
9
9
  PACKAGE_VERSION
10
- } from "./chunk-JJPZ4OQ2.js";
10
+ } from "./chunk-DDL2XSNM.js";
11
11
  import {
12
12
  SKILL_MANIFEST_FILENAME,
13
13
  SkillsClients
14
- } from "./chunk-TOSPZ7I5.js";
14
+ } from "./chunk-S5OSY3PI.js";
15
15
 
16
16
  // src/skills-autosync.ts
17
17
  import fs from "fs";
package/dist/cli.js CHANGED
@@ -35,11 +35,11 @@ import {
35
35
  trackCliCommandFinished,
36
36
  trackEvent,
37
37
  waitForServerRuntimeStartup
38
- } from "./chunk-P73YBGZP.js";
38
+ } from "./chunk-XFHXKLNT.js";
39
39
  import {
40
40
  autoSyncSkills,
41
41
  formatAutoSyncNotice
42
- } from "./chunk-CVUR3O5G.js";
42
+ } from "./chunk-YTSXQUJ3.js";
43
43
  import {
44
44
  configExists,
45
45
  createApiClient,
@@ -56,13 +56,13 @@ import {
56
56
  saveConfig,
57
57
  saveConfigPatch,
58
58
  shouldPrintServeSkillsNudge
59
- } from "./chunk-PXVJ3P5G.js";
59
+ } from "./chunk-GLLY2GEV.js";
60
60
  import {
61
61
  DEFAULT_DEMO_TRUSTED_PROXIES,
62
62
  trustedProxiesProblem,
63
63
  trustedProxyProblem
64
64
  } from "./chunk-RB2F4D3Z.js";
65
- import "./chunk-TWLJRAWA.js";
65
+ import "./chunk-3LCR6WU6.js";
66
66
  import {
67
67
  CliError,
68
68
  EXIT_SYSTEM_ERROR,
@@ -74,7 +74,7 @@ import {
74
74
  runMeasurementDraftAction,
75
75
  systemError,
76
76
  usageError
77
- } from "./chunk-JJPZ4OQ2.js";
77
+ } from "./chunk-DDL2XSNM.js";
78
78
  import {
79
79
  CLOUDFLARE_WORKER_BINDINGS,
80
80
  CLOUDFLARE_WORKER_GENERATED_MARKER,
@@ -89,7 +89,7 @@ import {
89
89
  queries,
90
90
  renderReportHtml,
91
91
  runs
92
- } from "./chunk-NSKFW3NF.js";
92
+ } from "./chunk-P5VXVFQW.js";
93
93
  import {
94
94
  AdsDeliverySnapshotStatuses,
95
95
  AdsHistoricalCampaignRollupStatuses,
@@ -146,6 +146,7 @@ import {
146
146
  formatRunErrorOneLine,
147
147
  formatWholePercent,
148
148
  googleAdsMetricsWindowSchema,
149
+ isVisibilityCompareClassMetric,
149
150
  logQuerySchema,
150
151
  measurementChangesQuerySchema,
151
152
  measurementDataQualityQuerySchema,
@@ -175,9 +176,10 @@ import {
175
176
  shareOfVoiceLabel,
176
177
  shareOfVoiceReason,
177
178
  snapshotProviderModeSchema,
179
+ visibilityCompareSelectionSchema,
178
180
  visibilityReportRequestSchema,
179
181
  winnabilityClassSchema
180
- } from "./chunk-TOSPZ7I5.js";
182
+ } from "./chunk-S5OSY3PI.js";
181
183
 
182
184
  // src/cli.ts
183
185
  import { pathToFileURL } from "url";
@@ -442,7 +444,7 @@ function parseDemoTrustedProxies(values) {
442
444
  async function demoCommand(options) {
443
445
  const { host, port } = parseDemoListenOptions(options);
444
446
  const trustProxy = parseDemoTrustedProxies(options.trustProxy);
445
- const { createDemoServer } = await import("./demo-server-FH2K6TCD.js");
447
+ const { createDemoServer } = await import("./demo-server-HULNEORN.js");
446
448
  const app = await createDemoServer({ trustProxy });
447
449
  let stopping = false;
448
450
  const stop = () => {
@@ -3049,7 +3051,8 @@ async function doctorCommand(opts) {
3049
3051
  const client = createApiClient();
3050
3052
  const report = await client.runDoctor({
3051
3053
  project: opts.project,
3052
- checkIds: opts.checks
3054
+ checkIds: opts.checks,
3055
+ ...opts.reportMonth ? { reportMonth: opts.reportMonth } : {}
3053
3056
  });
3054
3057
  if (opts.format === "json") {
3055
3058
  console.log(JSON.stringify(report, null, 2));
@@ -3075,8 +3078,8 @@ async function runDoctorAll(opts) {
3075
3078
  const client = createApiClient();
3076
3079
  const projects2 = await client.listProjects();
3077
3080
  const [globalReport, ...projectReports] = await Promise.all([
3078
- client.runDoctor({ checkIds: opts.checks }),
3079
- ...projects2.map((p) => client.runDoctor({ project: p.name, checkIds: opts.checks }))
3081
+ client.runDoctor({ checkIds: opts.checks, ...opts.reportMonth ? { reportMonth: opts.reportMonth } : {} }),
3082
+ ...projects2.map((p) => client.runDoctor({ project: p.name, checkIds: opts.checks, ...opts.reportMonth ? { reportMonth: opts.reportMonth } : {} }))
3080
3083
  ]);
3081
3084
  const byKey = { __global__: globalReport };
3082
3085
  projects2.forEach((p, i) => {
@@ -3172,13 +3175,14 @@ ${header}`);
3172
3175
  }
3173
3176
 
3174
3177
  // src/cli-commands/doctor.ts
3175
- var USAGE = "canonry doctor [--project <name>|--all] [--check <id>...] [--format json|jsonl]";
3178
+ var USAGE = "canonry doctor [--project <name>|--all] [--check <id>...] [--report-month YYYY-MM] [--format json|jsonl]";
3176
3179
  var DOCTOR_CLI_COMMANDS = [
3177
3180
  {
3178
3181
  path: ["doctor"],
3179
3182
  usage: USAGE,
3180
3183
  options: {
3181
3184
  project: stringOption(),
3185
+ "report-month": stringOption(),
3182
3186
  check: multiStringOption(),
3183
3187
  all: { type: "boolean" }
3184
3188
  },
@@ -3186,6 +3190,7 @@ var DOCTOR_CLI_COMMANDS = [
3186
3190
  run: async (input) => {
3187
3191
  await doctorCommand({
3188
3192
  project: getString(input.values, "project"),
3193
+ reportMonth: getString(input.values, "report-month"),
3189
3194
  all: getBoolean(input.values, "all"),
3190
3195
  checks: getStringArray(input.values, "check"),
3191
3196
  format: input.format
@@ -17420,7 +17425,7 @@ function pct3(rate) {
17420
17425
  async function showVisibilityCompare(project, opts) {
17421
17426
  if (!opts.from || !opts.to) throw new Error("visibility-compare requires --from <YYYY-MM> and --to <YYYY-MM>");
17422
17427
  const client = createApiClient();
17423
- const data = await client.getVisibilityCompare(project, opts.from, opts.to);
17428
+ const data = await client.getVisibilityCompare(project, opts.from, opts.to, { scope: opts.scope, scopeKey: opts.scopeKey, marketKey: opts.marketKey, provider: opts.provider, location: opts.location });
17424
17429
  if (isMachineFormat(opts.format)) {
17425
17430
  console.log(JSON.stringify(data, null, 2));
17426
17431
  return;
@@ -17428,6 +17433,7 @@ async function showVisibilityCompare(project, opts) {
17428
17433
  printVisibilityCompare(data);
17429
17434
  }
17430
17435
  function periodCell(p) {
17436
+ if (p.availability === "classification-unavailable") return "unavailable: query classification";
17431
17437
  if (p.availability === "no-competitive-frame") {
17432
17438
  return `unavailable: no competitive frame (${p.numerator} observed)`;
17433
17439
  }
@@ -17450,12 +17456,24 @@ function verdictCell(m) {
17450
17456
  }
17451
17457
  }
17452
17458
  function metricQueryClassLabel(metric) {
17459
+ if (metric.queryClass === "branded") return "branded queries";
17453
17460
  if (metric.queryClass === "non-brand") return "non-brand queries";
17454
17461
  if (metric.queryClass === "pooled") return "pooled queries; classification unavailable";
17455
17462
  return "all queries";
17456
17463
  }
17464
+ function selectionLabel(selection) {
17465
+ if (!selection) return null;
17466
+ const parts = [];
17467
+ if (selection.scope && selection.scope !== "project") parts.push(`${selection.scope} ${selection.scopeKey ?? ""}`.trim());
17468
+ if (selection.marketKey) parts.push(`market ${selection.marketKey}`);
17469
+ if (selection.provider) parts.push(`engine ${selection.provider}`);
17470
+ if (selection.location) parts.push(`location ${selection.location}`);
17471
+ return parts.length > 0 ? parts.join(" \xB7 ") : null;
17472
+ }
17457
17473
  function printVisibilityCompare(data) {
17458
17474
  console.log(`AEO month over month: ${data.project} ${data.from.month} -> ${data.to.month}`);
17475
+ const selection = selectionLabel(data.selection);
17476
+ if (selection) console.log(`Selection: ${selection}`);
17459
17477
  const b = data.basket;
17460
17478
  const excl = [];
17461
17479
  if (b.excludedFromOnly > 0) excl.push(`${b.excludedFromOnly} only in ${data.from.month}`);
@@ -17469,8 +17487,19 @@ function printVisibilityCompare(data) {
17469
17487
  console.log(`Continuity: ${data.continuity.status.replace("-", " ")} \u2014 no directional call is made.`);
17470
17488
  }
17471
17489
  console.log("");
17490
+ if (data.classComparison) {
17491
+ const frame = data.classComparison;
17492
+ console.log(`Class metrics basket (frozen Advanced): ${frame.basket.queryCount} queries; engines: ${frame.basket.providers.join(", ") || "none"}`);
17493
+ const classSweeps = `Class basket sweeps: ${frame.from.month} ${frame.from.runCount}, ${frame.to.month} ${frame.to.runCount}; continuity: ${frame.continuity.status}`;
17494
+ const classLow = frame.from.lowRunCount || frame.to.lowRunCount;
17495
+ console.log(classLow ? `${classSweeps} (below the 5-sweep floor \u2014 class intervals are wide, a "moved" verdict is unlikely to be reachable)` : classSweeps);
17496
+ for (const provider of frame.continuity.providers) {
17497
+ if (provider.status !== "included") console.log(`Class basket excludes ${provider.provider}: ${provider.fromModels.join("/") || "?"} -> ${provider.toModels.join("/") || "?"} (${provider.status})`);
17498
+ }
17499
+ console.log("");
17500
+ }
17472
17501
  const rows = data.metrics.map((m) => ({
17473
- label: `${m.label} \xB7 ${metricQueryClassLabel(m)}${m.driftRobust ? " *" : ""}`,
17502
+ label: `${m.label} \xB7 ${metricQueryClassLabel(m)}${data.classComparison && isVisibilityCompareClassMetric(m.key) ? " \xB7 class basket" : ""}${m.driftRobust ? " *" : ""}`,
17474
17503
  to: periodCell(m.to),
17475
17504
  from: periodCell(m.from),
17476
17505
  verdict: verdictCell(m)
@@ -17600,7 +17629,32 @@ function parseQueryClass(value) {
17600
17629
  }
17601
17630
  return value;
17602
17631
  }
17603
- var COMPARE_USAGE = "canonry visibility-compare <project> --from <YYYY-MM> --to <YYYY-MM> [--format json]";
17632
+ var COMPARE_USAGE = "canonry visibility-compare <project> --from <YYYY-MM> --to <YYYY-MM> [--scope project|group|market|property] [--scope-key <key>] [--market-key <key>] [--provider <engine>] [--location <label|none>] [--format json]";
17633
+ var COMPARE_SELECTION_FLAGS = {
17634
+ scope: "--scope",
17635
+ scopeKey: "--scope-key",
17636
+ marketKey: "--market-key",
17637
+ provider: "--provider",
17638
+ location: "--location"
17639
+ };
17640
+ function parseCompareSelection(values) {
17641
+ const parsed = visibilityCompareSelectionSchema.safeParse({
17642
+ scope: getString(values, "scope"),
17643
+ scopeKey: getString(values, "scope-key"),
17644
+ marketKey: getString(values, "market-key"),
17645
+ provider: getString(values, "provider"),
17646
+ location: getString(values, "location")
17647
+ });
17648
+ if (parsed.success) return parsed.data;
17649
+ const issue = parsed.error.issues[0];
17650
+ const flag = COMPARE_SELECTION_FLAGS[String(issue.path[0])] ?? "--scope";
17651
+ const message = flag === "--scope" ? "--scope must be one of: project, group, market, property" : `${flag} must not be empty`;
17652
+ throw usageError(`Error: ${message}
17653
+ Usage: ${COMPARE_USAGE}`, {
17654
+ message,
17655
+ details: { command: "visibility-compare", usage: COMPARE_USAGE }
17656
+ });
17657
+ }
17604
17658
  var VISIBILITY_STATS_CLI_COMMANDS = [
17605
17659
  {
17606
17660
  path: ["visibility-stats"],
@@ -17637,13 +17691,19 @@ var VISIBILITY_STATS_CLI_COMMANDS = [
17637
17691
  usage: COMPARE_USAGE,
17638
17692
  options: {
17639
17693
  from: stringOption(),
17640
- to: stringOption()
17694
+ to: stringOption(),
17695
+ scope: stringOption(),
17696
+ "scope-key": stringOption(),
17697
+ "market-key": stringOption(),
17698
+ provider: stringOption(),
17699
+ location: stringOption()
17641
17700
  },
17642
17701
  run: async (input) => {
17643
17702
  const project = requireProject(input, "visibility-compare", COMPARE_USAGE);
17644
17703
  await showVisibilityCompare(project, {
17645
17704
  from: getString(input.values, "from"),
17646
17705
  to: getString(input.values, "to"),
17706
+ ...parseCompareSelection(input.values),
17647
17707
  format: input.format
17648
17708
  });
17649
17709
  }
@@ -4,11 +4,11 @@ import {
4
4
  import {
5
5
  layoutSiteCrawlGraphInput,
6
6
  persistSiteCrawlGraphLayout
7
- } from "./chunk-TWLJRAWA.js";
7
+ } from "./chunk-3LCR6WU6.js";
8
8
  import {
9
9
  PACKAGE_VERSION,
10
10
  canonryMcpTools
11
- } from "./chunk-JJPZ4OQ2.js";
11
+ } from "./chunk-DDL2XSNM.js";
12
12
  import {
13
13
  HISTORY_WINDOW_RUNS,
14
14
  IntelligenceService,
@@ -84,7 +84,7 @@ import {
84
84
  siteCrawlPages,
85
85
  siteCrawlSnapshots,
86
86
  trafficSources
87
- } from "./chunk-NSKFW3NF.js";
87
+ } from "./chunk-P5VXVFQW.js";
88
88
  import {
89
89
  RunKinds,
90
90
  SiteCrawlFetchStates,
@@ -108,7 +108,7 @@ import {
108
108
  placementLinkDecision,
109
109
  siteAuditPageFactorSchema,
110
110
  wilsonInterval
111
- } from "./chunk-TOSPZ7I5.js";
111
+ } from "./chunk-S5OSY3PI.js";
112
112
 
113
113
  // src/demo-server.ts
114
114
  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-P73YBGZP.js";
6
+ } from "./chunk-XFHXKLNT.js";
7
7
  import {
8
8
  loadConfig
9
- } from "./chunk-PXVJ3P5G.js";
10
- import "./chunk-TWLJRAWA.js";
11
- import "./chunk-JJPZ4OQ2.js";
12
- import "./chunk-NSKFW3NF.js";
13
- import "./chunk-TOSPZ7I5.js";
9
+ } from "./chunk-GLLY2GEV.js";
10
+ import "./chunk-3LCR6WU6.js";
11
+ import "./chunk-DDL2XSNM.js";
12
+ import "./chunk-P5VXVFQW.js";
13
+ import "./chunk-S5OSY3PI.js";
14
14
  export {
15
15
  GoogleMarketingRuntimeError,
16
16
  createGoogleMarketingCredentialStore,
@@ -1,8 +1,8 @@
1
1
  import {
2
2
  HISTORY_WINDOW_RUNS,
3
3
  IntelligenceService
4
- } from "./chunk-NSKFW3NF.js";
5
- import "./chunk-TOSPZ7I5.js";
4
+ } from "./chunk-P5VXVFQW.js";
5
+ import "./chunk-S5OSY3PI.js";
6
6
  export {
7
7
  HISTORY_WINDOW_RUNS,
8
8
  IntelligenceService
package/dist/mcp.js CHANGED
@@ -1,15 +1,15 @@
1
1
  import {
2
2
  autoSyncSkills
3
- } from "./chunk-CVUR3O5G.js";
3
+ } from "./chunk-YTSXQUJ3.js";
4
4
  import {
5
5
  createApiClient,
6
6
  createCanonryMcpServer
7
- } from "./chunk-PXVJ3P5G.js";
8
- import "./chunk-JJPZ4OQ2.js";
7
+ } from "./chunk-GLLY2GEV.js";
8
+ import "./chunk-DDL2XSNM.js";
9
9
  import {
10
10
  isReadOnlyKey,
11
11
  updateCheckEnvOptOut
12
- } from "./chunk-TOSPZ7I5.js";
12
+ } from "./chunk-S5OSY3PI.js";
13
13
 
14
14
  // src/mcp/cli.ts
15
15
  import { randomUUID } from "crypto";