@ainyc/canonry 4.27.0 → 4.27.1

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.
@@ -1960,6 +1960,33 @@ function migrate(db) {
1960
1960
  }
1961
1961
  }
1962
1962
 
1963
+ // ../db/src/run-helpers.ts
1964
+ function groupRunsByCreatedAt(rows) {
1965
+ const groups = [];
1966
+ let current = [];
1967
+ let currentCreatedAt = null;
1968
+ for (const row of rows) {
1969
+ if (row.createdAt === currentCreatedAt) {
1970
+ current.push(row);
1971
+ } else {
1972
+ if (current.length > 0) groups.push(current);
1973
+ current = [row];
1974
+ currentCreatedAt = row.createdAt;
1975
+ }
1976
+ }
1977
+ if (current.length > 0) groups.push(current);
1978
+ return groups;
1979
+ }
1980
+ function pickGroupRepresentative(group) {
1981
+ if (group.length === 0) return null;
1982
+ let best = group[0];
1983
+ for (let i = 1; i < group.length; i++) {
1984
+ const candidate = group[i];
1985
+ if (candidate.id > best.id) best = candidate;
1986
+ }
1987
+ return best;
1988
+ }
1989
+
1963
1990
  // ../intelligence/src/regressions.ts
1964
1991
  function detectRegressions(currentRun, previousRun) {
1965
1992
  const regressions = [];
@@ -3560,20 +3587,49 @@ var IntelligenceService = class {
3560
3587
  const key = row.query.toLowerCase();
3561
3588
  gscImpressionsByQuery.set(key, (gscImpressionsByQuery.get(key) ?? 0) + row.impressions);
3562
3589
  }
3563
- const recentRunIds = this.db.select({ id: runs.id }).from(runs).where(
3590
+ const projectRow = this.db.select({ locations: projects.locations }).from(projects).where(eq(projects.id, projectId)).get();
3591
+ const locationCount = Math.max(
3592
+ 1,
3593
+ parseJsonColumn(projectRow?.locations ?? null, []).length
3594
+ );
3595
+ const ROWS_PER_GROUP_BUDGET = Math.max(2, locationCount);
3596
+ const recentRunRows = this.db.select({ id: runs.id, createdAt: runs.createdAt }).from(runs).where(
3564
3597
  and(
3565
3598
  eq(runs.projectId, projectId),
3566
3599
  eq(runs.kind, RunKinds["answer-visibility"]),
3567
3600
  or(eq(runs.status, "completed"), eq(runs.status, "partial"))
3568
3601
  )
3569
- ).orderBy(desc(runs.createdAt)).limit(RECURRENCE_LOOKBACK_RUNS + 1).all().map((r) => r.id).filter((id) => id !== excludeRunId).slice(0, RECURRENCE_LOOKBACK_RUNS);
3602
+ ).orderBy(desc(runs.createdAt), desc(runs.id)).limit((RECURRENCE_LOOKBACK_RUNS + 1) * ROWS_PER_GROUP_BUDGET).all();
3603
+ const recentGroups = groupRunsByCreatedAt(recentRunRows);
3604
+ const recentRunIds = [];
3605
+ const recentRunIdToCreatedAt = /* @__PURE__ */ new Map();
3606
+ let consumedGroups = 0;
3607
+ for (const group of recentGroups) {
3608
+ const groupIds = group.map((r) => r.id);
3609
+ if (groupIds.includes(excludeRunId)) continue;
3610
+ for (const r of group) recentRunIdToCreatedAt.set(r.id, r.createdAt);
3611
+ recentRunIds.push(...groupIds);
3612
+ consumedGroups++;
3613
+ if (consumedGroups >= RECURRENCE_LOOKBACK_RUNS) break;
3614
+ }
3570
3615
  const haveHistory = recentRunIds.length > 0;
3571
3616
  const priorRegressionsByPair = /* @__PURE__ */ new Map();
3572
3617
  if (haveHistory) {
3573
- const priorRows = this.db.select({ query: insights.query, provider: insights.provider }).from(insights).where(and(eq(insights.type, "regression"), inArray(insights.runId, recentRunIds))).all();
3618
+ const priorRows = this.db.select({ query: insights.query, provider: insights.provider, runId: insights.runId }).from(insights).where(and(eq(insights.type, "regression"), inArray(insights.runId, recentRunIds))).all();
3619
+ const regressionGroups = /* @__PURE__ */ new Map();
3574
3620
  for (const row of priorRows) {
3621
+ if (!row.runId) continue;
3575
3622
  const key = `${row.query}:${row.provider}`;
3576
- priorRegressionsByPair.set(key, (priorRegressionsByPair.get(key) ?? 0) + 1);
3623
+ const groupKey = recentRunIdToCreatedAt.get(row.runId) ?? row.runId;
3624
+ let groups = regressionGroups.get(key);
3625
+ if (!groups) {
3626
+ groups = /* @__PURE__ */ new Set();
3627
+ regressionGroups.set(key, groups);
3628
+ }
3629
+ groups.add(groupKey);
3630
+ }
3631
+ for (const [key, groups] of regressionGroups) {
3632
+ priorRegressionsByPair.set(key, groups.size);
3577
3633
  }
3578
3634
  }
3579
3635
  return rawInsights.map((insight) => {
@@ -3649,6 +3705,8 @@ export {
3649
3705
  extractLegacyCredentials,
3650
3706
  dropLegacyCredentialColumns,
3651
3707
  migrate,
3708
+ groupRunsByCreatedAt,
3709
+ pickGroupRepresentative,
3652
3710
  isBlogShapedQuery,
3653
3711
  buildInventory,
3654
3712
  buildContentTargetRows,
@@ -50,6 +50,7 @@ import {
50
50
  gaTrafficSummaries,
51
51
  gaTrafficWindowSummaries,
52
52
  groupInsights,
53
+ groupRunsByCreatedAt,
53
54
  gscCoverageSnapshots,
54
55
  gscSearchData,
55
56
  gscUrlInspections,
@@ -60,6 +61,7 @@ import {
60
61
  mapOpportunitiesToNextSteps,
61
62
  notifications,
62
63
  parseJsonColumn,
64
+ pickGroupRepresentative,
63
65
  projects,
64
66
  queries,
65
67
  querySnapshots,
@@ -68,7 +70,7 @@ import {
68
70
  schedules,
69
71
  trafficSources,
70
72
  usageCounters
71
- } from "./chunk-PN24DAGC.js";
73
+ } from "./chunk-NXXD6TX7.js";
72
74
  import {
73
75
  AGENT_MEMORY_VALUE_MAX_BYTES,
74
76
  AGENT_PROVIDER_IDS,
@@ -2317,12 +2319,16 @@ async function analyticsRoutes(app) {
2317
2319
  const project = resolveProject(app.db, request.params.name);
2318
2320
  const window = parseWindow(request.query.window);
2319
2321
  const cutoff = windowCutoff(window);
2320
- const latestRun = app.db.select().from(runs).where(eq10(runs.projectId, project.id)).orderBy(desc3(runs.createdAt)).all().find((r) => r.status === "completed" || r.status === "partial");
2322
+ const completedRuns = app.db.select().from(runs).where(eq10(runs.projectId, project.id)).orderBy(desc3(runs.createdAt), desc3(runs.id)).all().filter((r) => r.status === "completed" || r.status === "partial");
2323
+ const latestGroup = groupRunsByCreatedAt(completedRuns)[0] ?? [];
2324
+ const latestGroupRunIds = latestGroup.map((r) => r.id);
2325
+ const latestRun = pickGroupRepresentative(latestGroup);
2321
2326
  if (!latestRun) {
2322
2327
  return reply.send({ cited: [], gap: [], uncited: [], mentionedQueries: [], mentionGap: [], notMentioned: [], runId: "", window });
2323
2328
  }
2324
2329
  const windowRuns = app.db.select().from(runs).where(eq10(runs.projectId, project.id)).orderBy(runs.createdAt).all().filter((r) => r.status === "completed" || r.status === "partial").filter((r) => !cutoff || r.createdAt >= cutoff);
2325
2330
  const windowRunIds = windowRuns.map((r) => r.id);
2331
+ const runIdToCreatedAt = new Map(windowRuns.map((r) => [r.id, r.createdAt]));
2326
2332
  const consistencyMap = /* @__PURE__ */ new Map();
2327
2333
  if (windowRunIds.length > 0) {
2328
2334
  const allWindowSnaps = app.db.select({
@@ -2333,14 +2339,15 @@ async function analyticsRoutes(app) {
2333
2339
  answerText: querySnapshots.answerText
2334
2340
  }).from(querySnapshots).where(inArray2(querySnapshots.runId, windowRunIds)).all();
2335
2341
  for (const s of allWindowSnaps) {
2342
+ const timePoint = runIdToCreatedAt.get(s.runId) ?? s.runId;
2336
2343
  let entry = consistencyMap.get(s.queryId);
2337
2344
  if (!entry) {
2338
2345
  entry = { citedRuns: /* @__PURE__ */ new Set(), totalRuns: /* @__PURE__ */ new Set(), mentionedRuns: /* @__PURE__ */ new Set() };
2339
2346
  consistencyMap.set(s.queryId, entry);
2340
2347
  }
2341
- entry.totalRuns.add(s.runId);
2342
- if (s.citationState === CitationStates.cited) entry.citedRuns.add(s.runId);
2343
- if (resolveSnapshotAnswerMentioned(s, project)) entry.mentionedRuns.add(s.runId);
2348
+ entry.totalRuns.add(timePoint);
2349
+ if (s.citationState === CitationStates.cited) entry.citedRuns.add(timePoint);
2350
+ if (resolveSnapshotAnswerMentioned(s, project)) entry.mentionedRuns.add(timePoint);
2344
2351
  }
2345
2352
  }
2346
2353
  const rawSnapshots = app.db.select({
@@ -2351,7 +2358,7 @@ async function analyticsRoutes(app) {
2351
2358
  answerMentioned: querySnapshots.answerMentioned,
2352
2359
  answerText: querySnapshots.answerText,
2353
2360
  competitorOverlap: querySnapshots.competitorOverlap
2354
- }).from(querySnapshots).leftJoin(queries, eq10(querySnapshots.queryId, queries.id)).where(eq10(querySnapshots.runId, latestRun.id)).all();
2361
+ }).from(querySnapshots).leftJoin(queries, eq10(querySnapshots.queryId, queries.id)).where(inArray2(querySnapshots.runId, latestGroupRunIds)).all();
2355
2362
  const snapshots = rawSnapshots.map((s) => ({
2356
2363
  ...s,
2357
2364
  resolvedMentioned: resolveSnapshotAnswerMentioned(s, project)
@@ -2435,11 +2442,12 @@ async function analyticsRoutes(app) {
2435
2442
  const project = resolveProject(app.db, request.params.name);
2436
2443
  const window = parseWindow(request.query.window);
2437
2444
  const cutoff = windowCutoff(window);
2438
- const windowRuns = app.db.select().from(runs).where(eq10(runs.projectId, project.id)).orderBy(desc3(runs.createdAt)).all().filter((r) => r.status === "completed" || r.status === "partial").filter((r) => !cutoff || r.createdAt >= cutoff);
2445
+ const windowRuns = app.db.select().from(runs).where(eq10(runs.projectId, project.id)).orderBy(desc3(runs.createdAt), desc3(runs.id)).all().filter((r) => r.status === "completed" || r.status === "partial").filter((r) => !cutoff || r.createdAt >= cutoff);
2439
2446
  if (windowRuns.length === 0) {
2440
2447
  return reply.send({ overall: [], byQuery: {}, runId: "", window });
2441
2448
  }
2442
- const latestRunId = windowRuns[0].id;
2449
+ const latestGroup = groupRunsByCreatedAt(windowRuns)[0] ?? [];
2450
+ const latestRunId = pickGroupRepresentative(latestGroup)?.id ?? windowRuns[0].id;
2443
2451
  const windowRunIds = windowRuns.map((r) => r.id);
2444
2452
  const snapshots = app.db.select({
2445
2453
  queryId: querySnapshots.queryId,
@@ -5317,7 +5325,11 @@ function categorizeQuery(query, projectDisplayName, canonicalDomain) {
5317
5325
  return categorizeQueryByIntent(query, buildBrandTokens(canonicalDomain, projectDisplayName));
5318
5326
  }
5319
5327
  function loadSnapshotsForRun(db, runId) {
5320
- const rows = db.select().from(querySnapshots).where(eq13(querySnapshots.runId, runId)).all();
5328
+ return loadSnapshotsForRunIds(db, [runId]);
5329
+ }
5330
+ function loadSnapshotsForRunIds(db, runIds) {
5331
+ if (runIds.length === 0) return [];
5332
+ const rows = db.select().from(querySnapshots).where(inArray4(querySnapshots.runId, [...runIds])).all();
5321
5333
  return rows.map((r) => ({
5322
5334
  id: r.id,
5323
5335
  runId: r.runId,
@@ -6436,13 +6448,15 @@ function buildWhatsChanged(input) {
6436
6448
  function buildProjectReport(db, projectName) {
6437
6449
  const project = resolveProject(db, projectName);
6438
6450
  const queryLookup = loadQueryLookup(db, project.id);
6439
- const allRuns = db.select().from(runs).where(eq13(runs.projectId, project.id)).orderBy(desc6(runs.createdAt)).all();
6451
+ const allRuns = db.select().from(runs).where(eq13(runs.projectId, project.id)).orderBy(desc6(runs.createdAt), desc6(runs.id)).all();
6440
6452
  const visibilityRuns = allRuns.filter((r) => r.kind === RunKinds["answer-visibility"]);
6441
- const latestRun = visibilityRuns.find(
6442
- (r) => r.status === RunStatuses.completed || r.status === RunStatuses.partial
6443
- ) ?? visibilityRuns[0];
6444
- const latestSnapshots = latestRun ? loadSnapshotsForRun(db, latestRun.id) : [];
6445
- const latestRunLocation = latestRun?.location ?? null;
6453
+ const completedVisRunGroups = groupRunsByCreatedAt(
6454
+ visibilityRuns.filter((r) => r.status === RunStatuses.completed || r.status === RunStatuses.partial)
6455
+ );
6456
+ const latestVisRunGroup = completedVisRunGroups[0] ?? [];
6457
+ const representativeLatestRun = pickGroupRepresentative(latestVisRunGroup) ?? visibilityRuns[0] ?? null;
6458
+ const latestSnapshots = loadSnapshotsForRunIds(db, latestVisRunGroup.map((r) => r.id));
6459
+ const latestRunLocation = representativeLatestRun?.location ?? null;
6446
6460
  const competitorRows = db.select().from(competitors).where(eq13(competitors.projectId, project.id)).all();
6447
6461
  const competitorDomains = competitorRows.map((c) => c.domain);
6448
6462
  const ownedDomains = parseJsonColumn(project.ownedDomains, []);
@@ -6509,7 +6523,7 @@ function buildProjectReport(db, projectName) {
6509
6523
  const previousPoint = citationsTrend.length >= 2 ? citationsTrend.at(-2) : null;
6510
6524
  let trend = "unknown";
6511
6525
  if (!trendBaseline && latestPoint) {
6512
- const latestRunOnTrend = latestRun?.id === latestPoint.runId;
6526
+ const latestRunOnTrend = representativeLatestRun?.id === latestPoint.runId;
6513
6527
  const currentRate = latestRunOnTrend ? latestPoint.citationRate : citationRate;
6514
6528
  const priorRate = latestRunOnTrend ? previousPoint?.citationRate : latestPoint.citationRate;
6515
6529
  if (priorRate !== void 0) {
@@ -6531,7 +6545,7 @@ function buildProjectReport(db, projectName) {
6531
6545
  const periodStart = citationsTrend[0]?.date ?? null;
6532
6546
  const periodEnd = citationsTrend.at(-1)?.date ?? null;
6533
6547
  const configuredLocations = parseJsonColumn(project.locations, []);
6534
- const reportLocation = buildLocationMeta(latestRun?.location ?? null, configuredLocations);
6548
+ const reportLocation = buildLocationMeta(representativeLatestRun?.location ?? null, configuredLocations);
6535
6549
  const providerLocationHandling = reportLocation ? buildProviderLocationHandling(citationScorecard.providers) : [];
6536
6550
  const executiveSummary = {
6537
6551
  citationRate,
@@ -6839,15 +6853,17 @@ async function compositeRoutes(app) {
6839
6853
  const project = resolveProject(app.db, request.params.name);
6840
6854
  const filterLocation = (request.query.location ?? "").trim() || null;
6841
6855
  const sinceIso = parseSinceFilter(request.query.since);
6842
- const allRunsRaw = app.db.select().from(runs).where(eq15(runs.projectId, project.id)).orderBy(desc7(runs.createdAt)).all();
6856
+ const allRunsRaw = app.db.select().from(runs).where(eq15(runs.projectId, project.id)).orderBy(desc7(runs.createdAt), desc7(runs.id)).all();
6843
6857
  const allRuns = allRunsRaw.filter((r) => runMatchesFilters(r, filterLocation, sinceIso));
6844
6858
  const totalRuns = allRuns.length;
6845
6859
  const visibilityRuns = allRuns.filter((r) => r.kind === RunKinds["answer-visibility"]);
6846
6860
  const completedVisRuns = visibilityRuns.filter(
6847
6861
  (r) => r.status === RunStatuses.completed || r.status === RunStatuses.partial
6848
6862
  );
6849
- const latestVisibilityRun = completedVisRuns[0] ?? null;
6850
- const previousVisibilityRun = completedVisRuns[1] ?? null;
6863
+ const visRunGroups = groupRunsByCreatedAt(completedVisRuns);
6864
+ const latestVisRunGroup = visRunGroups[0] ?? [];
6865
+ const previousVisRunGroup = visRunGroups[1] ?? [];
6866
+ const previousVisibilityRun = pickGroupRepresentative(previousVisRunGroup);
6851
6867
  const latestRunRow = allRuns[0] ?? null;
6852
6868
  const latestRun = latestRunRow ? { totalRuns, run: summarizeRun(latestRunRow) } : { totalRuns: 0, run: null };
6853
6869
  const healthRow = app.db.select().from(healthSnapshots).where(eq15(healthSnapshots.projectId, project.id)).orderBy(desc7(healthSnapshots.createdAt)).limit(1).get();
@@ -6856,11 +6872,11 @@ async function compositeRoutes(app) {
6856
6872
  const topInsights = insightRows.filter((row) => !row.dismissed).slice(0, TOP_INSIGHT_LIMIT).map(mapInsightRow2);
6857
6873
  const sparklineRunIds = visibilityRuns.slice(0, DEFAULT_RUN_HISTORY_LIMIT).map((r) => r.id);
6858
6874
  const snapshotRunIds = new Set(sparklineRunIds);
6859
- if (latestVisibilityRun) snapshotRunIds.add(latestVisibilityRun.id);
6860
- if (previousVisibilityRun) snapshotRunIds.add(previousVisibilityRun.id);
6875
+ for (const run of latestVisRunGroup) snapshotRunIds.add(run.id);
6876
+ for (const run of previousVisRunGroup) snapshotRunIds.add(run.id);
6861
6877
  const snapshotsByRun = loadSnapshotsByRunIds(app, [...snapshotRunIds]);
6862
- const latestSnapshots = latestVisibilityRun ? snapshotsByRun.get(latestVisibilityRun.id) ?? [] : [];
6863
- const previousSnapshots = previousVisibilityRun ? snapshotsByRun.get(previousVisibilityRun.id) ?? [] : [];
6878
+ const latestSnapshots = latestVisRunGroup.flatMap((r) => snapshotsByRun.get(r.id) ?? []);
6879
+ const previousSnapshots = previousVisRunGroup.flatMap((r) => snapshotsByRun.get(r.id) ?? []);
6864
6880
  const { queryCounts, providers } = summarizeFromSnapshots(latestSnapshots);
6865
6881
  const transitions = summarizeTransitionsFromSnapshots(
6866
6882
  latestSnapshots,
@@ -24656,7 +24672,7 @@ var Scheduler = class {
24656
24672
  };
24657
24673
 
24658
24674
  // src/notifier.ts
24659
- import { eq as eq35, desc as desc16, and as and22, or as or4 } from "drizzle-orm";
24675
+ import { eq as eq35, desc as desc16, and as and22, inArray as inArray8, or as or4 } from "drizzle-orm";
24660
24676
  import crypto31 from "crypto";
24661
24677
  var log10 = createLogger("Notifier");
24662
24678
  var Notifier = class {
@@ -24761,41 +24777,76 @@ var Notifier = class {
24761
24777
  }
24762
24778
  }
24763
24779
  computeTransitions(runId, projectId) {
24780
+ const thisRun = this.db.select().from(runs).where(eq35(runs.id, runId)).get();
24781
+ if (!thisRun) return [];
24782
+ const groupSiblings = this.db.select().from(runs).where(and22(
24783
+ eq35(runs.projectId, projectId),
24784
+ eq35(runs.kind, thisRun.kind),
24785
+ eq35(runs.createdAt, thisRun.createdAt)
24786
+ )).all();
24787
+ const stillPending = groupSiblings.some((r) => r.status === "queued" || r.status === "running");
24788
+ if (stillPending) return [];
24789
+ const completedPartialSiblings = groupSiblings.filter(
24790
+ (r) => r.status === "completed" || r.status === "partial"
24791
+ );
24792
+ if (completedPartialSiblings.length === 0) return [];
24793
+ const winner = completedPartialSiblings.reduce((best, candidate) => {
24794
+ const candFinish = candidate.finishedAt ?? "";
24795
+ const bestFinish = best.finishedAt ?? "";
24796
+ if (candFinish > bestFinish) return candidate;
24797
+ if (candFinish < bestFinish) return best;
24798
+ return candidate.id > best.id ? candidate : best;
24799
+ });
24800
+ if (winner.id !== runId) return [];
24801
+ const projectLocations = this.db.select({ locations: projects.locations }).from(projects).where(eq35(projects.id, projectId)).get();
24802
+ const locationCount = Math.max(
24803
+ 1,
24804
+ parseJsonColumn(projectLocations?.locations ?? null, []).length
24805
+ );
24806
+ const RECENT_FETCH_LIMIT = Math.max(8, locationCount * 4);
24764
24807
  const recentRuns = this.db.select().from(runs).where(
24765
24808
  and22(
24766
24809
  eq35(runs.projectId, projectId),
24810
+ eq35(runs.kind, thisRun.kind),
24767
24811
  or4(eq35(runs.status, "completed"), eq35(runs.status, "partial"))
24768
24812
  )
24769
- ).orderBy(desc16(runs.createdAt)).limit(2).all();
24770
- if (recentRuns.length < 2) return [];
24771
- const currentRunId = recentRuns[0].id;
24772
- const previousRunId = recentRuns[1].id;
24773
- if (currentRunId !== runId) return [];
24813
+ ).orderBy(desc16(runs.createdAt), desc16(runs.id)).limit(RECENT_FETCH_LIMIT).all();
24814
+ const groups = groupRunsByCreatedAt(recentRuns);
24815
+ const currentGroupIdx = groups.findIndex((g) => g[0]?.createdAt === thisRun.createdAt);
24816
+ if (currentGroupIdx < 0) return [];
24817
+ const currentGroup = groups[currentGroupIdx] ?? [];
24818
+ const previousGroup = groups[currentGroupIdx + 1] ?? [];
24819
+ if (currentGroup.length === 0 || previousGroup.length === 0) return [];
24820
+ const currentRunIds = currentGroup.map((r) => r.id);
24821
+ const previousRunIds = previousGroup.map((r) => r.id);
24774
24822
  const currentSnapshots = this.db.select({
24775
24823
  queryId: querySnapshots.queryId,
24776
24824
  query: queries.query,
24777
24825
  provider: querySnapshots.provider,
24826
+ location: querySnapshots.location,
24778
24827
  citationState: querySnapshots.citationState
24779
- }).from(querySnapshots).leftJoin(queries, eq35(querySnapshots.queryId, queries.id)).where(eq35(querySnapshots.runId, currentRunId)).all();
24828
+ }).from(querySnapshots).leftJoin(queries, eq35(querySnapshots.queryId, queries.id)).where(inArray8(querySnapshots.runId, currentRunIds)).all();
24780
24829
  const previousSnapshots = this.db.select({
24781
24830
  queryId: querySnapshots.queryId,
24782
24831
  provider: querySnapshots.provider,
24832
+ location: querySnapshots.location,
24783
24833
  citationState: querySnapshots.citationState
24784
- }).from(querySnapshots).where(eq35(querySnapshots.runId, previousRunId)).all();
24834
+ }).from(querySnapshots).where(inArray8(querySnapshots.runId, previousRunIds)).all();
24785
24835
  const prevMap = /* @__PURE__ */ new Map();
24786
24836
  for (const s of previousSnapshots) {
24787
- prevMap.set(`${s.queryId}:${s.provider}`, s.citationState);
24837
+ prevMap.set(`${s.queryId}:${s.provider}:${s.location ?? ""}`, s.citationState);
24788
24838
  }
24789
24839
  const transitions = [];
24790
24840
  for (const s of currentSnapshots) {
24791
- const key = `${s.queryId}:${s.provider}`;
24841
+ const key = `${s.queryId}:${s.provider}:${s.location ?? ""}`;
24792
24842
  const prevState = prevMap.get(key);
24793
24843
  if (prevState && prevState !== s.citationState) {
24794
24844
  transitions.push({
24795
24845
  query: s.query ?? s.queryId,
24796
24846
  from: prevState,
24797
24847
  to: s.citationState,
24798
- provider: s.provider
24848
+ provider: s.provider,
24849
+ location: s.location
24799
24850
  });
24800
24851
  }
24801
24852
  }
package/dist/cli.js CHANGED
@@ -20,7 +20,7 @@ import {
20
20
  setTelemetrySource,
21
21
  showFirstRunNotice,
22
22
  trackEvent
23
- } from "./chunk-M3HZAUWZ.js";
23
+ } from "./chunk-QNXGCQEM.js";
24
24
  import {
25
25
  CliError,
26
26
  EXIT_SYSTEM_ERROR,
@@ -49,7 +49,7 @@ import {
49
49
  queries,
50
50
  querySnapshots,
51
51
  runs
52
- } from "./chunk-PN24DAGC.js";
52
+ } from "./chunk-NXXD6TX7.js";
53
53
  import {
54
54
  CcReleaseSyncStatuses,
55
55
  CheckScopes,
@@ -621,7 +621,7 @@ function readStoredGroundingSources(rawResponse) {
621
621
  return result;
622
622
  }
623
623
  async function backfillInsightsCommand(project, opts) {
624
- const { IntelligenceService } = await import("./intelligence-service-VUBODIGG.js");
624
+ const { IntelligenceService } = await import("./intelligence-service-Z6QIELKP.js");
625
625
  const config = loadConfig();
626
626
  const db = createClient(config.database);
627
627
  migrate(db);
package/dist/index.js CHANGED
@@ -1,10 +1,10 @@
1
1
  import {
2
2
  createServer
3
- } from "./chunk-M3HZAUWZ.js";
3
+ } from "./chunk-QNXGCQEM.js";
4
4
  import {
5
5
  loadConfig
6
6
  } from "./chunk-2FAEQ56I.js";
7
- import "./chunk-PN24DAGC.js";
7
+ import "./chunk-NXXD6TX7.js";
8
8
  import "./chunk-HVW665A4.js";
9
9
  export {
10
10
  createServer,
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  IntelligenceService
3
- } from "./chunk-PN24DAGC.js";
3
+ } from "./chunk-NXXD6TX7.js";
4
4
  import "./chunk-HVW665A4.js";
5
5
  export {
6
6
  IntelligenceService
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ainyc/canonry",
3
- "version": "4.27.0",
3
+ "version": "4.27.1",
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",
@@ -63,19 +63,19 @@
63
63
  "@ainyc/canonry-config": "0.0.0",
64
64
  "@ainyc/canonry-contracts": "0.0.0",
65
65
  "@ainyc/canonry-db": "0.0.0",
66
- "@ainyc/canonry-integration-commoncrawl": "0.0.0",
66
+ "@ainyc/canonry-integration-bing": "0.0.0",
67
+ "@ainyc/canonry-integration-cloud-run": "0.0.0",
67
68
  "@ainyc/canonry-integration-google": "0.0.0",
68
69
  "@ainyc/canonry-intelligence": "0.0.0",
69
- "@ainyc/canonry-integration-cloud-run": "0.0.0",
70
+ "@ainyc/canonry-integration-commoncrawl": "0.0.0",
70
71
  "@ainyc/canonry-integration-traffic": "0.0.0",
71
- "@ainyc/canonry-integration-wordpress": "0.0.0",
72
72
  "@ainyc/canonry-provider-cdp": "0.0.0",
73
+ "@ainyc/canonry-integration-wordpress": "0.0.0",
73
74
  "@ainyc/canonry-provider-claude": "0.0.0",
74
- "@ainyc/canonry-integration-bing": "0.0.0",
75
- "@ainyc/canonry-provider-gemini": "0.0.0",
76
75
  "@ainyc/canonry-provider-local": "0.0.0",
76
+ "@ainyc/canonry-provider-openai": "0.0.0",
77
77
  "@ainyc/canonry-provider-perplexity": "0.0.0",
78
- "@ainyc/canonry-provider-openai": "0.0.0"
78
+ "@ainyc/canonry-provider-gemini": "0.0.0"
79
79
  },
80
80
  "scripts": {
81
81
  "build": "tsx scripts/copy-agent-assets.ts && tsup && tsx build-web.ts",