@ainyc/canonry 4.82.0 → 4.84.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/SKILL.md +14 -10
  2. package/assets/agent-workspace/skills/aero/references/aeo-discovery.md +7 -5
  3. package/assets/agent-workspace/skills/aero/references/memory-patterns.md +1 -1
  4. package/assets/agent-workspace/skills/aero/references/orchestration.md +22 -20
  5. package/assets/agent-workspace/skills/aero/references/regression-playbook.md +9 -9
  6. package/assets/agent-workspace/skills/aero/references/reporting.md +14 -9
  7. package/assets/agent-workspace/skills/aero/soul.md +5 -5
  8. package/assets/agent-workspace/skills/canonry/SKILL.md +1 -1
  9. package/assets/agent-workspace/skills/canonry/references/aeo-analysis.md +84 -36
  10. package/assets/agent-workspace/skills/canonry/references/canonry-cli.md +25 -10
  11. package/assets/assets/{BacklinksPage-CHclt-pq.js → BacklinksPage-OrSg_iPA.js} +1 -1
  12. package/assets/assets/{ChartPrimitives-2Ub4vNWe.js → ChartPrimitives-DPBhAT_r.js} +1 -1
  13. package/assets/assets/{ProjectPage-UPmHfuxR.js → ProjectPage-CpMcEmtw.js} +1 -1
  14. package/assets/assets/{RunRow-rUL1UeA3.js → RunRow-2Rty0BAH.js} +1 -1
  15. package/assets/assets/{RunsPage-BQpHfUJf.js → RunsPage-B3ahqf8s.js} +1 -1
  16. package/assets/assets/{SettingsPage-DjTJlr_1.js → SettingsPage-BIjeI85q.js} +1 -1
  17. package/assets/assets/{TrafficPage-D7rv3BrH.js → TrafficPage-DjGoj691.js} +1 -1
  18. package/assets/assets/{TrafficSourceDetailPage-BysyuH2H.js → TrafficSourceDetailPage-BgKG-2q3.js} +1 -1
  19. package/assets/assets/{arrow-left-CR_FGlkE.js → arrow-left-Cf7wmru1.js} +1 -1
  20. package/assets/assets/{extract-error-message-BKkAbWNp.js → extract-error-message-CANxezte.js} +1 -1
  21. package/assets/assets/{index-DzzTt20n.js → index-CGlPx_cu.js} +3 -3
  22. package/assets/assets/{trash-2-uSttujvh.js → trash-2-6nHJZrvy.js} +1 -1
  23. package/assets/index.html +1 -1
  24. package/dist/{chunk-KPSFRSS7.js → chunk-BNF3HXBW.js} +5 -0
  25. package/dist/{chunk-NSZ3D3MM.js → chunk-M3IYKTSF.js} +17 -4
  26. package/dist/{chunk-IEUTAQUF.js → chunk-VJBO4VIK.js} +108 -5
  27. package/dist/{chunk-JLAD6CYH.js → chunk-Y3O3HBMN.js} +1 -1
  28. package/dist/cli.js +22 -16
  29. package/dist/index.js +4 -4
  30. package/dist/{intelligence-service-2UUJ3YGI.js → intelligence-service-PDIAMP5I.js} +2 -2
  31. package/dist/mcp.js +2 -2
  32. package/package.json +9 -9
@@ -1872,6 +1872,11 @@ var discoveryProbeDtoSchema = z17.object({
1872
1872
  bucket: discoveryBucketSchema.nullable().default(null),
1873
1873
  citationState: citationStateSchema,
1874
1874
  citedDomains: z17.array(z17.string()).default([]),
1875
+ // Answer-text mention signal, independent of citationState. Tri-state: true
1876
+ // (named in the answer prose), false (probed, not named), null (unknown: a
1877
+ // legacy probe written before the engine computed it). Consumers must treat
1878
+ // null as unknown, never as false.
1879
+ answerMentioned: z17.boolean().nullable().default(null),
1875
1880
  createdAt: z17.string()
1876
1881
  });
1877
1882
  var discoverySessionDtoSchema = z17.object({
@@ -9,7 +9,7 @@ import {
9
9
  loadConfig,
10
10
  loadConfigRaw,
11
11
  saveConfigPatch
12
- } from "./chunk-JLAD6CYH.js";
12
+ } from "./chunk-Y3O3HBMN.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-IEUTAQUF.js";
107
+ } from "./chunk-VJBO4VIK.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-KPSFRSS7.js";
163
+ } from "./chunk-BNF3HXBW.js";
164
164
 
165
165
  // src/telemetry.ts
166
166
  import crypto from "crypto";
@@ -5376,9 +5376,14 @@ async function executeDiscoveryRun(opts) {
5376
5376
  canonicalDomain: projectRow.canonicalDomain,
5377
5377
  ownedDomains: projectRow.ownedDomains
5378
5378
  });
5379
+ const brandNames = effectiveBrandNames({
5380
+ displayName: projectRow.displayName,
5381
+ aliases: projectRow.aliases
5382
+ });
5379
5383
  const project = {
5380
5384
  id: projectRow.id,
5381
5385
  name: projectRow.name,
5386
+ brandNames,
5382
5387
  canonicalDomains,
5383
5388
  competitorDomains: projectCompetitors
5384
5389
  };
@@ -5466,9 +5471,15 @@ function buildDefaultDeps(registry) {
5466
5471
  const normalized = adapter.normalizeResult(raw);
5467
5472
  const canonical = new Set(input.project.canonicalDomains.map((d) => d.toLowerCase()));
5468
5473
  const isCited = normalized.citedDomains.some((d) => canonical.has(d.toLowerCase()));
5474
+ const answerMentioned = determineAnswerMentioned(
5475
+ normalized.answerText,
5476
+ input.project.brandNames ?? [],
5477
+ input.project.canonicalDomains
5478
+ );
5469
5479
  return {
5470
5480
  citationState: isCited ? "cited" : "not-cited",
5471
5481
  citedDomains: normalized.citedDomains,
5482
+ answerMentioned,
5472
5483
  rawResponse: raw.rawResponse
5473
5484
  };
5474
5485
  },
@@ -6278,7 +6289,7 @@ function readStoredGroundingSources(rawResponse) {
6278
6289
  return result;
6279
6290
  }
6280
6291
  async function backfillInsightsCommand(project, opts) {
6281
- const { IntelligenceService: IntelligenceService2 } = await import("./intelligence-service-2UUJ3YGI.js");
6292
+ const { IntelligenceService: IntelligenceService2 } = await import("./intelligence-service-PDIAMP5I.js");
6282
6293
  const config = loadConfig();
6283
6294
  const db = createClient(config.database);
6284
6295
  migrate(db);
@@ -7843,8 +7854,10 @@ function analysisResultFromInsights(insights2) {
7843
7854
  competitorLosses: [],
7844
7855
  health: {
7845
7856
  overallCitedRate: 0,
7857
+ overallMentionRate: 0,
7846
7858
  totalPairs: 0,
7847
7859
  citedPairs: 0,
7860
+ mentionedPairs: 0,
7848
7861
  providerBreakdown: {}
7849
7862
  },
7850
7863
  insights: insights2
@@ -246,7 +246,7 @@ import {
246
246
  wordpressSchemaDeployResultDtoSchema,
247
247
  wordpressSchemaStatusResultDtoSchema,
248
248
  wordpressStatusDtoSchema
249
- } from "./chunk-KPSFRSS7.js";
249
+ } from "./chunk-BNF3HXBW.js";
250
250
 
251
251
  // src/intelligence-service.ts
252
252
  import { eq as eq36, desc as desc17, asc as asc5, and as and26, ne as ne5, or as or5, inArray as inArray13, gte as gte7, lte as lte4 } from "drizzle-orm";
@@ -805,8 +805,16 @@ var healthSnapshots = sqliteTable("health_snapshots", {
805
805
  projectId: text("project_id").notNull().references(() => projects.id, { onDelete: "cascade" }),
806
806
  runId: text("run_id").references(() => runs.id, { onDelete: "cascade" }),
807
807
  overallCitedRate: text("overall_cited_rate").notNull(),
808
+ // Answer-text mention rate, independent of citation. Nullable because the
809
+ // column is added by migration v80 via ALTER TABLE ADD COLUMN — rows
810
+ // persisted before v80 read back as NULL ("not measured"); readers coalesce
811
+ // NULL→0. New writes always populate it (see intelligence-service persist).
812
+ overallMentionRate: text("overall_mention_rate"),
808
813
  totalPairs: integer("total_pairs").notNull(),
809
814
  citedPairs: integer("cited_pairs").notNull(),
815
+ // Count of pairs MENTIONED in the answer text. Nullable for the same
816
+ // legacy-row reason as overall_mention_rate; coalesced NULL→0 on read.
817
+ mentionedPairs: integer("mentioned_pairs"),
810
818
  providerBreakdown: text("provider_breakdown", { mode: "json" }).$type().notNull().default({}),
811
819
  createdAt: text("created_at").notNull()
812
820
  }, (table) => [
@@ -1055,6 +1063,10 @@ var discoveryProbes = sqliteTable("discovery_probes", {
1055
1063
  query: text("query").notNull(),
1056
1064
  bucket: text("bucket"),
1057
1065
  citationState: text("citation_state").notNull(),
1066
+ // Answer-text mention signal, independent of citationState. Tri-state: true
1067
+ // (named in the answer prose), false (probed, not named), null (legacy rows
1068
+ // written before this column / never computed). Mirrors querySnapshots.answerMentioned.
1069
+ answerMentioned: integer("answer_mentioned", { mode: "boolean" }),
1058
1070
  citedDomains: text("cited_domains", { mode: "json" }).$type().notNull().default([]),
1059
1071
  rawResponse: text("raw_response"),
1060
1072
  createdAt: text("created_at").notNull()
@@ -3075,6 +3087,41 @@ var MIGRATION_VERSIONS = [
3075
3087
  run: (tx) => {
3076
3088
  addBacklinkSourceDiscriminator(tx);
3077
3089
  }
3090
+ },
3091
+ {
3092
+ // Answer-text mention signal on discovery probes (independent of citation).
3093
+ // Nullable: pre-existing rows were written before the column / never had the
3094
+ // mention computed, so they read back as null (unknown) downstream.
3095
+ version: 79,
3096
+ name: "discovery-probes-answer-mentioned",
3097
+ statements: [
3098
+ `ALTER TABLE discovery_probes ADD COLUMN answer_mentioned INTEGER`
3099
+ ]
3100
+ },
3101
+ {
3102
+ // Mention-rate columns on the persisted health snapshot, mirroring the
3103
+ // existing cited columns (overall_cited_rate / cited_pairs) for the
3104
+ // independent answer-text mention signal. Nullable: rows written before
3105
+ // this version have no mention math, so they read back as NULL ("not
3106
+ // measured") and readers coalesce NULL→0.
3107
+ //
3108
+ // Guarded `run` rather than bare `statements` (the v66 pattern): the
3109
+ // table-existence check makes this a no-op when `health_snapshots` is
3110
+ // absent — only possible on a legacy fixture whose recorded
3111
+ // `_migrations` version skips v23's `CREATE TABLE` (the bootstrap is
3112
+ // bypassed). The column-existence check keeps a replay idempotent.
3113
+ version: 80,
3114
+ name: "health-snapshots-mention-rate",
3115
+ statements: [],
3116
+ run: (db) => {
3117
+ if (!tableExists(db, "health_snapshots")) return;
3118
+ if (!columnExists(db, "health_snapshots", "overall_mention_rate")) {
3119
+ db.run(sql.raw(`ALTER TABLE health_snapshots ADD COLUMN overall_mention_rate TEXT`));
3120
+ }
3121
+ if (!columnExists(db, "health_snapshots", "mentioned_pairs")) {
3122
+ db.run(sql.raw(`ALTER TABLE health_snapshots ADD COLUMN mentioned_pairs INTEGER`));
3123
+ }
3124
+ }
3078
3125
  }
3079
3126
  ];
3080
3127
  function rebuildBacklinkTableWithSource(tx, table) {
@@ -3398,26 +3445,33 @@ function computeHealth(run) {
3398
3445
  const providerStats = /* @__PURE__ */ new Map();
3399
3446
  let totalPairs = 0;
3400
3447
  let citedPairs = 0;
3448
+ let mentionedPairs = 0;
3401
3449
  for (const snap of run.snapshots) {
3402
3450
  totalPairs++;
3403
3451
  if (snap.cited) citedPairs++;
3404
- const stats = providerStats.get(snap.provider) ?? { cited: 0, total: 0 };
3452
+ if (snap.answerMentioned === true) mentionedPairs++;
3453
+ const stats = providerStats.get(snap.provider) ?? { cited: 0, mentioned: 0, total: 0 };
3405
3454
  stats.total++;
3406
3455
  if (snap.cited) stats.cited++;
3456
+ if (snap.answerMentioned === true) stats.mentioned++;
3407
3457
  providerStats.set(snap.provider, stats);
3408
3458
  }
3409
3459
  const providerBreakdown = {};
3410
3460
  for (const [provider, stats] of providerStats) {
3411
3461
  providerBreakdown[provider] = {
3412
3462
  citedRate: stats.total > 0 ? stats.cited / stats.total : 0,
3463
+ mentionRate: stats.total > 0 ? stats.mentioned / stats.total : 0,
3413
3464
  cited: stats.cited,
3465
+ mentioned: stats.mentioned,
3414
3466
  total: stats.total
3415
3467
  };
3416
3468
  }
3417
3469
  return {
3418
3470
  overallCitedRate: totalPairs > 0 ? citedPairs / totalPairs : 0,
3471
+ overallMentionRate: totalPairs > 0 ? mentionedPairs / totalPairs : 0,
3419
3472
  totalPairs,
3420
3473
  citedPairs,
3474
+ mentionedPairs,
3421
3475
  providerBreakdown
3422
3476
  };
3423
3477
  }
@@ -7898,8 +7952,10 @@ function emptyHealthSnapshot(projectId) {
7898
7952
  projectId,
7899
7953
  runId: null,
7900
7954
  overallCitedRate: 0,
7955
+ overallMentionRate: 0,
7901
7956
  totalPairs: 0,
7902
7957
  citedPairs: 0,
7958
+ mentionedPairs: 0,
7903
7959
  providerBreakdown: {},
7904
7960
  createdAt: "",
7905
7961
  status: "no-data",
@@ -7922,15 +7978,31 @@ function mapInsightRow(r) {
7922
7978
  createdAt: r.createdAt
7923
7979
  };
7924
7980
  }
7981
+ function coalesceProviderBreakdown(breakdown) {
7982
+ const out = {};
7983
+ for (const [provider, entry] of Object.entries(breakdown)) {
7984
+ out[provider] = {
7985
+ citedRate: entry.citedRate,
7986
+ mentionRate: entry.mentionRate ?? 0,
7987
+ cited: entry.cited,
7988
+ mentioned: entry.mentioned ?? 0,
7989
+ total: entry.total
7990
+ };
7991
+ }
7992
+ return out;
7993
+ }
7925
7994
  function mapHealthRow(r) {
7926
7995
  return {
7927
7996
  id: r.id,
7928
7997
  projectId: r.projectId,
7929
7998
  runId: r.runId ?? null,
7930
7999
  overallCitedRate: Number(r.overallCitedRate),
8000
+ // Legacy rows (persisted before v80) have NULL mention columns → 0.
8001
+ overallMentionRate: r.overallMentionRate == null ? 0 : Number(r.overallMentionRate),
7931
8002
  totalPairs: r.totalPairs,
7932
8003
  citedPairs: r.citedPairs,
7933
- providerBreakdown: r.providerBreakdown,
8004
+ mentionedPairs: r.mentionedPairs ?? 0,
8005
+ providerBreakdown: coalesceProviderBreakdown(r.providerBreakdown),
7934
8006
  createdAt: r.createdAt,
7935
8007
  status: "ready"
7936
8008
  };
@@ -7939,26 +8011,31 @@ function aggregateHealthSnapshots(projectId, rows) {
7939
8011
  if (rows.length === 1) return mapHealthRow(rows[0]);
7940
8012
  let totalPairs = 0;
7941
8013
  let citedPairs = 0;
8014
+ let mentionedPairs = 0;
7942
8015
  const mergedProviders = {};
7943
8016
  let newestCreatedAt = "";
7944
8017
  const runIds = [];
7945
8018
  for (const row of rows) {
7946
8019
  totalPairs += row.totalPairs;
7947
8020
  citedPairs += row.citedPairs;
8021
+ mentionedPairs += row.mentionedPairs ?? 0;
7948
8022
  if (row.createdAt > newestCreatedAt) newestCreatedAt = row.createdAt;
7949
8023
  if (row.runId) runIds.push(row.runId);
7950
8024
  const providerBreakdown = row.providerBreakdown;
7951
8025
  for (const [provider, entry] of Object.entries(providerBreakdown)) {
7952
- const existing = mergedProviders[provider] ?? { total: 0, cited: 0, citedRate: 0 };
8026
+ const existing = mergedProviders[provider] ?? { total: 0, cited: 0, mentioned: 0, citedRate: 0, mentionRate: 0 };
7953
8027
  existing.total += entry.total;
7954
8028
  existing.cited += entry.cited;
8029
+ existing.mentioned += entry.mentioned ?? 0;
7955
8030
  mergedProviders[provider] = existing;
7956
8031
  }
7957
8032
  }
7958
8033
  for (const entry of Object.values(mergedProviders)) {
7959
8034
  entry.citedRate = entry.total > 0 ? entry.cited / entry.total : 0;
8035
+ entry.mentionRate = entry.total > 0 ? entry.mentioned / entry.total : 0;
7960
8036
  }
7961
8037
  const overallCitedRate = totalPairs > 0 ? citedPairs / totalPairs : 0;
8038
+ const overallMentionRate = totalPairs > 0 ? mentionedPairs / totalPairs : 0;
7962
8039
  return {
7963
8040
  // Synthetic id so consumers can tell this is an aggregate; concatenate
7964
8041
  // source runIds for traceability without inventing a new schema column.
@@ -7966,8 +8043,10 @@ function aggregateHealthSnapshots(projectId, rows) {
7966
8043
  projectId,
7967
8044
  runId: runIds[0] ?? null,
7968
8045
  overallCitedRate,
8046
+ overallMentionRate,
7969
8047
  totalPairs,
7970
8048
  citedPairs,
8049
+ mentionedPairs,
7971
8050
  providerBreakdown: mergedProviders,
7972
8051
  createdAt: newestCreatedAt,
7973
8052
  status: "ready"
@@ -13164,14 +13243,27 @@ function mapInsightRow2(r) {
13164
13243
  };
13165
13244
  }
13166
13245
  function mapHealthRow2(r) {
13246
+ const providerBreakdown = {};
13247
+ for (const [provider, entry] of Object.entries(r.providerBreakdown)) {
13248
+ providerBreakdown[provider] = {
13249
+ citedRate: entry.citedRate,
13250
+ mentionRate: entry.mentionRate ?? 0,
13251
+ cited: entry.cited,
13252
+ mentioned: entry.mentioned ?? 0,
13253
+ total: entry.total
13254
+ };
13255
+ }
13167
13256
  return {
13168
13257
  id: r.id,
13169
13258
  projectId: r.projectId,
13170
13259
  runId: r.runId ?? null,
13171
13260
  overallCitedRate: Number(r.overallCitedRate),
13261
+ // Legacy rows (persisted before v80) have NULL mention columns → 0.
13262
+ overallMentionRate: r.overallMentionRate == null ? 0 : Number(r.overallMentionRate),
13172
13263
  totalPairs: r.totalPairs,
13173
13264
  citedPairs: r.citedPairs,
13174
- providerBreakdown: r.providerBreakdown,
13265
+ mentionedPairs: r.mentionedPairs ?? 0,
13266
+ providerBreakdown,
13175
13267
  createdAt: r.createdAt,
13176
13268
  status: "ready"
13177
13269
  };
@@ -32779,6 +32871,9 @@ function serializeProbe(row) {
32779
32871
  bucket: bucketParsed?.success ? bucketParsed.data : null,
32780
32872
  citationState: stateParsed.success ? stateParsed.data : "not-cited",
32781
32873
  citedDomains: row.citedDomains,
32874
+ // Boolean-mode column already reads back as boolean | null; a legacy row
32875
+ // written before the column is null (unknown), never coerced to false.
32876
+ answerMentioned: row.answerMentioned ?? null,
32782
32877
  createdAt: row.createdAt
32783
32878
  };
32784
32879
  }
@@ -32895,6 +32990,7 @@ async function executeDiscovery(opts) {
32895
32990
  query,
32896
32991
  bucket,
32897
32992
  citationState: probe.citationState,
32993
+ answerMentioned: probe.answerMentioned,
32898
32994
  citedDomains: probe.citedDomains,
32899
32995
  rawResponse: JSON.stringify(probe.rawResponse),
32900
32996
  createdAt: (/* @__PURE__ */ new Date()).toISOString()
@@ -34111,8 +34207,10 @@ var IntelligenceService = class {
34111
34207
  projectId,
34112
34208
  runId,
34113
34209
  overallCitedRate: String(result.health.overallCitedRate),
34210
+ overallMentionRate: String(result.health.overallMentionRate),
34114
34211
  totalPairs: result.health.totalPairs,
34115
34212
  citedPairs: result.health.citedPairs,
34213
+ mentionedPairs: result.health.mentionedPairs,
34116
34214
  providerBreakdown: result.health.providerBreakdown,
34117
34215
  createdAt: now
34118
34216
  }).run();
@@ -34217,6 +34315,7 @@ var IntelligenceService = class {
34217
34315
  queryText: querySnapshots.queryText,
34218
34316
  provider: querySnapshots.provider,
34219
34317
  citationState: querySnapshots.citationState,
34318
+ answerMentioned: querySnapshots.answerMentioned,
34220
34319
  citedDomains: querySnapshots.citedDomains,
34221
34320
  competitorOverlap: querySnapshots.competitorOverlap,
34222
34321
  snapshotLocation: querySnapshots.location
@@ -34235,6 +34334,10 @@ var IntelligenceService = class {
34235
34334
  query: resolvedQuery,
34236
34335
  provider: r.provider,
34237
34336
  cited: r.citationState === CitationStates.cited,
34337
+ // Independent answer-text signal. Tri-state passes through untouched
34338
+ // (true / false / null = "not checked"); computeHealth counts only
34339
+ // exact `true`. Never coerce null→false here.
34340
+ answerMentioned: r.answerMentioned,
34238
34341
  // The project's OWN cited domain — never a co-cited competitor that
34239
34342
  // happens to sort first in the full citedDomains set.
34240
34343
  citationUrl: pickProjectCitedDomain(domains, projectDomains),
@@ -23,7 +23,7 @@ import {
23
23
  trafficConnectVercelRequestSchema,
24
24
  trafficConnectWordpressRequestSchema,
25
25
  trafficEventKindSchema
26
- } from "./chunk-KPSFRSS7.js";
26
+ } from "./chunk-BNF3HXBW.js";
27
27
 
28
28
  // src/config.ts
29
29
  import fs from "fs";
package/dist/cli.js CHANGED
@@ -27,7 +27,7 @@ import {
27
27
  setTelemetrySource,
28
28
  showFirstRunNotice,
29
29
  trackEvent
30
- } from "./chunk-NSZ3D3MM.js";
30
+ } from "./chunk-M3IYKTSF.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-JLAD6CYH.js";
47
+ } from "./chunk-Y3O3HBMN.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-IEUTAQUF.js";
55
+ } from "./chunk-VJBO4VIK.js";
56
56
  import {
57
57
  BacklinkSources,
58
58
  CcReleaseSyncStatuses,
@@ -76,7 +76,7 @@ import {
76
76
  providerQuotaPolicySchema,
77
77
  resolveProviderInput,
78
78
  winnabilityClassSchema
79
- } from "./chunk-KPSFRSS7.js";
79
+ } from "./chunk-BNF3HXBW.js";
80
80
 
81
81
  // src/cli.ts
82
82
  import { pathToFileURL } from "url";
@@ -1902,11 +1902,12 @@ function printSessionDetail(session) {
1902
1902
  if (session.probes && session.probes.length > 0) {
1903
1903
  const sorted = [...session.probes].sort((a, b) => (a.bucket ?? "").localeCompare(b.bucket ?? ""));
1904
1904
  console.log(`
1905
- Probes (${session.probes.length}):`);
1905
+ Probes (${session.probes.length}): (cell = [citation][mention]; C=cited c=not, M=mentioned m=not, \u2013=no data)`);
1906
1906
  for (const p of sorted) {
1907
1907
  const bucket = (p.bucket ?? "\u2013").padEnd(15);
1908
- const cit = p.citationState === "cited" ? "C" : "c";
1909
- console.log(` [${cit}] ${bucket} ${p.query}`);
1908
+ const citationGlyph = p.citationState === CitationStates.cited ? "C" : "c";
1909
+ const mentionGlyph = typeof p.answerMentioned === "boolean" ? p.answerMentioned ? "M" : "m" : "\u2013";
1910
+ console.log(` [${citationGlyph}${mentionGlyph}] ${bucket} ${p.query}`);
1910
1911
  }
1911
1912
  }
1912
1913
  }
@@ -9246,13 +9247,15 @@ async function showHealth(project, opts) {
9246
9247
  console.log("No health history available.");
9247
9248
  return;
9248
9249
  }
9249
- console.log("Date Cited Rate Cited/Total");
9250
- console.log("\u2500".repeat(55));
9250
+ console.log("Date Mention Rate Mentioned/Total Cited Rate Cited/Total");
9251
+ console.log("\u2500".repeat(86));
9251
9252
  for (const snap of snapshots) {
9252
- const rate2 = (snap.overallCitedRate * 100).toFixed(1).padStart(5) + "%";
9253
- const ratio = `${snap.citedPairs}/${snap.totalPairs}`;
9253
+ const mRate = (snap.overallMentionRate * 100).toFixed(1).padStart(5) + "%";
9254
+ const mRatio = `${snap.mentionedPairs}/${snap.totalPairs}`.padEnd(15);
9255
+ const cRate = (snap.overallCitedRate * 100).toFixed(1).padStart(5) + "%";
9256
+ const cRatio = `${snap.citedPairs}/${snap.totalPairs}`;
9254
9257
  const date = snap.createdAt.slice(0, 19).padEnd(25);
9255
- console.log(`${date} ${rate2} ${ratio}`);
9258
+ console.log(`${date} ${mRate} ${mRatio} ${cRate} ${cRatio}`);
9256
9259
  }
9257
9260
  return;
9258
9261
  }
@@ -9265,14 +9268,17 @@ async function showHealth(project, opts) {
9265
9268
  console.log("No health data yet \u2014 run a sweep first (canonry run <project>).");
9266
9269
  return;
9267
9270
  }
9268
- const rate = (health.overallCitedRate * 100).toFixed(1);
9269
- console.log(`Health: ${rate}% cited (${health.citedPairs}/${health.totalPairs} pairs)`);
9271
+ const mentionRate = (health.overallMentionRate * 100).toFixed(1);
9272
+ const citedRate = (health.overallCitedRate * 100).toFixed(1);
9273
+ console.log(`Health: ${mentionRate}% mentioned (${health.mentionedPairs}/${health.totalPairs} pairs)`);
9274
+ console.log(` ${citedRate}% cited (${health.citedPairs}/${health.totalPairs} pairs)`);
9270
9275
  console.log("");
9271
9276
  if (health.providerBreakdown && Object.keys(health.providerBreakdown).length > 0) {
9272
9277
  console.log("Provider Breakdown:");
9273
9278
  for (const [provider, stats] of Object.entries(health.providerBreakdown)) {
9274
- const pRate = (stats.citedRate * 100).toFixed(1);
9275
- console.log(` ${provider.padEnd(15)} ${pRate}% (${stats.cited}/${stats.total})`);
9279
+ const pMention = (stats.mentionRate * 100).toFixed(1);
9280
+ const pCited = (stats.citedRate * 100).toFixed(1);
9281
+ console.log(` ${provider.padEnd(15)} ${pMention}% mentioned (${stats.mentioned}/${stats.total}) ${pCited}% cited (${stats.cited}/${stats.total})`);
9276
9282
  }
9277
9283
  }
9278
9284
  }
package/dist/index.js CHANGED
@@ -1,11 +1,11 @@
1
1
  import {
2
2
  createServer
3
- } from "./chunk-NSZ3D3MM.js";
3
+ } from "./chunk-M3IYKTSF.js";
4
4
  import {
5
5
  loadConfig
6
- } from "./chunk-JLAD6CYH.js";
7
- import "./chunk-IEUTAQUF.js";
8
- import "./chunk-KPSFRSS7.js";
6
+ } from "./chunk-Y3O3HBMN.js";
7
+ import "./chunk-VJBO4VIK.js";
8
+ import "./chunk-BNF3HXBW.js";
9
9
  export {
10
10
  createServer,
11
11
  loadConfig
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  IntelligenceService
3
- } from "./chunk-IEUTAQUF.js";
4
- import "./chunk-KPSFRSS7.js";
3
+ } from "./chunk-VJBO4VIK.js";
4
+ import "./chunk-BNF3HXBW.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-JLAD6CYH.js";
6
+ } from "./chunk-Y3O3HBMN.js";
7
7
  import {
8
8
  isReadOnlyKey
9
- } from "./chunk-KPSFRSS7.js";
9
+ } from "./chunk-BNF3HXBW.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.82.0",
3
+ "version": "4.84.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",
@@ -36,7 +36,7 @@
36
36
  "node": ">=22.14.0"
37
37
  },
38
38
  "dependencies": {
39
- "@ainyc/aeo-audit": "3.0.0",
39
+ "@ainyc/aeo-audit": "4.0.1",
40
40
  "@anthropic-ai/sdk": "^0.91.1",
41
41
  "@fastify/static": "^9.1.1",
42
42
  "@google/genai": "^1.46.0",
@@ -62,27 +62,27 @@
62
62
  "@types/node-cron": "^3.0.11",
63
63
  "tsup": "^8.5.1",
64
64
  "tsx": "^4.19.0",
65
- "@ainyc/canonry-api-routes": "0.0.0",
66
65
  "@ainyc/canonry-api-client": "0.0.0",
67
- "@ainyc/canonry-config": "0.0.0",
68
66
  "@ainyc/canonry-db": "0.0.0",
67
+ "@ainyc/canonry-api-routes": "0.0.0",
69
68
  "@ainyc/canonry-contracts": "0.0.0",
69
+ "@ainyc/canonry-config": "0.0.0",
70
70
  "@ainyc/canonry-integration-bing": "0.0.0",
71
- "@ainyc/canonry-integration-openai-ads": "0.0.0",
72
71
  "@ainyc/canonry-integration-cloud-run": "0.0.0",
72
+ "@ainyc/canonry-integration-openai-ads": "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-integration-traffic": "0.0.0",
78
77
  "@ainyc/canonry-intelligence": "0.0.0",
78
+ "@ainyc/canonry-integration-traffic": "0.0.0",
79
+ "@ainyc/canonry-provider-claude": "0.0.0",
79
80
  "@ainyc/canonry-provider-cdp": "0.0.0",
80
81
  "@ainyc/canonry-integration-wordpress": "0.0.0",
81
- "@ainyc/canonry-provider-claude": "0.0.0",
82
82
  "@ainyc/canonry-provider-gemini": "0.0.0",
83
+ "@ainyc/canonry-provider-openai": "0.0.0",
83
84
  "@ainyc/canonry-provider-local": "0.0.0",
84
- "@ainyc/canonry-provider-perplexity": "0.0.0",
85
- "@ainyc/canonry-provider-openai": "0.0.0"
85
+ "@ainyc/canonry-provider-perplexity": "0.0.0"
86
86
  },
87
87
  "scripts": {
88
88
  "build": "tsx scripts/copy-agent-assets.ts && tsup && tsx build-web.ts",