@ainyc/canonry 4.86.0 → 4.87.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/assets/{BacklinksPage-BNrvc-gV.js → BacklinksPage-BPvsw_Bi.js} +1 -1
- package/assets/assets/{ChartPrimitives-BlIkdUdy.js → ChartPrimitives-BdlKCq7y.js} +1 -1
- package/assets/assets/ProjectPage-1Q8YC9Vd.js +6 -0
- package/assets/assets/{RunRow-CAPnKzi7.js → RunRow-DcSsnE5c.js} +1 -1
- package/assets/assets/{RunsPage-idnuzKBn.js → RunsPage-DKoIMkQL.js} +1 -1
- package/assets/assets/{SettingsPage-Bka67uJq.js → SettingsPage-bH3PdNKb.js} +1 -1
- package/assets/assets/{TrafficPage-C_o-rA5o.js → TrafficPage-IW_DX-0V.js} +1 -1
- package/assets/assets/{TrafficSourceDetailPage-D_jvoSTV.js → TrafficSourceDetailPage-DRHOGn9B.js} +1 -1
- package/assets/assets/{arrow-left-B-JfzARi.js → arrow-left-B5Du72nk.js} +1 -1
- package/assets/assets/{extract-error-message-BhPbjIX6.js → extract-error-message-C7Vhd5zH.js} +1 -1
- package/assets/assets/{index-uPSrDA8e.js → index-C_ZzKZfM.js} +107 -107
- package/assets/assets/index-ClkRAeHL.css +1 -0
- package/assets/assets/{trash-2-BbRvn40h.js → trash-2-DWcofmpv.js} +1 -1
- package/assets/index.html +2 -2
- package/dist/{chunk-DLBQU3VG.js → chunk-5LW7CJAO.js} +184 -52
- package/dist/{chunk-LLJPZKHG.js → chunk-6XMXBAEW.js} +2 -2
- package/dist/{chunk-SELXBOAP.js → chunk-DUDFNP5Y.js} +4 -4
- package/dist/{chunk-23HGQV22.js → chunk-MDRDX5R2.js} +197 -0
- package/dist/cli.js +14 -9
- package/dist/index.js +4 -4
- package/dist/{intelligence-service-ZHUJKZRO.js → intelligence-service-XUKYOHKL.js} +2 -2
- package/dist/mcp.js +2 -2
- package/package.json +9 -9
- package/assets/assets/ProjectPage-CAyx_xNr.js +0 -6
- package/assets/assets/index-BgWgJE7S.css +0 -1
|
@@ -170,6 +170,7 @@ import {
|
|
|
170
170
|
missingDependency,
|
|
171
171
|
normalizeProjectAliases,
|
|
172
172
|
normalizeProjectDomain,
|
|
173
|
+
normalizeQueryText,
|
|
173
174
|
normalizeUrlPath,
|
|
174
175
|
notFound,
|
|
175
176
|
notImplemented,
|
|
@@ -180,6 +181,7 @@ import {
|
|
|
180
181
|
pickClusterRepresentative,
|
|
181
182
|
projectConfigSchema,
|
|
182
183
|
projectDtoSchema,
|
|
184
|
+
projectOverviewDtoSchema,
|
|
183
185
|
projectReportDtoSchema,
|
|
184
186
|
projectUpsertRequestSchema,
|
|
185
187
|
providerError,
|
|
@@ -253,7 +255,7 @@ import {
|
|
|
253
255
|
wordpressSchemaDeployResultDtoSchema,
|
|
254
256
|
wordpressSchemaStatusResultDtoSchema,
|
|
255
257
|
wordpressStatusDtoSchema
|
|
256
|
-
} from "./chunk-
|
|
258
|
+
} from "./chunk-MDRDX5R2.js";
|
|
257
259
|
|
|
258
260
|
// src/intelligence-service.ts
|
|
259
261
|
import { eq as eq37, desc as desc18, asc as asc5, and as and27, ne as ne5, or as or5, inArray as inArray14, gte as gte7, lte as lte4 } from "drizzle-orm";
|
|
@@ -4532,35 +4534,101 @@ function buildAiSourceOrigin(snapshots, projectDomains, competitorDomains, topDo
|
|
|
4532
4534
|
|
|
4533
4535
|
// ../intelligence/src/movement-summary.ts
|
|
4534
4536
|
function buildMovementSummary(currentSnapshots, previousSnapshots, options = {}) {
|
|
4537
|
+
return buildSignalMovementSummary(
|
|
4538
|
+
currentSnapshots,
|
|
4539
|
+
previousSnapshots,
|
|
4540
|
+
(snapshot) => snapshot.citationState === CitationStates.cited,
|
|
4541
|
+
options
|
|
4542
|
+
);
|
|
4543
|
+
}
|
|
4544
|
+
function buildCitationMovementSummary(currentSnapshots, previousSnapshots, options = {}) {
|
|
4545
|
+
return buildMovementSummary(currentSnapshots, previousSnapshots, options);
|
|
4546
|
+
}
|
|
4547
|
+
function buildMentionMovementSummary(currentSnapshots, previousSnapshots, options = {}) {
|
|
4548
|
+
return buildSignalMovementSummary(
|
|
4549
|
+
currentSnapshots,
|
|
4550
|
+
previousSnapshots,
|
|
4551
|
+
(snapshot) => snapshot.answerMentioned === true,
|
|
4552
|
+
options
|
|
4553
|
+
);
|
|
4554
|
+
}
|
|
4555
|
+
function buildMovementComparison(currentSnapshots, previousSnapshots, options = {}) {
|
|
4556
|
+
const currentIds = collectQueryIds(currentSnapshots);
|
|
4557
|
+
const previousIds = collectQueryIds(previousSnapshots);
|
|
4558
|
+
const hasPreviousRun = previousSnapshots.length > 0;
|
|
4559
|
+
if (!hasPreviousRun) {
|
|
4560
|
+
return {
|
|
4561
|
+
hasPreviousRun: false,
|
|
4562
|
+
comparable: false,
|
|
4563
|
+
querySetChanged: false,
|
|
4564
|
+
previousRunAt: null,
|
|
4565
|
+
currentQueryCount: currentIds.size,
|
|
4566
|
+
previousQueryCount: 0,
|
|
4567
|
+
comparableQueryCount: 0,
|
|
4568
|
+
addedQueryCount: 0,
|
|
4569
|
+
removedQueryCount: 0,
|
|
4570
|
+
addedQueries: [],
|
|
4571
|
+
removedQueries: []
|
|
4572
|
+
};
|
|
4573
|
+
}
|
|
4574
|
+
const comparableIds = intersection(currentIds, previousIds);
|
|
4575
|
+
const addedIds = difference(currentIds, previousIds);
|
|
4576
|
+
const removedIds = difference(previousIds, currentIds);
|
|
4577
|
+
const querySetChanged = addedIds.size > 0 || removedIds.size > 0;
|
|
4578
|
+
return {
|
|
4579
|
+
hasPreviousRun: true,
|
|
4580
|
+
comparable: !querySetChanged && currentIds.size > 0,
|
|
4581
|
+
querySetChanged,
|
|
4582
|
+
previousRunAt: options.previousRunAt ?? null,
|
|
4583
|
+
currentQueryCount: currentIds.size,
|
|
4584
|
+
previousQueryCount: previousIds.size,
|
|
4585
|
+
comparableQueryCount: comparableIds.size,
|
|
4586
|
+
addedQueryCount: addedIds.size,
|
|
4587
|
+
removedQueryCount: removedIds.size,
|
|
4588
|
+
addedQueries: resolveQueryTexts(addedIds, options.queryLookup),
|
|
4589
|
+
removedQueries: resolveQueryTexts(removedIds, options.queryLookup)
|
|
4590
|
+
};
|
|
4591
|
+
}
|
|
4592
|
+
function buildSignalMovementSummary(currentSnapshots, previousSnapshots, isActive, options) {
|
|
4535
4593
|
if (previousSnapshots.length === 0) {
|
|
4536
|
-
const
|
|
4537
|
-
const citedCount = citedIds.size;
|
|
4538
|
-
const tone2 = citedCount > 0 ? "positive" : "neutral";
|
|
4594
|
+
const activeIds = collectActiveQueryIds(currentSnapshots, isActive);
|
|
4539
4595
|
return withQueryLists(
|
|
4540
|
-
{
|
|
4541
|
-
|
|
4596
|
+
{
|
|
4597
|
+
gained: activeIds.size,
|
|
4598
|
+
lost: 0,
|
|
4599
|
+
tone: activeIds.size > 0 ? "positive" : "neutral",
|
|
4600
|
+
hasPreviousRun: false
|
|
4601
|
+
},
|
|
4602
|
+
activeIds,
|
|
4542
4603
|
/* @__PURE__ */ new Set(),
|
|
4543
4604
|
options.queryLookup
|
|
4544
4605
|
);
|
|
4545
4606
|
}
|
|
4546
|
-
const
|
|
4547
|
-
|
|
4548
|
-
|
|
4549
|
-
|
|
4550
|
-
|
|
4551
|
-
|
|
4552
|
-
|
|
4553
|
-
|
|
4554
|
-
if (!latestCited.has(id)) lostIds.add(id);
|
|
4555
|
-
}
|
|
4556
|
-
const tone = lostIds.size > gainedIds.size ? "negative" : gainedIds.size > lostIds.size ? "positive" : "neutral";
|
|
4607
|
+
const comparableIds = intersection(
|
|
4608
|
+
collectQueryIds(currentSnapshots),
|
|
4609
|
+
collectQueryIds(previousSnapshots)
|
|
4610
|
+
);
|
|
4611
|
+
const currentActive = intersection(collectActiveQueryIds(currentSnapshots, isActive), comparableIds);
|
|
4612
|
+
const previousActive = intersection(collectActiveQueryIds(previousSnapshots, isActive), comparableIds);
|
|
4613
|
+
const gainedIds = difference(currentActive, previousActive);
|
|
4614
|
+
const lostIds = difference(previousActive, currentActive);
|
|
4557
4615
|
return withQueryLists(
|
|
4558
|
-
{
|
|
4616
|
+
{
|
|
4617
|
+
gained: gainedIds.size,
|
|
4618
|
+
lost: lostIds.size,
|
|
4619
|
+
tone: movementTone(gainedIds.size, lostIds.size),
|
|
4620
|
+
hasPreviousRun: true
|
|
4621
|
+
},
|
|
4559
4622
|
gainedIds,
|
|
4560
4623
|
lostIds,
|
|
4561
4624
|
options.queryLookup
|
|
4562
4625
|
);
|
|
4563
4626
|
}
|
|
4627
|
+
function movementTone(gained, lost) {
|
|
4628
|
+
if (lost > gained) return "negative";
|
|
4629
|
+
if (gained > lost) return "positive";
|
|
4630
|
+
return "neutral";
|
|
4631
|
+
}
|
|
4564
4632
|
function withQueryLists(base, gainedIds, lostIds, lookup) {
|
|
4565
4633
|
if (!lookup) return base;
|
|
4566
4634
|
return {
|
|
@@ -4570,6 +4638,7 @@ function withQueryLists(base, gainedIds, lostIds, lookup) {
|
|
|
4570
4638
|
};
|
|
4571
4639
|
}
|
|
4572
4640
|
function resolveQueryTexts(ids, lookup) {
|
|
4641
|
+
if (!lookup) return [];
|
|
4573
4642
|
const out = [];
|
|
4574
4643
|
for (const id of ids) {
|
|
4575
4644
|
const text2 = lookup.get(id);
|
|
@@ -4577,12 +4646,33 @@ function resolveQueryTexts(ids, lookup) {
|
|
|
4577
4646
|
}
|
|
4578
4647
|
return out.sort();
|
|
4579
4648
|
}
|
|
4580
|
-
function
|
|
4581
|
-
const
|
|
4582
|
-
for (const
|
|
4583
|
-
if (
|
|
4649
|
+
function collectQueryIds(snapshots) {
|
|
4650
|
+
const ids = /* @__PURE__ */ new Set();
|
|
4651
|
+
for (const snapshot of snapshots) {
|
|
4652
|
+
if (snapshot.queryId) ids.add(snapshot.queryId);
|
|
4653
|
+
}
|
|
4654
|
+
return ids;
|
|
4655
|
+
}
|
|
4656
|
+
function collectActiveQueryIds(snapshots, isActive) {
|
|
4657
|
+
const active = /* @__PURE__ */ new Set();
|
|
4658
|
+
for (const snapshot of snapshots) {
|
|
4659
|
+
if (snapshot.queryId && isActive(snapshot)) active.add(snapshot.queryId);
|
|
4584
4660
|
}
|
|
4585
|
-
return
|
|
4661
|
+
return active;
|
|
4662
|
+
}
|
|
4663
|
+
function intersection(left, right) {
|
|
4664
|
+
const out = /* @__PURE__ */ new Set();
|
|
4665
|
+
for (const value of left) {
|
|
4666
|
+
if (right.has(value)) out.add(value);
|
|
4667
|
+
}
|
|
4668
|
+
return out;
|
|
4669
|
+
}
|
|
4670
|
+
function difference(left, right) {
|
|
4671
|
+
const out = /* @__PURE__ */ new Set();
|
|
4672
|
+
for (const value of left) {
|
|
4673
|
+
if (!right.has(value)) out.add(value);
|
|
4674
|
+
}
|
|
4675
|
+
return out;
|
|
4586
4676
|
}
|
|
4587
4677
|
|
|
4588
4678
|
// ../intelligence/src/score-tones.ts
|
|
@@ -5027,12 +5117,12 @@ var DEFAULT_LIMIT = 10;
|
|
|
5027
5117
|
function buildSuggestedQueries(gscRows, options) {
|
|
5028
5118
|
const minImpressions = options.minImpressions ?? DEFAULT_MIN_IMPRESSIONS;
|
|
5029
5119
|
const limit = options.limit ?? DEFAULT_LIMIT;
|
|
5030
|
-
const trackedSet = new Set(options.trackedQueries.map(
|
|
5120
|
+
const trackedSet = new Set(options.trackedQueries.map(normalizeQueryText));
|
|
5031
5121
|
let skippedAlreadyTracked = 0;
|
|
5032
5122
|
const candidates = [];
|
|
5033
5123
|
for (const row of gscRows) {
|
|
5034
5124
|
if (row.impressions < minImpressions) continue;
|
|
5035
|
-
const normalized =
|
|
5125
|
+
const normalized = normalizeQueryText(row.query);
|
|
5036
5126
|
if (normalized.length === 0) continue;
|
|
5037
5127
|
if (trackedSet.has(normalized)) {
|
|
5038
5128
|
skippedAlreadyTracked++;
|
|
@@ -5054,9 +5144,6 @@ function buildSuggestedQueries(gscRows, options) {
|
|
|
5054
5144
|
skippedAlreadyTracked
|
|
5055
5145
|
};
|
|
5056
5146
|
}
|
|
5057
|
-
function normalizeQuery(value) {
|
|
5058
|
-
return value.trim().toLowerCase();
|
|
5059
|
-
}
|
|
5060
5147
|
function buildReason(row) {
|
|
5061
5148
|
const impressionsLabel = formatImpressions2(row.impressions);
|
|
5062
5149
|
if (row.avgPosition <= 10) {
|
|
@@ -12924,18 +13011,31 @@ async function compositeRoutes(app) {
|
|
|
12924
13011
|
const snapshotRunIds = new Set(sparklineRunIds);
|
|
12925
13012
|
for (const run of latestVisRunGroup) snapshotRunIds.add(run.id);
|
|
12926
13013
|
for (const run of previousVisRunGroup) snapshotRunIds.add(run.id);
|
|
12927
|
-
const
|
|
13014
|
+
const projectQueries = app.db.select({ id: queries.id, query: queries.query }).from(queries).where(eq17(queries.projectId, project.id)).all();
|
|
13015
|
+
const queryIdByText = new Map(projectQueries.map((q) => [normalizeQueryText(q.query), q.id]));
|
|
13016
|
+
const snapshotsByRun = loadSnapshotsByRunIds(app, [...snapshotRunIds], queryIdByText);
|
|
12928
13017
|
const latestSnapshots = latestVisRunGroup.flatMap((r) => snapshotsByRun.get(r.id) ?? []);
|
|
12929
13018
|
const previousSnapshots = previousVisRunGroup.flatMap((r) => snapshotsByRun.get(r.id) ?? []);
|
|
12930
|
-
const
|
|
13019
|
+
const trackedLatest = latestSnapshots.filter((s) => !s.archived);
|
|
13020
|
+
const trackedPrevious = previousSnapshots.filter((s) => !s.archived);
|
|
13021
|
+
const trackedSnapshotsByRun = new Map(
|
|
13022
|
+
[...snapshotsByRun].map(([runId, snaps]) => [runId, snaps.filter((s) => !s.archived)])
|
|
13023
|
+
);
|
|
13024
|
+
const { queryCounts, providers } = summarizeFromSnapshots(trackedLatest);
|
|
12931
13025
|
const transitions = summarizeTransitionsFromSnapshots(
|
|
12932
|
-
|
|
12933
|
-
|
|
13026
|
+
trackedLatest,
|
|
13027
|
+
trackedPrevious,
|
|
12934
13028
|
previousVisibilityRun?.createdAt ?? null
|
|
12935
13029
|
);
|
|
12936
13030
|
const competitorRows = app.db.select().from(competitors).where(eq17(competitors.projectId, project.id)).all();
|
|
12937
|
-
const projectQueries = app.db.select({ id: queries.id, query: queries.query }).from(queries).where(eq17(queries.projectId, project.id)).all();
|
|
12938
13031
|
const queryLookup = { byId: new Map(projectQueries.map((q) => [q.id, q.query])) };
|
|
13032
|
+
for (const snapshots of snapshotsByRun.values()) {
|
|
13033
|
+
for (const snapshot of snapshots) {
|
|
13034
|
+
if (snapshot.queryText && !queryLookup.byId.has(snapshot.queryId)) {
|
|
13035
|
+
queryLookup.byId.set(snapshot.queryId, snapshot.queryText);
|
|
13036
|
+
}
|
|
13037
|
+
}
|
|
13038
|
+
}
|
|
12939
13039
|
const configuredApiProviders = project.providers.filter((p) => !p.startsWith("cdp:"));
|
|
12940
13040
|
const mentionShareCompetitors = competitorRows.map((c) => ({
|
|
12941
13041
|
domain: c.domain,
|
|
@@ -12945,32 +13045,39 @@ async function compositeRoutes(app) {
|
|
|
12945
13045
|
brandTokens: [brandLabelFromDomain(c.domain)].filter((t) => t.length >= 3)
|
|
12946
13046
|
}));
|
|
12947
13047
|
const scores = {
|
|
12948
|
-
mention: buildMentionCoverage(
|
|
12949
|
-
visibility: buildVisibilityScore(
|
|
13048
|
+
mention: buildMentionCoverage(trackedLatest, { configuredApiProviders }),
|
|
13049
|
+
visibility: buildVisibilityScore(trackedLatest, { configuredApiProviders }),
|
|
12950
13050
|
mentionShare: buildMentionShare(
|
|
12951
|
-
|
|
13051
|
+
trackedLatest.map((s) => ({
|
|
12952
13052
|
projectMentioned: s.answerMentioned === true,
|
|
12953
13053
|
answerText: s.answerText
|
|
12954
13054
|
})),
|
|
12955
13055
|
{ competitors: mentionShareCompetitors }
|
|
12956
13056
|
),
|
|
12957
|
-
gapQueries: buildGapQueryScore(
|
|
12958
|
-
mentionGaps: buildMentionGapScore(
|
|
13057
|
+
gapQueries: buildGapQueryScore(trackedLatest),
|
|
13058
|
+
mentionGaps: buildMentionGapScore(trackedLatest),
|
|
12959
13059
|
indexCoverage: buildIndexCoverageScore(app, project.id),
|
|
12960
13060
|
competitorPressure: buildCompetitorPressureScore(
|
|
12961
|
-
|
|
13061
|
+
trackedLatest,
|
|
12962
13062
|
competitorRows.map((c) => c.domain),
|
|
12963
13063
|
competitorRows.length
|
|
12964
13064
|
),
|
|
12965
13065
|
runStatus: buildRunStatusScore(allRuns)
|
|
12966
13066
|
};
|
|
12967
|
-
const
|
|
13067
|
+
const citationMovement = buildCitationMovementSummary(latestSnapshots, previousSnapshots, {
|
|
12968
13068
|
queryLookup: queryLookup.byId
|
|
12969
13069
|
});
|
|
12970
|
-
const
|
|
13070
|
+
const mentionMovement = buildMentionMovementSummary(latestSnapshots, previousSnapshots, {
|
|
13071
|
+
queryLookup: queryLookup.byId
|
|
13072
|
+
});
|
|
13073
|
+
const movementComparison = buildMovementComparison(latestSnapshots, previousSnapshots, {
|
|
13074
|
+
queryLookup: queryLookup.byId,
|
|
13075
|
+
previousRunAt: previousVisibilityRun?.createdAt ?? null
|
|
13076
|
+
});
|
|
13077
|
+
const providerScoresBase = buildProviderScores(trackedLatest);
|
|
12971
13078
|
const providerTrends = buildProviderTrends(
|
|
12972
13079
|
visibilityRuns.slice(0, DEFAULT_RUN_HISTORY_LIMIT).map((r) => ({ id: r.id, createdAt: r.createdAt })),
|
|
12973
|
-
|
|
13080
|
+
trackedSnapshotsByRun,
|
|
12974
13081
|
DEFAULT_RUN_HISTORY_LIMIT
|
|
12975
13082
|
);
|
|
12976
13083
|
const providerScores = providerScoresBase.map((score) => {
|
|
@@ -12978,13 +13085,13 @@ async function compositeRoutes(app) {
|
|
|
12978
13085
|
return trend.length > 1 ? { ...score, trend: trend.map((p) => p.rate) } : score;
|
|
12979
13086
|
});
|
|
12980
13087
|
const overviewCompetitors = buildOverviewCompetitors(
|
|
12981
|
-
|
|
13088
|
+
trackedLatest,
|
|
12982
13089
|
competitorRows.map((c) => ({ id: c.id, domain: c.domain })),
|
|
12983
13090
|
queryLookup
|
|
12984
13091
|
);
|
|
12985
13092
|
const attentionItems = buildAttentionItems(insightRows, allRuns);
|
|
12986
13093
|
const sparklineRuns = visibilityRuns.slice(0, DEFAULT_RUN_HISTORY_LIMIT).map((r) => ({ id: r.id, createdAt: r.createdAt, status: r.status }));
|
|
12987
|
-
const runHistory = buildRunHistory(sparklineRuns,
|
|
13094
|
+
const runHistory = buildRunHistory(sparklineRuns, trackedSnapshotsByRun);
|
|
12988
13095
|
scores.mention.trend = runHistory.map((p) => p.mentionRate);
|
|
12989
13096
|
scores.visibility.trend = runHistory.map((p) => p.citationRate);
|
|
12990
13097
|
const suggestedQueries = buildSuggestedQueriesFromGsc(
|
|
@@ -13001,7 +13108,12 @@ async function compositeRoutes(app) {
|
|
|
13001
13108
|
providers,
|
|
13002
13109
|
transitions,
|
|
13003
13110
|
scores,
|
|
13004
|
-
|
|
13111
|
+
// Keep the legacy citation-only field for API compatibility. New
|
|
13112
|
+
// consumers read the explicitly named siblings below.
|
|
13113
|
+
movementSummary: citationMovement,
|
|
13114
|
+
citationMovement,
|
|
13115
|
+
mentionMovement,
|
|
13116
|
+
movementComparison,
|
|
13005
13117
|
competitors: overviewCompetitors,
|
|
13006
13118
|
providerScores,
|
|
13007
13119
|
attentionItems,
|
|
@@ -13111,12 +13223,13 @@ function summarizeRun(run) {
|
|
|
13111
13223
|
createdAt: run.createdAt
|
|
13112
13224
|
};
|
|
13113
13225
|
}
|
|
13114
|
-
function loadSnapshotsByRunIds(app, runIds) {
|
|
13226
|
+
function loadSnapshotsByRunIds(app, runIds, queryIdByText) {
|
|
13115
13227
|
const result = /* @__PURE__ */ new Map();
|
|
13116
13228
|
if (runIds.length === 0) return result;
|
|
13117
|
-
const rows =
|
|
13229
|
+
const rows = app.db.select({
|
|
13118
13230
|
runId: querySnapshots.runId,
|
|
13119
13231
|
queryId: querySnapshots.queryId,
|
|
13232
|
+
queryText: querySnapshots.queryText,
|
|
13120
13233
|
provider: querySnapshots.provider,
|
|
13121
13234
|
model: querySnapshots.model,
|
|
13122
13235
|
citationState: querySnapshots.citationState,
|
|
@@ -13124,11 +13237,30 @@ function loadSnapshotsByRunIds(app, runIds) {
|
|
|
13124
13237
|
answerText: querySnapshots.answerText,
|
|
13125
13238
|
competitorOverlap: querySnapshots.competitorOverlap,
|
|
13126
13239
|
citedDomains: querySnapshots.citedDomains
|
|
13127
|
-
}).from(querySnapshots).where(inArray9(querySnapshots.runId, [...runIds])).all()
|
|
13240
|
+
}).from(querySnapshots).where(inArray9(querySnapshots.runId, [...runIds])).all();
|
|
13128
13241
|
for (const row of rows) {
|
|
13242
|
+
const queryText = row.queryText?.trim() || null;
|
|
13243
|
+
let queryId;
|
|
13244
|
+
let archived = false;
|
|
13245
|
+
if (row.queryId) {
|
|
13246
|
+
queryId = row.queryId;
|
|
13247
|
+
} else if (queryText) {
|
|
13248
|
+
const tracked = queryIdByText.get(normalizeQueryText(queryText));
|
|
13249
|
+
if (tracked) {
|
|
13250
|
+
queryId = tracked;
|
|
13251
|
+
} else {
|
|
13252
|
+
queryId = `archived:${normalizeQueryText(queryText)}`;
|
|
13253
|
+
archived = true;
|
|
13254
|
+
}
|
|
13255
|
+
} else {
|
|
13256
|
+
queryId = null;
|
|
13257
|
+
}
|
|
13258
|
+
if (!queryId) continue;
|
|
13129
13259
|
const list = result.get(row.runId) ?? [];
|
|
13130
13260
|
list.push({
|
|
13131
|
-
queryId
|
|
13261
|
+
queryId,
|
|
13262
|
+
queryText,
|
|
13263
|
+
archived,
|
|
13132
13264
|
provider: row.provider,
|
|
13133
13265
|
model: row.model,
|
|
13134
13266
|
citationState: row.citationState,
|
|
@@ -13618,6 +13750,7 @@ var SCHEMA_TABLE = {
|
|
|
13618
13750
|
LocationContext: locationContextSchema,
|
|
13619
13751
|
NotificationDto: notificationDtoSchema,
|
|
13620
13752
|
ProjectDto: projectDtoSchema,
|
|
13753
|
+
ProjectOverviewDto: projectOverviewDtoSchema,
|
|
13621
13754
|
ProjectReportDto: projectReportDtoSchema,
|
|
13622
13755
|
QueryDto: queryDtoSchema,
|
|
13623
13756
|
RunDetailDto: runDetailDtoSchema,
|
|
@@ -16851,12 +16984,11 @@ var routeCatalog = [
|
|
|
16851
16984
|
method: "get",
|
|
16852
16985
|
path: "/api/v1/projects/{name}/overview",
|
|
16853
16986
|
summary: "Get a composite overview of project health",
|
|
16854
|
-
description: 'Bundles project info, latest run, top undismissed insights,
|
|
16987
|
+
description: 'Bundles project info, latest run, top undismissed insights, health, independent mention and citation coverage, query-basket comparability, and separate mention/citation movement over the shared query cohort. Designed for the "how is project X doing?" question so agents can answer in one call.',
|
|
16855
16988
|
tags: ["intelligence"],
|
|
16856
16989
|
parameters: [nameParameter],
|
|
16857
16990
|
responses: {
|
|
16858
|
-
|
|
16859
|
-
200: rawJsonResponse("Overview returned.", looseObjectSchema),
|
|
16991
|
+
200: jsonResponse("Overview returned.", "ProjectOverviewDto"),
|
|
16860
16992
|
404: errorResponse("Project not found.")
|
|
16861
16993
|
}
|
|
16862
16994
|
},
|
|
@@ -23,7 +23,7 @@ import {
|
|
|
23
23
|
trafficConnectVercelRequestSchema,
|
|
24
24
|
trafficConnectWordpressRequestSchema,
|
|
25
25
|
trafficEventKindSchema
|
|
26
|
-
} from "./chunk-
|
|
26
|
+
} from "./chunk-MDRDX5R2.js";
|
|
27
27
|
|
|
28
28
|
// src/config.ts
|
|
29
29
|
import fs from "fs";
|
|
@@ -5597,7 +5597,7 @@ var canonryMcpTools = [
|
|
|
5597
5597
|
defineTool({
|
|
5598
5598
|
name: "canonry_project_overview",
|
|
5599
5599
|
title: "Get project overview (composite)",
|
|
5600
|
-
description: 'One-call summary for "how is project X doing?"
|
|
5600
|
+
description: 'One-call summary for "how is project X doing?". Returns independent mention and citation coverage, separate query-level movement for each signal, query-basket comparability with added/removed counts, latest run and health, insights, provider/model breakdowns, competitors, attention items, and recent history. Movement excludes queries not shared by both sweeps. Filterable by location and time window. Prefer this over fanning out to separate tools.',
|
|
5601
5601
|
access: "read",
|
|
5602
5602
|
tier: "core",
|
|
5603
5603
|
inputSchema: z2.object({
|
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
loadConfig,
|
|
10
10
|
loadConfigRaw,
|
|
11
11
|
saveConfigPatch
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-6XMXBAEW.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-5LW7CJAO.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-MDRDX5R2.js";
|
|
164
164
|
|
|
165
165
|
// src/telemetry.ts
|
|
166
166
|
import crypto from "crypto";
|
|
@@ -6289,7 +6289,7 @@ function readStoredGroundingSources(rawResponse) {
|
|
|
6289
6289
|
return result;
|
|
6290
6290
|
}
|
|
6291
6291
|
async function backfillInsightsCommand(project, opts) {
|
|
6292
|
-
const { IntelligenceService: IntelligenceService2 } = await import("./intelligence-service-
|
|
6292
|
+
const { IntelligenceService: IntelligenceService2 } = await import("./intelligence-service-XUKYOHKL.js");
|
|
6293
6293
|
const config = loadConfig();
|
|
6294
6294
|
const db = createClient(config.database);
|
|
6295
6295
|
migrate(db);
|
|
@@ -3163,6 +3163,196 @@ var ccCachedReleaseSchema = z23.object({
|
|
|
3163
3163
|
|
|
3164
3164
|
// ../contracts/src/composites.ts
|
|
3165
3165
|
import { z as z24 } from "zod";
|
|
3166
|
+
var metricToneSchema = z24.enum(["positive", "caution", "negative", "neutral"]);
|
|
3167
|
+
var scoreSummarySchema = z24.object({
|
|
3168
|
+
label: z24.string(),
|
|
3169
|
+
value: z24.string(),
|
|
3170
|
+
delta: z24.string(),
|
|
3171
|
+
tone: metricToneSchema,
|
|
3172
|
+
description: z24.string(),
|
|
3173
|
+
tooltip: z24.string().optional(),
|
|
3174
|
+
trend: z24.array(z24.number()),
|
|
3175
|
+
progress: z24.number().optional(),
|
|
3176
|
+
providerCoverage: z24.string().optional()
|
|
3177
|
+
});
|
|
3178
|
+
var mentionShareSchema = scoreSummarySchema.extend({
|
|
3179
|
+
breakdown: z24.object({
|
|
3180
|
+
projectMentionSnapshots: z24.number().int().nonnegative(),
|
|
3181
|
+
competitorMentionSnapshots: z24.number().int().nonnegative(),
|
|
3182
|
+
perCompetitor: z24.array(z24.object({
|
|
3183
|
+
domain: z24.string(),
|
|
3184
|
+
mentionSnapshots: z24.number().int().nonnegative(),
|
|
3185
|
+
shareOfCompetitiveTotal: z24.number()
|
|
3186
|
+
})),
|
|
3187
|
+
snapshotsWithAnswerText: z24.number().int().nonnegative(),
|
|
3188
|
+
snapshotsTotal: z24.number().int().nonnegative()
|
|
3189
|
+
})
|
|
3190
|
+
});
|
|
3191
|
+
var movementSummarySchema = z24.object({
|
|
3192
|
+
gained: z24.number().int().nonnegative(),
|
|
3193
|
+
lost: z24.number().int().nonnegative(),
|
|
3194
|
+
tone: metricToneSchema,
|
|
3195
|
+
hasPreviousRun: z24.boolean(),
|
|
3196
|
+
gainedQueries: z24.array(z24.string()).optional(),
|
|
3197
|
+
lostQueries: z24.array(z24.string()).optional()
|
|
3198
|
+
});
|
|
3199
|
+
var movementComparisonSchema = z24.object({
|
|
3200
|
+
hasPreviousRun: z24.boolean(),
|
|
3201
|
+
comparable: z24.boolean(),
|
|
3202
|
+
querySetChanged: z24.boolean(),
|
|
3203
|
+
previousRunAt: z24.string().nullable(),
|
|
3204
|
+
currentQueryCount: z24.number().int().nonnegative(),
|
|
3205
|
+
previousQueryCount: z24.number().int().nonnegative(),
|
|
3206
|
+
comparableQueryCount: z24.number().int().nonnegative(),
|
|
3207
|
+
addedQueryCount: z24.number().int().nonnegative(),
|
|
3208
|
+
removedQueryCount: z24.number().int().nonnegative(),
|
|
3209
|
+
addedQueries: z24.array(z24.string()),
|
|
3210
|
+
removedQueries: z24.array(z24.string())
|
|
3211
|
+
});
|
|
3212
|
+
var projectOverviewInsightSchema = z24.object({
|
|
3213
|
+
id: z24.string(),
|
|
3214
|
+
projectId: z24.string(),
|
|
3215
|
+
runId: z24.string().nullable(),
|
|
3216
|
+
type: z24.enum([
|
|
3217
|
+
"regression",
|
|
3218
|
+
"gain",
|
|
3219
|
+
"opportunity",
|
|
3220
|
+
"first-citation",
|
|
3221
|
+
"provider-pickup",
|
|
3222
|
+
"persistent-gap",
|
|
3223
|
+
"competitor-gained",
|
|
3224
|
+
"competitor-lost",
|
|
3225
|
+
"gbp-lodging-gap",
|
|
3226
|
+
"gbp-listing-discrepancy",
|
|
3227
|
+
"gbp-cta-gap",
|
|
3228
|
+
"gbp-metric-drop",
|
|
3229
|
+
"gbp-keyword-drop"
|
|
3230
|
+
]),
|
|
3231
|
+
severity: z24.enum(["critical", "high", "medium", "low"]),
|
|
3232
|
+
title: z24.string(),
|
|
3233
|
+
query: z24.string(),
|
|
3234
|
+
provider: z24.string(),
|
|
3235
|
+
recommendation: z24.object({
|
|
3236
|
+
action: z24.string(),
|
|
3237
|
+
target: z24.string().optional(),
|
|
3238
|
+
reason: z24.string()
|
|
3239
|
+
}).optional(),
|
|
3240
|
+
cause: z24.object({
|
|
3241
|
+
cause: z24.string(),
|
|
3242
|
+
competitorDomain: z24.string().optional(),
|
|
3243
|
+
details: z24.string().optional()
|
|
3244
|
+
}).optional(),
|
|
3245
|
+
dismissed: z24.boolean(),
|
|
3246
|
+
createdAt: z24.string()
|
|
3247
|
+
});
|
|
3248
|
+
var projectOverviewHealthSchema = z24.object({
|
|
3249
|
+
id: z24.string(),
|
|
3250
|
+
projectId: z24.string(),
|
|
3251
|
+
runId: z24.string().nullable(),
|
|
3252
|
+
overallCitedRate: z24.number(),
|
|
3253
|
+
overallMentionRate: z24.number(),
|
|
3254
|
+
totalPairs: z24.number().int().nonnegative(),
|
|
3255
|
+
citedPairs: z24.number().int().nonnegative(),
|
|
3256
|
+
mentionedPairs: z24.number().int().nonnegative(),
|
|
3257
|
+
providerBreakdown: z24.record(z24.string(), z24.object({
|
|
3258
|
+
citedRate: z24.number(),
|
|
3259
|
+
mentionRate: z24.number(),
|
|
3260
|
+
cited: z24.number().int().nonnegative(),
|
|
3261
|
+
mentioned: z24.number().int().nonnegative(),
|
|
3262
|
+
total: z24.number().int().nonnegative()
|
|
3263
|
+
})),
|
|
3264
|
+
createdAt: z24.string(),
|
|
3265
|
+
status: z24.enum(["ready", "no-data"]),
|
|
3266
|
+
reason: z24.literal("no-runs-yet").optional()
|
|
3267
|
+
});
|
|
3268
|
+
var projectOverviewDtoSchema = z24.object({
|
|
3269
|
+
project: projectDtoSchema,
|
|
3270
|
+
latestRun: latestProjectRunDtoSchema,
|
|
3271
|
+
health: projectOverviewHealthSchema.nullable(),
|
|
3272
|
+
topInsights: z24.array(projectOverviewInsightSchema),
|
|
3273
|
+
queryCounts: z24.object({
|
|
3274
|
+
totalQueries: z24.number().int().nonnegative(),
|
|
3275
|
+
citedQueries: z24.number().int().nonnegative(),
|
|
3276
|
+
notCitedQueries: z24.number().int().nonnegative(),
|
|
3277
|
+
citedRate: z24.number(),
|
|
3278
|
+
mentionedQueries: z24.number().int().nonnegative(),
|
|
3279
|
+
notMentionedQueries: z24.number().int().nonnegative(),
|
|
3280
|
+
mentionRate: z24.number()
|
|
3281
|
+
}),
|
|
3282
|
+
providers: z24.array(z24.object({
|
|
3283
|
+
provider: z24.string(),
|
|
3284
|
+
citedRate: z24.number(),
|
|
3285
|
+
cited: z24.number().int().nonnegative(),
|
|
3286
|
+
total: z24.number().int().nonnegative()
|
|
3287
|
+
})),
|
|
3288
|
+
transitions: z24.object({
|
|
3289
|
+
since: z24.string().nullable(),
|
|
3290
|
+
gained: z24.number().int().nonnegative(),
|
|
3291
|
+
lost: z24.number().int().nonnegative(),
|
|
3292
|
+
emerging: z24.number().int().nonnegative()
|
|
3293
|
+
}),
|
|
3294
|
+
scores: z24.object({
|
|
3295
|
+
mention: scoreSummarySchema,
|
|
3296
|
+
visibility: scoreSummarySchema,
|
|
3297
|
+
mentionShare: mentionShareSchema,
|
|
3298
|
+
gapQueries: scoreSummarySchema,
|
|
3299
|
+
mentionGaps: scoreSummarySchema,
|
|
3300
|
+
indexCoverage: scoreSummarySchema,
|
|
3301
|
+
competitorPressure: scoreSummarySchema,
|
|
3302
|
+
runStatus: scoreSummarySchema
|
|
3303
|
+
}),
|
|
3304
|
+
movementSummary: movementSummarySchema,
|
|
3305
|
+
citationMovement: movementSummarySchema,
|
|
3306
|
+
mentionMovement: movementSummarySchema,
|
|
3307
|
+
movementComparison: movementComparisonSchema,
|
|
3308
|
+
competitors: z24.array(z24.object({
|
|
3309
|
+
id: z24.string(),
|
|
3310
|
+
domain: z24.string(),
|
|
3311
|
+
citationCount: z24.number().int().nonnegative(),
|
|
3312
|
+
totalQueries: z24.number().int().nonnegative(),
|
|
3313
|
+
pressureLabel: z24.enum(["None", "Low", "Moderate", "High"]),
|
|
3314
|
+
citedQueries: z24.array(z24.string())
|
|
3315
|
+
})),
|
|
3316
|
+
providerScores: z24.array(z24.object({
|
|
3317
|
+
provider: z24.string(),
|
|
3318
|
+
model: z24.string().nullable(),
|
|
3319
|
+
score: z24.number(),
|
|
3320
|
+
cited: z24.number().int().nonnegative(),
|
|
3321
|
+
total: z24.number().int().nonnegative(),
|
|
3322
|
+
trend: z24.array(z24.number()).optional()
|
|
3323
|
+
})),
|
|
3324
|
+
attentionItems: z24.array(z24.object({
|
|
3325
|
+
id: z24.string(),
|
|
3326
|
+
tone: metricToneSchema,
|
|
3327
|
+
title: z24.string(),
|
|
3328
|
+
detail: z24.string(),
|
|
3329
|
+
actionLabel: z24.string(),
|
|
3330
|
+
href: z24.string()
|
|
3331
|
+
})),
|
|
3332
|
+
runHistory: z24.array(z24.object({
|
|
3333
|
+
runId: z24.string(),
|
|
3334
|
+
createdAt: z24.string(),
|
|
3335
|
+
citedCount: z24.number().int().nonnegative(),
|
|
3336
|
+
totalCount: z24.number().int().nonnegative(),
|
|
3337
|
+
citationRate: z24.number(),
|
|
3338
|
+
mentionedCount: z24.number().int().nonnegative(),
|
|
3339
|
+
mentionRate: z24.number(),
|
|
3340
|
+
status: z24.string()
|
|
3341
|
+
})),
|
|
3342
|
+
suggestedQueries: z24.object({
|
|
3343
|
+
rows: z24.array(z24.object({
|
|
3344
|
+
query: z24.string(),
|
|
3345
|
+
impressions: z24.number(),
|
|
3346
|
+
clicks: z24.number(),
|
|
3347
|
+
avgPosition: z24.number(),
|
|
3348
|
+
reason: z24.string()
|
|
3349
|
+
})),
|
|
3350
|
+
totalCandidates: z24.number().int().nonnegative(),
|
|
3351
|
+
skippedAlreadyTracked: z24.number().int().nonnegative()
|
|
3352
|
+
}),
|
|
3353
|
+
dateRangeLabel: z24.string(),
|
|
3354
|
+
contextLabel: z24.string()
|
|
3355
|
+
});
|
|
3166
3356
|
var searchHitKindSchema = z24.enum(["snapshot", "insight"]);
|
|
3167
3357
|
var projectSearchSnapshotHitSchema = z24.object({
|
|
3168
3358
|
kind: z24.literal("snapshot"),
|
|
@@ -3533,6 +3723,11 @@ function summarizeCheckResults(results) {
|
|
|
3533
3723
|
return summary;
|
|
3534
3724
|
}
|
|
3535
3725
|
|
|
3726
|
+
// ../contracts/src/query-normalize.ts
|
|
3727
|
+
function normalizeQueryText(value) {
|
|
3728
|
+
return value.trim().toLowerCase();
|
|
3729
|
+
}
|
|
3730
|
+
|
|
3536
3731
|
// ../contracts/src/citations.ts
|
|
3537
3732
|
import { z as z27 } from "zod";
|
|
3538
3733
|
var citationCoverageProviderSchema = z27.object({
|
|
@@ -5029,6 +5224,7 @@ export {
|
|
|
5029
5224
|
backlinksInstallResultDtoSchema,
|
|
5030
5225
|
ccAvailableReleaseSchema,
|
|
5031
5226
|
ccCachedReleaseSchema,
|
|
5227
|
+
projectOverviewDtoSchema,
|
|
5032
5228
|
ContentActions,
|
|
5033
5229
|
contentActionLabel,
|
|
5034
5230
|
actionConfidenceLabel,
|
|
@@ -5052,6 +5248,7 @@ export {
|
|
|
5052
5248
|
CheckCategories,
|
|
5053
5249
|
doctorReportSchema,
|
|
5054
5250
|
summarizeCheckResults,
|
|
5251
|
+
normalizeQueryText,
|
|
5055
5252
|
citationVisibilityResponseSchema,
|
|
5056
5253
|
emptyCitationVisibility,
|
|
5057
5254
|
citationStateToCited,
|