@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.
- package/assets/agent-workspace/skills/aero/SKILL.md +14 -10
- package/assets/agent-workspace/skills/aero/references/aeo-discovery.md +7 -5
- package/assets/agent-workspace/skills/aero/references/memory-patterns.md +1 -1
- package/assets/agent-workspace/skills/aero/references/orchestration.md +22 -20
- package/assets/agent-workspace/skills/aero/references/regression-playbook.md +9 -9
- package/assets/agent-workspace/skills/aero/references/reporting.md +14 -9
- package/assets/agent-workspace/skills/aero/soul.md +5 -5
- package/assets/agent-workspace/skills/canonry/SKILL.md +1 -1
- package/assets/agent-workspace/skills/canonry/references/aeo-analysis.md +84 -36
- package/assets/agent-workspace/skills/canonry/references/canonry-cli.md +25 -10
- package/assets/assets/{BacklinksPage-CHclt-pq.js → BacklinksPage-OrSg_iPA.js} +1 -1
- package/assets/assets/{ChartPrimitives-2Ub4vNWe.js → ChartPrimitives-DPBhAT_r.js} +1 -1
- package/assets/assets/{ProjectPage-UPmHfuxR.js → ProjectPage-CpMcEmtw.js} +1 -1
- package/assets/assets/{RunRow-rUL1UeA3.js → RunRow-2Rty0BAH.js} +1 -1
- package/assets/assets/{RunsPage-BQpHfUJf.js → RunsPage-B3ahqf8s.js} +1 -1
- package/assets/assets/{SettingsPage-DjTJlr_1.js → SettingsPage-BIjeI85q.js} +1 -1
- package/assets/assets/{TrafficPage-D7rv3BrH.js → TrafficPage-DjGoj691.js} +1 -1
- package/assets/assets/{TrafficSourceDetailPage-BysyuH2H.js → TrafficSourceDetailPage-BgKG-2q3.js} +1 -1
- package/assets/assets/{arrow-left-CR_FGlkE.js → arrow-left-Cf7wmru1.js} +1 -1
- package/assets/assets/{extract-error-message-BKkAbWNp.js → extract-error-message-CANxezte.js} +1 -1
- package/assets/assets/{index-DzzTt20n.js → index-CGlPx_cu.js} +3 -3
- package/assets/assets/{trash-2-uSttujvh.js → trash-2-6nHJZrvy.js} +1 -1
- package/assets/index.html +1 -1
- package/dist/{chunk-KPSFRSS7.js → chunk-BNF3HXBW.js} +5 -0
- package/dist/{chunk-NSZ3D3MM.js → chunk-M3IYKTSF.js} +17 -4
- package/dist/{chunk-IEUTAQUF.js → chunk-VJBO4VIK.js} +108 -5
- package/dist/{chunk-JLAD6CYH.js → chunk-Y3O3HBMN.js} +1 -1
- package/dist/cli.js +22 -16
- package/dist/index.js +4 -4
- package/dist/{intelligence-service-2UUJ3YGI.js → intelligence-service-PDIAMP5I.js} +2 -2
- package/dist/mcp.js +2 -2
- 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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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),
|
package/dist/cli.js
CHANGED
|
@@ -27,7 +27,7 @@ import {
|
|
|
27
27
|
setTelemetrySource,
|
|
28
28
|
showFirstRunNotice,
|
|
29
29
|
trackEvent
|
|
30
|
-
} from "./chunk-
|
|
30
|
+
} from "./chunk-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-
|
|
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-
|
|
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-
|
|
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
|
|
1909
|
-
|
|
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(
|
|
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
|
|
9253
|
-
const
|
|
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} ${
|
|
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
|
|
9269
|
-
|
|
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
|
|
9275
|
-
|
|
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-
|
|
3
|
+
} from "./chunk-M3IYKTSF.js";
|
|
4
4
|
import {
|
|
5
5
|
loadConfig
|
|
6
|
-
} from "./chunk-
|
|
7
|
-
import "./chunk-
|
|
8
|
-
import "./chunk-
|
|
6
|
+
} from "./chunk-Y3O3HBMN.js";
|
|
7
|
+
import "./chunk-VJBO4VIK.js";
|
|
8
|
+
import "./chunk-BNF3HXBW.js";
|
|
9
9
|
export {
|
|
10
10
|
createServer,
|
|
11
11
|
loadConfig
|
package/dist/mcp.js
CHANGED
|
@@ -3,10 +3,10 @@ import {
|
|
|
3
3
|
PACKAGE_VERSION,
|
|
4
4
|
canonryMcpTools,
|
|
5
5
|
createApiClient
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-Y3O3HBMN.js";
|
|
7
7
|
import {
|
|
8
8
|
isReadOnlyKey
|
|
9
|
-
} from "./chunk-
|
|
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.
|
|
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": "
|
|
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",
|