@ainyc/canonry 3.2.4 → 3.2.7

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/dist/cli.js CHANGED
@@ -17,7 +17,7 @@ import {
17
17
  setGoogleAuthConfig,
18
18
  showFirstRunNotice,
19
19
  trackEvent
20
- } from "./chunk-X5ZTFJ37.js";
20
+ } from "./chunk-7R5NSWF7.js";
21
21
  import {
22
22
  CcReleaseSyncStatuses,
23
23
  CheckScopes,
@@ -45,7 +45,7 @@ import {
45
45
  saveConfig,
46
46
  saveConfigPatch,
47
47
  usageError
48
- } from "./chunk-PS7JRDL3.js";
48
+ } from "./chunk-GY4MNUTI.js";
49
49
  import {
50
50
  apiKeys,
51
51
  competitors,
@@ -57,7 +57,7 @@ import {
57
57
  projects,
58
58
  querySnapshots,
59
59
  runs
60
- } from "./chunk-UQH5SKM2.js";
60
+ } from "./chunk-ZCPZOVVE.js";
61
61
  import "./chunk-MLKGABMK.js";
62
62
 
63
63
  // src/cli.ts
@@ -448,8 +448,133 @@ async function backfillAiReferralPathsCommand(opts) {
448
448
  console.log(` Updated: ${updated}`);
449
449
  console.log(` Unchanged: ${unchanged}`);
450
450
  }
451
+ async function backfillAnswerMentionsCommand(opts) {
452
+ const config = loadConfig();
453
+ const db = createClient(config.database);
454
+ migrate(db);
455
+ const projectFilter = opts?.project?.trim();
456
+ const scopedProjects = projectFilter ? db.select().from(projects).where(eq(projects.name, projectFilter)).all() : db.select().from(projects).all();
457
+ let examined = 0;
458
+ let updated = 0;
459
+ let mentioned = 0;
460
+ if (scopedProjects.length > 0) {
461
+ const runRows = projectFilter ? db.select({ id: runs.id, projectId: runs.projectId }).from(runs).where(and(
462
+ eq(runs.kind, RunKinds["answer-visibility"]),
463
+ inArray(runs.projectId, scopedProjects.map((project) => project.id))
464
+ )).all() : db.select({ id: runs.id, projectId: runs.projectId }).from(runs).where(eq(runs.kind, RunKinds["answer-visibility"])).all();
465
+ const runIdsByProject = /* @__PURE__ */ new Map();
466
+ for (const run of runRows) {
467
+ const existing = runIdsByProject.get(run.projectId);
468
+ if (existing) existing.push(run.id);
469
+ else runIdsByProject.set(run.projectId, [run.id]);
470
+ }
471
+ for (const project of scopedProjects) {
472
+ const competitorDomains = db.select({ domain: competitors.domain }).from(competitors).where(eq(competitors.projectId, project.id)).all().map((row) => row.domain);
473
+ const runIds = runIdsByProject.get(project.id) ?? [];
474
+ if (runIds.length === 0) continue;
475
+ const projectDomains = effectiveDomains({
476
+ canonicalDomain: project.canonicalDomain,
477
+ ownedDomains: parseJsonColumn(project.ownedDomains, [])
478
+ });
479
+ for (let offset = 0; offset < runIds.length; offset += SNAPSHOT_BATCH_SIZE) {
480
+ const batchRunIds = runIds.slice(offset, offset + SNAPSHOT_BATCH_SIZE);
481
+ const snapshotRows = db.select({
482
+ id: querySnapshots.id,
483
+ provider: querySnapshots.provider,
484
+ answerMentioned: querySnapshots.answerMentioned,
485
+ answerText: querySnapshots.answerText,
486
+ citedDomains: querySnapshots.citedDomains,
487
+ competitorOverlap: querySnapshots.competitorOverlap,
488
+ recommendedCompetitors: querySnapshots.recommendedCompetitors,
489
+ rawResponse: querySnapshots.rawResponse
490
+ }).from(querySnapshots).where(inArray(querySnapshots.runId, batchRunIds)).all();
491
+ const pendingUpdates = [];
492
+ for (const snapshot of snapshotRows) {
493
+ examined++;
494
+ const answerText = snapshot.answerText ?? "";
495
+ const nextAnswerMentioned = determineAnswerMentioned(answerText, project.displayName, projectDomains);
496
+ if (nextAnswerMentioned) mentioned++;
497
+ const citedDomains = parseJsonColumn(snapshot.citedDomains, []);
498
+ const groundingSources = readStoredGroundingSources(snapshot.rawResponse);
499
+ const normalized = {
500
+ provider: snapshot.provider,
501
+ answerText,
502
+ citedDomains,
503
+ groundingSources,
504
+ searchQueries: []
505
+ };
506
+ const nextCompetitorOverlap = JSON.stringify(
507
+ computeCompetitorOverlap(normalized, competitorDomains)
508
+ );
509
+ const nextRecommendedCompetitors = JSON.stringify(
510
+ extractRecommendedCompetitors(
511
+ answerText,
512
+ projectDomains,
513
+ citedDomains,
514
+ competitorDomains
515
+ )
516
+ );
517
+ const nextPatch = {};
518
+ if (snapshot.answerMentioned !== nextAnswerMentioned) {
519
+ nextPatch.answerMentioned = nextAnswerMentioned;
520
+ }
521
+ if (snapshot.competitorOverlap !== nextCompetitorOverlap) {
522
+ nextPatch.competitorOverlap = nextCompetitorOverlap;
523
+ }
524
+ if (snapshot.recommendedCompetitors !== nextRecommendedCompetitors) {
525
+ nextPatch.recommendedCompetitors = nextRecommendedCompetitors;
526
+ }
527
+ if (Object.keys(nextPatch).length > 0) {
528
+ pendingUpdates.push({ id: snapshot.id, patch: nextPatch });
529
+ }
530
+ }
531
+ if (pendingUpdates.length > 0) {
532
+ db.transaction((tx) => {
533
+ for (const update of pendingUpdates) {
534
+ tx.update(querySnapshots).set(update.patch).where(eq(querySnapshots.id, update.id)).run();
535
+ }
536
+ });
537
+ updated += pendingUpdates.length;
538
+ }
539
+ }
540
+ }
541
+ }
542
+ const result = {
543
+ project: projectFilter ?? null,
544
+ projects: scopedProjects.length,
545
+ examined,
546
+ updated,
547
+ mentioned
548
+ };
549
+ if (opts?.format === "json") {
550
+ console.log(JSON.stringify(result, null, 2));
551
+ return;
552
+ }
553
+ console.log("Answer mentions backfill complete.\n");
554
+ if (projectFilter) console.log(` Project: ${projectFilter}`);
555
+ console.log(` Projects: ${scopedProjects.length}`);
556
+ console.log(` Examined: ${examined}`);
557
+ console.log(` Updated: ${updated}`);
558
+ console.log(` Mentioned: ${mentioned}`);
559
+ }
560
+ function readStoredGroundingSources(rawResponse) {
561
+ const envelope = parseJsonColumn(rawResponse, {});
562
+ const sources = envelope.groundingSources;
563
+ if (!Array.isArray(sources)) return [];
564
+ const result = [];
565
+ for (const source of sources) {
566
+ if (source && typeof source === "object") {
567
+ const uri = source.uri;
568
+ const title = source.title;
569
+ if (typeof uri === "string") {
570
+ result.push({ uri, title: typeof title === "string" ? title : "" });
571
+ }
572
+ }
573
+ }
574
+ return result;
575
+ }
451
576
  async function backfillInsightsCommand(project, opts) {
452
- const { IntelligenceService } = await import("./intelligence-service-GYY23WHR.js");
577
+ const { IntelligenceService } = await import("./intelligence-service-FNJTFSI3.js");
453
578
  const config = loadConfig();
454
579
  const db = createClient(config.database);
455
580
  migrate(db);
@@ -628,6 +753,20 @@ var BACKFILL_CLI_COMMANDS = [
628
753
  });
629
754
  }
630
755
  },
756
+ {
757
+ path: ["backfill", "answer-mentions"],
758
+ usage: "canonry backfill answer-mentions [--project <name>] [--format json]",
759
+ options: {
760
+ project: stringOption()
761
+ },
762
+ allowPositionals: false,
763
+ run: async (input) => {
764
+ await backfillAnswerMentionsCommand({
765
+ project: getString(input.values, "project"),
766
+ format: input.format
767
+ });
768
+ }
769
+ },
631
770
  {
632
771
  path: ["backfill", "insights"],
633
772
  usage: "canonry backfill insights <project> [--from-run <id>] [--to-run <id>] [--format json]",
@@ -675,12 +814,12 @@ var BACKFILL_CLI_COMMANDS = [
675
814
  },
676
815
  {
677
816
  path: ["backfill"],
678
- usage: "canonry backfill <answer-visibility|insights|normalized-paths|ai-referral-paths> [options]",
817
+ usage: "canonry backfill <answer-visibility|answer-mentions|insights|normalized-paths|ai-referral-paths> [options]",
679
818
  run: async (input) => {
680
819
  unknownSubcommand(input.positionals[0], {
681
820
  command: "backfill",
682
- usage: "canonry backfill <answer-visibility|insights|normalized-paths|ai-referral-paths> [options]",
683
- available: ["answer-visibility", "insights", "normalized-paths", "ai-referral-paths"]
821
+ usage: "canonry backfill <answer-visibility|answer-mentions|insights|normalized-paths|ai-referral-paths> [options]",
822
+ available: ["answer-visibility", "answer-mentions", "insights", "normalized-paths", "ai-referral-paths"]
684
823
  });
685
824
  }
686
825
  }
package/dist/index.js CHANGED
@@ -1,10 +1,10 @@
1
1
  import {
2
2
  createServer
3
- } from "./chunk-X5ZTFJ37.js";
3
+ } from "./chunk-7R5NSWF7.js";
4
4
  import {
5
5
  loadConfig
6
- } from "./chunk-PS7JRDL3.js";
7
- import "./chunk-UQH5SKM2.js";
6
+ } from "./chunk-GY4MNUTI.js";
7
+ import "./chunk-ZCPZOVVE.js";
8
8
  import "./chunk-MLKGABMK.js";
9
9
  export {
10
10
  createServer,
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  IntelligenceService
3
- } from "./chunk-UQH5SKM2.js";
3
+ } from "./chunk-ZCPZOVVE.js";
4
4
  import "./chunk-MLKGABMK.js";
5
5
  export {
6
6
  IntelligenceService
package/dist/mcp.js CHANGED
@@ -2,7 +2,7 @@ import {
2
2
  CliError,
3
3
  canonryMcpTools,
4
4
  createApiClient
5
- } from "./chunk-PS7JRDL3.js";
5
+ } from "./chunk-GY4MNUTI.js";
6
6
  import "./chunk-MLKGABMK.js";
7
7
 
8
8
  // src/mcp/cli.ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ainyc/canonry",
3
- "version": "3.2.4",
3
+ "version": "3.2.7",
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",
@@ -60,20 +60,20 @@
60
60
  "tsup": "^8.5.1",
61
61
  "tsx": "^4.19.0",
62
62
  "@ainyc/canonry-api-routes": "0.0.0",
63
- "@ainyc/canonry-config": "0.0.0",
64
63
  "@ainyc/canonry-contracts": "0.0.0",
65
- "@ainyc/canonry-integration-bing": "0.0.0",
66
- "@ainyc/canonry-intelligence": "0.0.0",
67
- "@ainyc/canonry-integration-commoncrawl": "0.0.0",
64
+ "@ainyc/canonry-config": "0.0.0",
68
65
  "@ainyc/canonry-db": "0.0.0",
66
+ "@ainyc/canonry-integration-commoncrawl": "0.0.0",
67
+ "@ainyc/canonry-intelligence": "0.0.0",
69
68
  "@ainyc/canonry-integration-google": "0.0.0",
69
+ "@ainyc/canonry-integration-bing": "0.0.0",
70
70
  "@ainyc/canonry-integration-wordpress": "0.0.0",
71
71
  "@ainyc/canonry-provider-gemini": "0.0.0",
72
72
  "@ainyc/canonry-provider-claude": "0.0.0",
73
- "@ainyc/canonry-provider-perplexity": "0.0.0",
73
+ "@ainyc/canonry-provider-cdp": "0.0.0",
74
74
  "@ainyc/canonry-provider-local": "0.0.0",
75
75
  "@ainyc/canonry-provider-openai": "0.0.0",
76
- "@ainyc/canonry-provider-cdp": "0.0.0"
76
+ "@ainyc/canonry-provider-perplexity": "0.0.0"
77
77
  },
78
78
  "scripts": {
79
79
  "build": "tsx scripts/copy-agent-assets.ts && tsup && tsx build-web.ts",