@ainyc/canonry 4.110.0 → 4.112.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (27) hide show
  1. package/assets/agent-workspace/skills/canonry/references/canonry-cli.md +1 -1
  2. package/assets/assets/{BacklinksPage-Duk8YbV2.js → BacklinksPage-0OUPoMJf.js} +1 -1
  3. package/assets/assets/ChartPrimitives-BeJemaLi.js +1 -0
  4. package/assets/assets/ProjectPage-CD0RS8DR.js +7 -0
  5. package/assets/assets/{RunRow-DH8UMAwj.js → RunRow-CCnuv5wi.js} +1 -1
  6. package/assets/assets/{RunsPage-OPteH1b_.js → RunsPage-IqTj8i9c.js} +1 -1
  7. package/assets/assets/{SettingsPage-7cspMOFv.js → SettingsPage-DKdvVPVp.js} +1 -1
  8. package/assets/assets/{TrafficPage-D4pcnfc8.js → TrafficPage-xPENJ4Du.js} +1 -1
  9. package/assets/assets/{TrafficSourceDetailPage-D-KbCCEK.js → TrafficSourceDetailPage-CP6o754T.js} +1 -1
  10. package/assets/assets/{arrow-left-M8KVuve8.js → arrow-left-DGiw6bsJ.js} +1 -1
  11. package/assets/assets/{extract-error-message-D2aTaSV5.js → extract-error-message-CYh3RHSN.js} +1 -1
  12. package/assets/assets/{index-ChPgQUZ5.js → index-BpHZkgFH.js} +51 -51
  13. package/assets/assets/index-CD6LKwQu.css +1 -0
  14. package/assets/assets/{trash-2-BNVgf5NY.js → trash-2-DBeJW7Iw.js} +1 -1
  15. package/assets/index.html +2 -2
  16. package/dist/{chunk-X4LLTNQZ.js → chunk-6M2ALGJA.js} +1 -1
  17. package/dist/{chunk-6PHBWPPN.js → chunk-KS2M7B5E.js} +8 -4
  18. package/dist/{chunk-JGRVQJHX.js → chunk-UOMNYP5T.js} +61 -6
  19. package/dist/{chunk-YQ4KOC5Z.js → chunk-VICGMHY2.js} +4 -0
  20. package/dist/cli.js +400 -102
  21. package/dist/index.js +4 -4
  22. package/dist/{intelligence-service-BGLF7DQW.js → intelligence-service-RGOY43QR.js} +2 -2
  23. package/dist/mcp.js +2 -2
  24. package/package.json +10 -10
  25. package/assets/assets/ChartPrimitives-aLxtVH28.js +0 -1
  26. package/assets/assets/ProjectPage-Bqd0JvpC.js +0 -7
  27. package/assets/assets/index-CjrSrPKf.css +0 -1
@@ -102,6 +102,7 @@ import {
102
102
  contentTargetDismissalDtoSchema,
103
103
  contentTargetDismissalsResponseDtoSchema,
104
104
  contentTargetsResponseDtoSchema,
105
+ cosineSimilarity,
105
106
  createApiKeyRequestSchema,
106
107
  createdApiKeyDtoSchema,
107
108
  dedupeReportActions,
@@ -270,7 +271,7 @@ import {
270
271
  wordpressSchemaDeployResultDtoSchema,
271
272
  wordpressSchemaStatusResultDtoSchema,
272
273
  wordpressStatusDtoSchema
273
- } from "./chunk-YQ4KOC5Z.js";
274
+ } from "./chunk-VICGMHY2.js";
274
275
 
275
276
  // src/intelligence-service.ts
276
277
  import { eq as eq38, desc as desc18, asc as asc6, and as and28, ne as ne5, or as or6, inArray as inArray14, gte as gte7, lte as lte4 } from "drizzle-orm";
@@ -1164,6 +1165,10 @@ var discoverySessions = sqliteTable("discovery_sessions", {
1164
1165
  // session identity for consolidation — and per-provider candidate counts.
1165
1166
  seedProviders: text("seed_providers", { mode: "json" }).$type(),
1166
1167
  seedProviderCounts: text("seed_provider_counts", { mode: "json" }).$type(),
1168
+ // TRUE canonical count after dedup, BEFORE the probe-budget slice. seed_count
1169
+ // is post-truncation (probedCanonicals.length), so a deliberately small
1170
+ // maxProbes deflates it; this column is the honest numerator.
1171
+ canonicalCount: integer("canonical_count"),
1167
1172
  dedupThreshold: real("dedup_threshold"),
1168
1173
  probeCount: integer("probe_count"),
1169
1174
  citedCount: integer("cited_count"),
@@ -3466,6 +3471,15 @@ var MIGRATION_VERSIONS = [
3466
3471
  `ALTER TABLE discovery_sessions ADD COLUMN seed_providers TEXT`,
3467
3472
  `ALTER TABLE discovery_sessions ADD COLUMN seed_provider_counts TEXT`
3468
3473
  ]
3474
+ },
3475
+ {
3476
+ version: 94,
3477
+ name: "discovery-session-canonical-count",
3478
+ statements: [
3479
+ // True post-dedup, pre-truncation canonical count (seed_count is
3480
+ // post-truncation). Additive + nullable (downgrade-safe).
3481
+ `ALTER TABLE discovery_sessions ADD COLUMN canonical_count INTEGER`
3482
+ ]
3469
3483
  }
3470
3484
  ];
3471
3485
  function rebuildBacklinkTableWithSource(tx, table) {
@@ -34179,6 +34193,7 @@ function serializeSession(row) {
34179
34193
  seedRawCandidates: row.seedRawCandidates ?? null,
34180
34194
  seedProviders: row.seedProviders ?? null,
34181
34195
  seedProviderCounts: row.seedProviderCounts ?? null,
34196
+ canonicalCount: row.canonicalCount ?? null,
34182
34197
  dedupClusterMinSims: row.dedupClusterMinSims ?? null,
34183
34198
  dedupBandPairFraction: row.dedupBandPairFraction ?? null,
34184
34199
  dedupPairsTotal: row.dedupPairsTotal ?? null,
@@ -34264,14 +34279,41 @@ async function classifyCompetitorDomains(deps, project, icpDescription, domains)
34264
34279
  return {};
34265
34280
  }
34266
34281
  }
34267
- async function pickCanonicalsWithStats(candidates, deps, dedupThreshold) {
34282
+ async function pickCanonicalsWithStats(candidates, deps, dedupThreshold, primaryMask) {
34268
34283
  const emptyStats = { perClusterMinSimilarity: [], bandPairFraction: null, pairsTotal: 0 };
34269
34284
  if (candidates.length === 0) return { canonicals: [], stats: emptyStats };
34270
34285
  if (candidates.length === 1) return { canonicals: candidates, stats: emptyStats };
34271
34286
  const vectors = await deps.embed(candidates);
34272
- const indexClusters = clusterByCosine(candidates.map((_, i) => i), vectors, dedupThreshold);
34273
- const canonicals = indexClusters.map((cluster) => pickClusterRepresentative(cluster.map((i) => candidates[i])));
34274
- return { canonicals, stats: computeDedupSimilarityStats(vectors, indexClusters) };
34287
+ const indices = candidates.map((_, i) => i);
34288
+ const hasBothRoles = primaryMask !== void 0 && primaryMask.length === candidates.length && primaryMask.some((p) => p) && primaryMask.some((p) => !p);
34289
+ if (!hasBothRoles) {
34290
+ const indexClusters = clusterByCosine(indices, vectors, dedupThreshold);
34291
+ const canonicals = indexClusters.map((cluster) => pickClusterRepresentative(cluster.map((i) => candidates[i])));
34292
+ return { canonicals, stats: computeDedupSimilarityStats(vectors, indexClusters) };
34293
+ }
34294
+ const primaryIdx = indices.filter((i) => primaryMask[i]);
34295
+ const primaryClusters = clusterByCosine(
34296
+ primaryIdx,
34297
+ primaryIdx.map((i) => vectors[i]),
34298
+ dedupThreshold
34299
+ );
34300
+ const repIndexOf = (cluster) => {
34301
+ const rep = pickClusterRepresentative(cluster.map((i) => candidates[i]));
34302
+ return cluster.find((i) => candidates[i] === rep);
34303
+ };
34304
+ const keptIdx = primaryClusters.map(repIndexOf);
34305
+ for (const s of indices.filter((i) => !primaryMask[i])) {
34306
+ const novel = keptIdx.every((k) => cosineSimilarity(vectors[s], vectors[k]) < dedupThreshold);
34307
+ if (novel) keptIdx.push(s);
34308
+ }
34309
+ return {
34310
+ canonicals: keptIdx.map((i) => candidates[i]),
34311
+ // Band fraction describes the candidate SPACE (not the clustering), so it is
34312
+ // computed over all vectors as before; per-cluster cohesion reports the
34313
+ // primary clusters.
34314
+ stats: computeDedupSimilarityStats(vectors, primaryClusters),
34315
+ primaryCanonicalCount: primaryClusters.length
34316
+ };
34275
34317
  }
34276
34318
  async function executeDiscovery(opts) {
34277
34319
  const dedupThreshold = opts.dedupThreshold ?? DISCOVERY_DEFAULT_DEDUP_THRESHOLD;
@@ -34301,10 +34343,22 @@ async function executeDiscovery(opts) {
34301
34343
  });
34302
34344
  const rawCandidates = dedupeStrings(unbrandedCandidates);
34303
34345
  const seedCountRaw = rawCandidates.length;
34346
+ const primaryProvider = opts.seedProviders?.[0];
34347
+ const multiProvider = (opts.seedProviders?.length ?? 0) >= 2 && seedResult.candidateProviders != null;
34348
+ let primaryMask;
34349
+ if (multiProvider && primaryProvider) {
34350
+ const providerOf = /* @__PURE__ */ new Map();
34351
+ seedResult.candidates.forEach((candidate, i) => {
34352
+ const key = candidate.trim().toLowerCase();
34353
+ if (!providerOf.has(key)) providerOf.set(key, seedResult.candidateProviders[i]);
34354
+ });
34355
+ primaryMask = rawCandidates.map((c) => providerOf.get(c.trim().toLowerCase()) === primaryProvider);
34356
+ }
34304
34357
  const { canonicals, stats: dedupStats } = await pickCanonicalsWithStats(
34305
34358
  rawCandidates,
34306
34359
  { embed: opts.deps.embed },
34307
- dedupThreshold
34360
+ dedupThreshold,
34361
+ primaryMask
34308
34362
  );
34309
34363
  const warning = seedCollapseWarning({
34310
34364
  seedCountRaw,
@@ -34323,6 +34377,7 @@ async function executeDiscovery(opts) {
34323
34377
  seedFromAnswerCount: seedResult.fromAnswerCount ?? null,
34324
34378
  seedFromGroundingCount: seedResult.fromGroundingCount ?? null,
34325
34379
  seedBrandFilteredCount: droppedBranded.length,
34380
+ canonicalCount: canonicals.length,
34326
34381
  // Full seed provenance + dedup calibration diagnostics: the raw
34327
34382
  // candidate list (as the seed dep returned it, pre-filter) makes every
34328
34383
  // live session a replayable fixture; the similarity stats are the data
@@ -2246,6 +2246,9 @@ var discoverySessionDtoSchema = z17.object({
2246
2246
  seedProviders: z17.array(z17.string()).nullable().optional(),
2247
2247
  /** Raw candidate count contributed per seed provider. */
2248
2248
  seedProviderCounts: z17.record(z17.string(), z17.number().int()).nullable().optional(),
2249
+ /** True post-dedup canonical count BEFORE the probe-budget slice (seedCount
2250
+ * is post-truncation). Null on legacy sessions. */
2251
+ canonicalCount: z17.number().int().nullable().optional(),
2249
2252
  dedupThreshold: z17.number().nullable().optional(),
2250
2253
  probeCount: z17.number().int().nullable().optional(),
2251
2254
  citedCount: z17.number().int().nullable().default(null),
@@ -5760,6 +5763,7 @@ export {
5760
5763
  categorizeSource,
5761
5764
  categorizeSourceWithCompetitors,
5762
5765
  categoryLabel,
5766
+ cosineSimilarity,
5763
5767
  clusterByCosine,
5764
5768
  pickClusterRepresentative,
5765
5769
  computeDedupSimilarityStats,