@canonry/canonry 5.19.1 → 5.20.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 (30) hide show
  1. package/assets/agent-workspace/skills/canonry/references/canonry-cli.md +3 -1
  2. package/assets/assets/{AuditHistoryPanel-ddq5tdlB.js → AuditHistoryPanel-BSh3Oezj.js} +1 -1
  3. package/assets/assets/{BacklinksPage-g57_xzTX.js → BacklinksPage-DQ59dhCx.js} +1 -1
  4. package/assets/assets/{HistoryPage-C-TdCUQ2.js → HistoryPage-BBvgid3o.js} +1 -1
  5. package/assets/assets/{MeasurementPropertyPage-CAADmNfw.js → MeasurementPropertyPage-Dmb18JbT.js} +1 -1
  6. package/assets/assets/{ProjectPage-CoBwpHmA.js → ProjectPage-CPg0q2Dy.js} +1 -1
  7. package/assets/assets/{RunRow-BpG0Zy-x.js → RunRow-BK8sZCID.js} +1 -1
  8. package/assets/assets/{RunsPage-DK3pb1LH.js → RunsPage-CIcVBTdP.js} +1 -1
  9. package/assets/assets/{SettingsPage-BruiY8Zh.js → SettingsPage-Bc3aR-gz.js} +1 -1
  10. package/assets/assets/{SiteHealthSection-De4U11Gv.js → SiteHealthSection-FF14aIXT.js} +3 -3
  11. package/assets/assets/{TrafficPage-BVolLXT2.js → TrafficPage-C_qoeGDl.js} +1 -1
  12. package/assets/assets/{TrafficSourceDetailPage-CFDb6lPD.js → TrafficSourceDetailPage-B3i_B2MI.js} +1 -1
  13. package/assets/assets/{extract-error-message-Bk1RTjzo.js → extract-error-message-BisUn6nN.js} +1 -1
  14. package/assets/assets/{index-B--AA1mG.js → index-Dht7JNX5.js} +3 -3
  15. package/assets/assets/{react-sigma_core.esm.min--QXVK1JS.js → react-sigma_core.esm.min-tWhS09SS.js} +1 -1
  16. package/assets/assets/{v2-overview-adapter-CpjJPZsC.js → v2-overview-adapter-CAoeWKQJ.js} +1 -1
  17. package/assets/index.html +1 -1
  18. package/dist/{chunk-PGOID3LE.js → chunk-4PENJKRN.js} +2 -2
  19. package/dist/{chunk-EJXDABGU.js → chunk-5FKR2K76.js} +4 -3
  20. package/dist/{chunk-EJZFTNZG.js → chunk-DRZWMFRV.js} +195 -90
  21. package/dist/{chunk-SOCYTKTF.js → chunk-QF7SY7AF.js} +27 -6
  22. package/dist/{chunk-J3JXJIST.js → chunk-TSFKNQ5X.js} +3 -3
  23. package/dist/{chunk-3IAIW5KH.js → chunk-WL27HO5C.js} +36 -8
  24. package/dist/{chunk-4WROKFN6.js → chunk-XBGPHZKA.js} +1 -1
  25. package/dist/cli.js +9 -9
  26. package/dist/{demo-server-BLDYKCFS.js → demo-server-OCBV5OMS.js} +4 -4
  27. package/dist/index.js +6 -6
  28. package/dist/{intelligence-service-3MHYLKMS.js → intelligence-service-MKHINDHN.js} +2 -2
  29. package/dist/mcp.js +4 -4
  30. package/package.json +13 -13
@@ -671,6 +671,7 @@ import {
671
671
  resolveLocations,
672
672
  resolveMeasurementRunQueryScope,
673
673
  resolveMeasurementRunScope,
674
+ resolveProviderModel,
674
675
  resolveSnapshotRequestQueries,
675
676
  restrictedWriteScopes,
676
677
  resultsClearRequestSchema,
@@ -791,7 +792,7 @@ import {
791
792
  wordpressSchemaDeployResultDtoSchema,
792
793
  wordpressSchemaStatusResultDtoSchema,
793
794
  wordpressStatusDtoSchema
794
- } from "./chunk-SOCYTKTF.js";
795
+ } from "./chunk-QF7SY7AF.js";
795
796
 
796
797
  // src/intelligence-service.ts
797
798
  import { eq as eq71, desc as desc32, asc as asc12, and as and60, ne as ne11, or as or18, inArray as inArray27, gte as gte18, lte as lte15, isNull as isNull13, sql as sql28, exists } from "drizzle-orm";
@@ -12739,7 +12740,7 @@ function validateProviderModels(models, adapters) {
12739
12740
  { provider, model, hint: adapter.modelValidationHint }
12740
12741
  );
12741
12742
  }
12742
- normalized[provider] = model;
12743
+ normalized[provider] = resolveProviderModel(provider, model);
12743
12744
  }
12744
12745
  return normalized;
12745
12746
  }
@@ -16494,7 +16495,7 @@ function effectiveModels(tx, params, providers) {
16494
16495
  const resolved = {};
16495
16496
  for (const provider of providers) {
16496
16497
  const model = overrides[provider] ?? instance[provider];
16497
- if (model) resolved[provider] = model;
16498
+ if (model) resolved[provider] = resolveProviderModel(provider, model);
16498
16499
  }
16499
16500
  return resolved;
16500
16501
  }
@@ -16536,6 +16537,8 @@ function materializeV2ExecutionNodes(nodes, instanceModels) {
16536
16537
  const expectedSlots = [];
16537
16538
  const providers = /* @__PURE__ */ new Set();
16538
16539
  const models = /* @__PURE__ */ new Map();
16540
+ const answering = /* @__PURE__ */ new Map();
16541
+ const retired = /* @__PURE__ */ new Set();
16539
16542
  const claimed = /* @__PURE__ */ new Set();
16540
16543
  for (const node of [...nodes].sort((left, right) => compareText4(left.stableKey, right.stableKey))) {
16541
16544
  const nodeProviders = normalizeProviders(node.context.providers);
@@ -16553,6 +16556,11 @@ function materializeV2ExecutionNodes(nodes, instanceModels) {
16553
16556
  const model = resolved.get(provider) ?? null;
16554
16557
  if (!models.has(provider)) models.set(provider, model);
16555
16558
  else if (models.get(provider) !== model) models.set(provider, null);
16559
+ if (model) {
16560
+ const current = resolveProviderModel(provider, model);
16561
+ if (current !== model) retired.add(provider);
16562
+ answering.set(provider, (answering.get(provider) ?? /* @__PURE__ */ new Set()).add(current));
16563
+ }
16556
16564
  expectedSlots.push({
16557
16565
  executionId: node.stableKey,
16558
16566
  queryText: node.queryText,
@@ -16565,7 +16573,11 @@ function materializeV2ExecutionNodes(nodes, instanceModels) {
16565
16573
  return {
16566
16574
  expectedSlots,
16567
16575
  providers: [...providers].sort(compareText4),
16568
- models: Object.fromEntries([...models].flatMap(([provider, model]) => model ? [[provider, model]] : []))
16576
+ models: Object.fromEntries([...models].flatMap(([provider, model]) => {
16577
+ if (model) return [[provider, model]];
16578
+ const current = answering.get(provider);
16579
+ return retired.has(provider) && current ? [[provider, [...current].sort(compareText4).join(" + ")]] : [];
16580
+ }))
16569
16581
  };
16570
16582
  }
16571
16583
  function sliceForV2(plan, params) {
@@ -16849,6 +16861,11 @@ function newerFullSweep(db, run) {
16849
16861
  )
16850
16862
  )).orderBy(desc4(runs.createdAt)).get();
16851
16863
  }
16864
+ function measuredOnRetiredModel(run, provider, missing) {
16865
+ const recorded = run.measurementExecutionIdentity?.models[provider];
16866
+ if (recorded !== void 0) return resolveProviderModel(provider, recorded) !== recorded;
16867
+ return missing.some((slot) => typeof slot.requestedModel === "string" && resolveProviderModel(provider, slot.requestedModel) !== slot.requestedModel);
16868
+ }
16852
16869
  function evaluateRunFill(db, run, input = {}) {
16853
16870
  const slots = measurementRunSlotState(db, run.id);
16854
16871
  const refuse = (code, message) => ({ kind: "refused", code, message, slots });
@@ -16938,6 +16955,13 @@ function evaluateRunFill(db, run, input = {}) {
16938
16955
  `${unfrozen.length} missing answer(s) have no model frozen in the run's manifest, so filling them would use today's model instead of the one the run measured with.`
16939
16956
  );
16940
16957
  }
16958
+ const retired = providers.filter((provider) => measuredOnRetiredModel(run, provider, missingByProvider.get(provider) ?? []));
16959
+ if (retired.length) {
16960
+ return refuse(
16961
+ RunFillRefusalCodes.model_retired,
16962
+ `This run measured ${retired.join(", ")} on a model the provider has since retired, and the replacement is a different engine. Filling it now would mix two engines in one run; run a new sweep instead.`
16963
+ );
16964
+ }
16941
16965
  if (input.runnableProviders) {
16942
16966
  const runnable = new Set(input.runnableProviders.map(normalizeProvider));
16943
16967
  const absent = providers.filter((provider) => !runnable.has(provider));
@@ -25104,10 +25128,14 @@ function simpleDispatchEngines(project, opts) {
25104
25128
  return selected.filter((provider) => available === null || available.has(provider)).map((provider) => ({
25105
25129
  provider,
25106
25130
  // `undefined` is materially different from an intentionally blank model
25107
- // override/configuration, just as it is in JobRunner.
25108
- requestedModel: overrides[provider] ?? summaries.get(provider)?.model ?? null
25131
+ // override/configuration, just as it is in JobRunner, which also resolves
25132
+ // a retired override to the id that answers now.
25133
+ requestedModel: resolvedOverride(provider, overrides[provider]) ?? summaries.get(provider)?.model ?? null
25109
25134
  })).sort((left, right) => compareText15(left.provider, right.provider));
25110
25135
  }
25136
+ function resolvedOverride(provider, model) {
25137
+ return model === void 0 ? void 0 : resolveProviderModel(provider, model);
25138
+ }
25111
25139
  function simpleDefaultLocation(project) {
25112
25140
  if (!project.defaultLocation) return null;
25113
25141
  return project.locations.find((location) => location.label === project.defaultLocation) ?? null;
@@ -85756,7 +85784,7 @@ async function researchRoutes(app, opts) {
85756
85784
  if (location && !project.locations.some((item2) => sameLocation(item2, location))) throw validationError("Research location must exactly match a configured project location.", { location });
85757
85785
  const template = input.template ? resolveResearchTemplate(app, project.id, input.template, scope, location) : null;
85758
85786
  const requestedModel2 = input.model ?? null;
85759
- const resolvedModel = requestedModel2 ?? (project.providerModels[providerName] || opts.getEffectiveProviderModels?.()[providerName] || adapter.defaultModel);
85787
+ const resolvedModel = resolveProviderModel(providerName, requestedModel2 ?? (project.providerModels[providerName] || opts.getEffectiveProviderModels?.()[providerName] || adapter.defaultModel));
85760
85788
  adapter.modelValidationPattern.lastIndex = 0;
85761
85789
  if (!adapter.modelValidationPattern.test(resolvedModel)) throw validationError('Invalid resolved model "' + resolvedModel + '" for provider "' + providerName + '".', { provider: providerName, model: resolvedModel, hint: adapter.modelValidationHint });
85762
85790
  if (deduplicateResearchQueries(input.queries).length !== input.queries.length) throw validationError("Research queries must be unique within a batch.");
@@ -85893,7 +85921,7 @@ async function researchRoutes(app, opts) {
85893
85921
  const configured = new Set(opts.configuredProviderNames ?? []);
85894
85922
  const effectiveModels2 = opts.getEffectiveProviderModels?.() ?? {};
85895
85923
  const providers = (opts.providerAdapters ?? []).filter((adapter) => adapter.mode === "api" && !isBrowserProvider(adapter.name) && configured.has(adapter.name)).map((adapter) => {
85896
- const defaultModel = project.providerModels[adapter.name] || effectiveModels2[adapter.name] || adapter.defaultModel;
85924
+ const defaultModel = resolveProviderModel(adapter.name, project.providerModels[adapter.name] || effectiveModels2[adapter.name] || adapter.defaultModel);
85897
85925
  const cached = opts.getCachedProviderModels?.(adapter.name) ?? [];
85898
85926
  const models = cached.length ? cached : adapter.knownModels;
85899
85927
  return {
@@ -105,7 +105,7 @@ import {
105
105
  trafficEventKindSchema,
106
106
  trafficSeriesGranularitySchema,
107
107
  visibilityReportRequestSchema
108
- } from "./chunk-SOCYTKTF.js";
108
+ } from "./chunk-QF7SY7AF.js";
109
109
 
110
110
  // src/cli-error.ts
111
111
  function isMachineFormat(format) {
package/dist/cli.js CHANGED
@@ -35,11 +35,11 @@ import {
35
35
  trackCliCommandFinished,
36
36
  trackEvent,
37
37
  waitForServerRuntimeStartup
38
- } from "./chunk-EJZFTNZG.js";
38
+ } from "./chunk-DRZWMFRV.js";
39
39
  import {
40
40
  autoSyncSkills,
41
41
  formatAutoSyncNotice
42
- } from "./chunk-J3JXJIST.js";
42
+ } from "./chunk-TSFKNQ5X.js";
43
43
  import {
44
44
  configExists,
45
45
  createApiClient,
@@ -56,13 +56,13 @@ import {
56
56
  saveConfig,
57
57
  saveConfigPatch,
58
58
  shouldPrintServeSkillsNudge
59
- } from "./chunk-EJXDABGU.js";
59
+ } from "./chunk-5FKR2K76.js";
60
60
  import {
61
61
  DEFAULT_DEMO_TRUSTED_PROXIES,
62
62
  trustedProxiesProblem,
63
63
  trustedProxyProblem
64
64
  } from "./chunk-RB2F4D3Z.js";
65
- import "./chunk-PGOID3LE.js";
65
+ import "./chunk-4PENJKRN.js";
66
66
  import {
67
67
  CliError,
68
68
  EXIT_SYSTEM_ERROR,
@@ -74,7 +74,7 @@ import {
74
74
  runMeasurementDraftAction,
75
75
  systemError,
76
76
  usageError
77
- } from "./chunk-4WROKFN6.js";
77
+ } from "./chunk-XBGPHZKA.js";
78
78
  import {
79
79
  CLOUDFLARE_WORKER_BINDINGS,
80
80
  CLOUDFLARE_WORKER_GENERATED_MARKER,
@@ -89,7 +89,7 @@ import {
89
89
  queries,
90
90
  renderReportHtml,
91
91
  runs
92
- } from "./chunk-3IAIW5KH.js";
92
+ } from "./chunk-WL27HO5C.js";
93
93
  import {
94
94
  AdsDeliverySnapshotStatuses,
95
95
  AdsHistoricalCampaignRollupStatuses,
@@ -177,7 +177,7 @@ import {
177
177
  snapshotProviderModeSchema,
178
178
  visibilityReportRequestSchema,
179
179
  winnabilityClassSchema
180
- } from "./chunk-SOCYTKTF.js";
180
+ } from "./chunk-QF7SY7AF.js";
181
181
 
182
182
  // src/cli.ts
183
183
  import { pathToFileURL } from "url";
@@ -442,7 +442,7 @@ function parseDemoTrustedProxies(values) {
442
442
  async function demoCommand(options) {
443
443
  const { host, port } = parseDemoListenOptions(options);
444
444
  const trustProxy = parseDemoTrustedProxies(options.trustProxy);
445
- const { createDemoServer } = await import("./demo-server-BLDYKCFS.js");
445
+ const { createDemoServer } = await import("./demo-server-OCBV5OMS.js");
446
446
  const app = await createDemoServer({ trustProxy });
447
447
  let stopping = false;
448
448
  const stop = () => {
@@ -15511,7 +15511,7 @@ async function initCommand(opts) {
15511
15511
  }
15512
15512
  const perplexityApiKey = await promptProviderApiKey("Perplexity", "PERPLEXITY_API_KEY");
15513
15513
  if (perplexityApiKey) {
15514
- const perplexityModel = await prompt(" Perplexity model [sonar]: ") || "sonar";
15514
+ const perplexityModel = await prompt(" Perplexity preset or model [fast]: ") || "fast";
15515
15515
  providers.perplexity = { apiKey: perplexityApiKey, model: perplexityModel, quota: DEFAULT_QUOTA };
15516
15516
  }
15517
15517
  console.log("\nLocal LLM (Ollama, LM Studio, llama.cpp, vLLM \u2014 any OpenAI-compatible API):");
@@ -4,11 +4,11 @@ import {
4
4
  import {
5
5
  layoutSiteCrawlGraphInput,
6
6
  persistSiteCrawlGraphLayout
7
- } from "./chunk-PGOID3LE.js";
7
+ } from "./chunk-4PENJKRN.js";
8
8
  import {
9
9
  PACKAGE_VERSION,
10
10
  canonryMcpTools
11
- } from "./chunk-4WROKFN6.js";
11
+ } from "./chunk-XBGPHZKA.js";
12
12
  import {
13
13
  HISTORY_WINDOW_RUNS,
14
14
  IntelligenceService,
@@ -84,7 +84,7 @@ import {
84
84
  siteCrawlPages,
85
85
  siteCrawlSnapshots,
86
86
  trafficSources
87
- } from "./chunk-3IAIW5KH.js";
87
+ } from "./chunk-WL27HO5C.js";
88
88
  import {
89
89
  RunKinds,
90
90
  SiteCrawlFetchStates,
@@ -108,7 +108,7 @@ import {
108
108
  placementLinkDecision,
109
109
  siteAuditPageFactorSchema,
110
110
  wilsonInterval
111
- } from "./chunk-SOCYTKTF.js";
111
+ } from "./chunk-QF7SY7AF.js";
112
112
 
113
113
  // src/demo-server.ts
114
114
  import { dirname, join as join2 } from "path";
package/dist/index.js CHANGED
@@ -3,14 +3,14 @@ import {
3
3
  createGoogleMarketingCredentialStore,
4
4
  createGoogleMarketingRuntime,
5
5
  createServer
6
- } from "./chunk-EJZFTNZG.js";
6
+ } from "./chunk-DRZWMFRV.js";
7
7
  import {
8
8
  loadConfig
9
- } from "./chunk-EJXDABGU.js";
10
- import "./chunk-PGOID3LE.js";
11
- import "./chunk-4WROKFN6.js";
12
- import "./chunk-3IAIW5KH.js";
13
- import "./chunk-SOCYTKTF.js";
9
+ } from "./chunk-5FKR2K76.js";
10
+ import "./chunk-4PENJKRN.js";
11
+ import "./chunk-XBGPHZKA.js";
12
+ import "./chunk-WL27HO5C.js";
13
+ import "./chunk-QF7SY7AF.js";
14
14
  export {
15
15
  GoogleMarketingRuntimeError,
16
16
  createGoogleMarketingCredentialStore,
@@ -1,8 +1,8 @@
1
1
  import {
2
2
  HISTORY_WINDOW_RUNS,
3
3
  IntelligenceService
4
- } from "./chunk-3IAIW5KH.js";
5
- import "./chunk-SOCYTKTF.js";
4
+ } from "./chunk-WL27HO5C.js";
5
+ import "./chunk-QF7SY7AF.js";
6
6
  export {
7
7
  HISTORY_WINDOW_RUNS,
8
8
  IntelligenceService
package/dist/mcp.js CHANGED
@@ -1,15 +1,15 @@
1
1
  import {
2
2
  autoSyncSkills
3
- } from "./chunk-J3JXJIST.js";
3
+ } from "./chunk-TSFKNQ5X.js";
4
4
  import {
5
5
  createApiClient,
6
6
  createCanonryMcpServer
7
- } from "./chunk-EJXDABGU.js";
8
- import "./chunk-4WROKFN6.js";
7
+ } from "./chunk-5FKR2K76.js";
8
+ import "./chunk-XBGPHZKA.js";
9
9
  import {
10
10
  isReadOnlyKey,
11
11
  updateCheckEnvOptOut
12
- } from "./chunk-SOCYTKTF.js";
12
+ } from "./chunk-QF7SY7AF.js";
13
13
 
14
14
  // src/mcp/cli.ts
15
15
  import { randomUUID } from "crypto";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@canonry/canonry",
3
- "version": "5.19.1",
3
+ "version": "5.20.0",
4
4
  "type": "module",
5
5
  "description": "Self-hosted AI visibility (AEO) platform: track how ChatGPT, Claude, Gemini, and Perplexity cite your domain, join it with Search Console, GA4, server-side traffic, and paid media, and fix what you find through agent tools (CLI, REST, MCP). Local SQLite.",
6
6
  "keywords": [
@@ -86,32 +86,32 @@
86
86
  "@types/node-cron": "^3.0.11",
87
87
  "tsup": "^8.5.1",
88
88
  "tsx": "^4.19.0",
89
- "@ainyc/canonry-api-client": "0.0.0",
90
- "@ainyc/canonry-config": "0.0.0",
91
- "@ainyc/canonry-api-routes": "0.0.0",
92
89
  "@ainyc/canonry-web": "0.0.0",
90
+ "@ainyc/canonry-api-routes": "0.0.0",
91
+ "@ainyc/canonry-api-client": "0.0.0",
93
92
  "@ainyc/canonry-contracts": "0.0.0",
93
+ "@ainyc/canonry-config": "0.0.0",
94
94
  "@ainyc/canonry-db": "0.0.0",
95
95
  "@ainyc/canonry-integration-bing": "0.0.0",
96
96
  "@ainyc/canonry-integration-cloud-run": "0.0.0",
97
- "@ainyc/canonry-integration-commoncrawl": "0.0.0",
98
97
  "@ainyc/canonry-integration-cloudflare-queue": "0.0.0",
99
- "@ainyc/canonry-integration-google": "0.0.0",
100
- "@ainyc/canonry-integration-google-ads": "0.0.0",
101
98
  "@ainyc/canonry-integration-cloudflare-worker": "0.0.0",
102
- "@ainyc/canonry-integration-google-tag-manager": "0.0.0",
99
+ "@ainyc/canonry-integration-commoncrawl": "0.0.0",
100
+ "@ainyc/canonry-integration-google-ads": "0.0.0",
103
101
  "@ainyc/canonry-integration-google-business-profile": "0.0.0",
104
- "@ainyc/canonry-integration-openai-ads": "0.0.0",
105
- "@ainyc/canonry-integration-google-places": "0.0.0",
102
+ "@ainyc/canonry-integration-google-tag-manager": "0.0.0",
106
103
  "@ainyc/canonry-integration-traffic": "0.0.0",
104
+ "@ainyc/canonry-integration-openai-ads": "0.0.0",
105
+ "@ainyc/canonry-integration-google": "0.0.0",
107
106
  "@ainyc/canonry-integration-wordpress": "0.0.0",
108
107
  "@ainyc/canonry-intelligence": "0.0.0",
108
+ "@ainyc/canonry-integration-google-places": "0.0.0",
109
+ "@ainyc/canonry-provider-claude": "0.0.0",
109
110
  "@ainyc/canonry-provider-cdp": "0.0.0",
110
111
  "@ainyc/canonry-provider-gemini": "0.0.0",
111
- "@ainyc/canonry-provider-claude": "0.0.0",
112
112
  "@ainyc/canonry-provider-local": "0.0.0",
113
- "@ainyc/canonry-provider-openai": "0.0.0",
114
- "@ainyc/canonry-provider-perplexity": "0.0.0"
113
+ "@ainyc/canonry-provider-perplexity": "0.0.0",
114
+ "@ainyc/canonry-provider-openai": "0.0.0"
115
115
  },
116
116
  "scripts": {
117
117
  "build": "pnpm run build:cli && pnpm run build:web",