@canonry/canonry 6.3.1 → 7.1.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.
Files changed (44) hide show
  1. package/README.md +3 -3
  2. package/assets/agent-workspace/skills/aero/SKILL.md +2 -2
  3. package/assets/agent-workspace/skills/aero/references/reporting.md +26 -23
  4. package/assets/agent-workspace/skills/canonry/references/canonry-cli.md +55 -22
  5. package/assets/agent-workspace/skills/canonry/references/server-side-traffic.md +17 -6
  6. package/assets/assets/AuditHistoryPanel-CZWzgyrD.js +1 -0
  7. package/assets/assets/{BacklinksPage-aBcxpN_9.js → BacklinksPage-D23A-ahd.js} +1 -1
  8. package/assets/assets/ChartPrimitives-CYlrwLJs.js +1 -0
  9. package/assets/assets/{HistoryPage-PoBuxiY_.js → HistoryPage-BKGVxmNz.js} +1 -1
  10. package/assets/assets/MeasurementPropertyPage-BSxn6_RB.js +1 -0
  11. package/assets/assets/ProjectPage-D9W8G_1m.js +8 -0
  12. package/assets/assets/{RunsPage-CHHxOpzo.js → RunsPage-CeBBjLSE.js} +1 -1
  13. package/assets/assets/{SettingsPage-CNKnrLXC.js → SettingsPage-Jp5Yp4cz.js} +1 -1
  14. package/assets/assets/SiteHealthSection-DzVegBeN.js +4 -0
  15. package/assets/assets/{TrafficPage-CY-ibXnb.js → TrafficPage-B66AYwWk.js} +2 -2
  16. package/assets/assets/{TrafficSourceDetailPage-BgiPXubs.js → TrafficSourceDetailPage-CXtq1yES.js} +1 -1
  17. package/assets/assets/{extract-error-message-H1dzzfBP.js → extract-error-message-BVa0lOze.js} +1 -1
  18. package/assets/assets/index-CMe_-fAB.css +1 -0
  19. package/assets/assets/index-DuhS0WLM.js +86 -0
  20. package/assets/assets/{react-sigma_core.esm.min-uiYtR_DU.js → react-sigma_core.esm.min-60drsJa6.js} +1 -1
  21. package/assets/assets/v2-overview-adapter-CLUi2Lkv.js +1 -0
  22. package/assets/assets/{vendor-recharts-llkUFBGR.js → vendor-recharts-D-cUuLZo.js} +1 -1
  23. package/assets/index.html +3 -3
  24. package/dist/{chunk-4WZUR7XX.js → chunk-22R5E5CY.js} +101 -192
  25. package/dist/{chunk-DERWXLHX.js → chunk-2OQ6D26U.js} +66 -20
  26. package/dist/{chunk-5GY5WBAF.js → chunk-IAMECH2N.js} +3 -3
  27. package/dist/{chunk-ZZEPF3A5.js → chunk-MTSFSXCG.js} +83 -19
  28. package/dist/{chunk-5FYTFE5T.js → chunk-U2S5ABOR.js} +2 -2
  29. package/dist/{chunk-7CVTTQRV.js → chunk-VDX3LYKL.js} +4460 -8332
  30. package/dist/{chunk-EV5G5QRR.js → chunk-YGHPT5B2.js} +1475 -3002
  31. package/dist/cli.js +240 -178
  32. package/dist/{demo-server-AIFR77TP.js → demo-server-TIMYQLXS.js} +5 -14
  33. package/dist/index.js +6 -6
  34. package/dist/{intelligence-service-SYISPW25.js → intelligence-service-YCMRTVCI.js} +2 -2
  35. package/dist/mcp.js +4 -4
  36. package/package.json +15 -15
  37. package/assets/assets/AuditHistoryPanel-BUYWIjlG.js +0 -1
  38. package/assets/assets/ChartPrimitives-B5okB5g-.js +0 -1
  39. package/assets/assets/MeasurementPropertyPage-DyjyqHac.js +0 -1
  40. package/assets/assets/ProjectPage-Mmv5YW-K.js +0 -8
  41. package/assets/assets/SiteHealthSection-C9RivT7G.js +0 -4
  42. package/assets/assets/index-C17E5ZcA.css +0 -1
  43. package/assets/assets/index-DSCun3I9.js +0 -86
  44. package/assets/assets/v2-overview-adapter-BQokN2eb.js +0 -1
package/assets/index.html CHANGED
@@ -12,14 +12,14 @@
12
12
  <link rel="icon" type="image/png" sizes="32x32" href="./favicon-32.png" />
13
13
  <link rel="apple-touch-icon" href="./apple-touch-icon.png" />
14
14
  <title>Canonry</title>
15
- <script type="module" crossorigin src="./assets/index-DSCun3I9.js"></script>
15
+ <script type="module" crossorigin src="./assets/index-DuhS0WLM.js"></script>
16
16
  <link rel="modulepreload" crossorigin href="./assets/vendor-tanstack-ZXXkndVj.js">
17
17
  <link rel="modulepreload" crossorigin href="./assets/vendor-radix-twS1M3FF.js">
18
- <link rel="modulepreload" crossorigin href="./assets/vendor-recharts-llkUFBGR.js">
18
+ <link rel="modulepreload" crossorigin href="./assets/vendor-recharts-D-cUuLZo.js">
19
19
  <link rel="modulepreload" crossorigin href="./assets/vendor-lucide-N6vOpZmh.js">
20
20
  <link rel="modulepreload" crossorigin href="./assets/vendor-markdown-B4giJcws.js">
21
21
  <link rel="modulepreload" crossorigin href="./assets/vendor-yaml-GWJz5H2G.js">
22
- <link rel="stylesheet" crossorigin href="./assets/index-C17E5ZcA.css">
22
+ <link rel="stylesheet" crossorigin href="./assets/index-CMe_-fAB.css">
23
23
  </head>
24
24
  <body>
25
25
  <div id="root"></div>
@@ -17,23 +17,24 @@ import {
17
17
  resolveOperatorApiKeyIds,
18
18
  resolveSentimentInstallConfig,
19
19
  runWithUsageTags,
20
+ saveConfig,
20
21
  saveConfigPatch,
21
22
  sentimentInstallReadiness
22
- } from "./chunk-ZZEPF3A5.js";
23
+ } from "./chunk-MTSFSXCG.js";
23
24
  import {
24
25
  computeFactorAverages,
25
26
  deleteSiteCrawlGraphLayout,
26
27
  persistSiteCrawlGraphLayout,
27
28
  prepareSiteCrawlGraphLayout,
28
29
  recordedSharePct
29
- } from "./chunk-5FYTFE5T.js";
30
+ } from "./chunk-U2S5ABOR.js";
30
31
  import {
31
32
  CanonryMcpToolNames,
32
33
  CliError,
33
34
  PACKAGE_VERSION,
34
35
  canonryMcpTools,
35
36
  isMachineFormat
36
- } from "./chunk-DERWXLHX.js";
37
+ } from "./chunk-2OQ6D26U.js";
37
38
  import {
38
39
  CC_CACHE_DIR,
39
40
  DUCKDB_SPEC,
@@ -161,6 +162,7 @@ import {
161
162
  newerFullSweep,
162
163
  nextRunFromCron,
163
164
  nextRunFromSchedule,
165
+ notProbeRun,
164
166
  notifications,
165
167
  parseCookieHeader,
166
168
  parseJsonColumn,
@@ -214,7 +216,7 @@ import {
214
216
  siteLivenessState,
215
217
  toAlertView,
216
218
  usageCounters
217
- } from "./chunk-7CVTTQRV.js";
219
+ } from "./chunk-VDX3LYKL.js";
218
220
  import {
219
221
  AGENT_MEMORY_VALUE_MAX_BYTES,
220
222
  AGENT_NONE,
@@ -330,6 +332,7 @@ import {
330
332
  effectiveBrandNames,
331
333
  effectiveDomains,
332
334
  embedClientConfigForRequest,
335
+ embedProjectTabsError,
333
336
  extractProviderHttpStatus,
334
337
  factorStatusFromScore,
335
338
  filterCapturedCitedUrls,
@@ -375,6 +378,7 @@ import {
375
378
  normalizeAgentSlug,
376
379
  normalizeIdTokens,
377
380
  normalizeMeasurementExecutionQueryText,
381
+ normalizeProjectDomain,
378
382
  normalizeServedModel,
379
383
  normalizeSiteAuditRunRequest,
380
384
  normalizeUrlPath,
@@ -420,7 +424,7 @@ import {
420
424
  visibilityReportRequestSchema,
421
425
  winnabilityClassLabel,
422
426
  withRetry
423
- } from "./chunk-EV5G5QRR.js";
427
+ } from "./chunk-YGHPT5B2.js";
424
428
 
425
429
  // src/runtime-context.ts
426
430
  function cliRuntimeContext(env = process.env, stdio = process) {
@@ -440,9 +444,6 @@ var TELEMETRY_ENDPOINT = "https://canonry.ai/api/telemetry";
440
444
  var TIMEOUT_MS = 3e3;
441
445
  var ANON_ID_ENV_VAR = "CANONRY_ANONYMOUS_ID";
442
446
  var ANON_ID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
443
- function shouldDropTelemetryEvent(event, properties) {
444
- return isGhostTelemetryEvent(event, properties);
445
- }
446
447
  function bucketCliCommandDuration(durationMs) {
447
448
  const duration = Number.isFinite(durationMs) ? Math.max(0, durationMs) : 0;
448
449
  if (duration < 1e3) return "under_1s";
@@ -486,7 +487,7 @@ function setTelemetrySource(source) {
486
487
  function resolveTelemetryStatus(input) {
487
488
  const base = {
488
489
  configuredEnabled: input.configuredEnabled,
489
- ...input.anonymousId ? { anonymousId: maskAnonymousId(input.anonymousId) } : {},
490
+ ...input.anonymousId ? { anonymousId: maskTelemetryAnonymousId(input.anonymousId) } : {},
490
491
  target: "local"
491
492
  };
492
493
  if (input.canonryTelemetryDisabled === "1") {
@@ -501,9 +502,6 @@ function resolveTelemetryStatus(input) {
501
502
  if (input.configState === "unavailable") return { ...base, enabled: true, reason: "CONFIG_UNAVAILABLE" };
502
503
  return { ...base, enabled: true, reason: "enabled" };
503
504
  }
504
- function maskAnonymousId(value) {
505
- return maskTelemetryAnonymousId(value);
506
- }
507
505
  function getTelemetryStatus() {
508
506
  const env = {
509
507
  canonryTelemetryDisabled: process.env.CANONRY_TELEMETRY_DISABLED,
@@ -629,6 +627,10 @@ function detectAndTrackUpgrade() {
629
627
  function trackEvent(event, properties, options) {
630
628
  void deliverEvent(event, properties, options);
631
629
  }
630
+ function recordDashboardEvent(event) {
631
+ const { event: eventName, eventId, ...properties } = event;
632
+ trackEvent(eventName, properties, { source: "dashboard", eventId: String(eventId) });
633
+ }
632
634
  function setTelemetryPreference(enabled, method) {
633
635
  loadConfig();
634
636
  const announce = !enabled && isTelemetryEnabled();
@@ -637,7 +639,7 @@ function setTelemetryPreference(enabled, method) {
637
639
  }
638
640
  function deliverEvent(event, properties, options, delivery = {}) {
639
641
  if (!delivery.preferenceChecked && !isTelemetryEnabled()) return Promise.resolve();
640
- if (shouldDropTelemetryEvent(event, properties)) return Promise.resolve();
642
+ if (isGhostTelemetryEvent(event, properties)) return Promise.resolve();
641
643
  const anonymousId = getOrCreateAnonymousId();
642
644
  if (!anonymousId) return Promise.resolve();
643
645
  const payload = {
@@ -890,92 +892,6 @@ var GOOGLE_ADS_MAX_CUSTOMER_CLIENTS = 1e3;
890
892
  var GOOGLE_ADS_DEFAULT_CUSTOMER_CLIENT_DEPTH = 1;
891
893
  var GOOGLE_ADS_MAX_CUSTOMER_CLIENT_DEPTH = 10;
892
894
 
893
- // ../integration-google-ads/src/goal-semantics.ts
894
- function addInclusion(included, action, inclusion) {
895
- const existing = included.get(action.resourceName);
896
- if (existing) {
897
- existing.includedBy.push(inclusion);
898
- return;
899
- }
900
- included.set(action.resourceName, { conversionAction: action, includedBy: [inclusion] });
901
- }
902
- function resolveEffectiveCampaignGoalInputs(inputs) {
903
- const actions = inputs.conversionActions.map((row) => row.conversionAction);
904
- const actionsByResource = new Map(actions.map((action) => [action.resourceName, action]));
905
- const customGoalsByResource = new Map(
906
- inputs.customGoals.map((row) => [row.customConversionGoal.resourceName, row.customConversionGoal])
907
- );
908
- return inputs.campaignConfigs.map((row) => {
909
- const config = row.conversionGoalCampaignConfig;
910
- let categoryGoalSource = "UNKNOWN";
911
- let categoryOriginGoals = [];
912
- if (config.goalConfigLevel === "CUSTOMER") {
913
- categoryGoalSource = "CUSTOMER";
914
- categoryOriginGoals = inputs.customerGoals.map(({ customerConversionGoal: goal }) => ({
915
- resourceName: goal.resourceName,
916
- source: "CUSTOMER",
917
- category: goal.category,
918
- origin: goal.origin,
919
- biddable: goal.biddable === true
920
- }));
921
- } else if (config.goalConfigLevel === "CAMPAIGN") {
922
- categoryGoalSource = "CAMPAIGN";
923
- categoryOriginGoals = inputs.campaignGoals.filter(({ campaignConversionGoal: goal }) => goal.campaign === config.campaign).map(({ campaignConversionGoal: goal }) => ({
924
- resourceName: goal.resourceName,
925
- source: "CAMPAIGN",
926
- category: goal.category,
927
- origin: goal.origin,
928
- biddable: goal.biddable === true
929
- }));
930
- }
931
- const included = /* @__PURE__ */ new Map();
932
- for (const goal of categoryOriginGoals) {
933
- if (!goal.biddable) continue;
934
- for (const action of actions) {
935
- if (action.primaryForGoal !== false && action.category === goal.category && action.origin === goal.origin) {
936
- addInclusion(included, action, {
937
- source: goal.source === "CUSTOMER" ? "CUSTOMER_GOAL" : "CAMPAIGN_GOAL",
938
- goalResourceName: goal.resourceName,
939
- category: goal.category,
940
- origin: goal.origin
941
- });
942
- }
943
- }
944
- }
945
- let customGoal = null;
946
- let missingCustomGoalResourceName;
947
- const missingConversionActionResourceNames = [];
948
- if (config.goalConfigLevel === "CAMPAIGN" && config.customConversionGoal) {
949
- customGoal = customGoalsByResource.get(config.customConversionGoal) ?? null;
950
- if (!customGoal) {
951
- missingCustomGoalResourceName = config.customConversionGoal;
952
- } else {
953
- for (const resourceName of customGoal.conversionActions ?? []) {
954
- const action = actionsByResource.get(resourceName);
955
- if (!action) {
956
- missingConversionActionResourceNames.push(resourceName);
957
- continue;
958
- }
959
- addInclusion(included, action, {
960
- source: "CUSTOM_GOAL",
961
- goalResourceName: customGoal.resourceName
962
- });
963
- }
964
- }
965
- }
966
- return {
967
- campaign: row.campaign,
968
- config,
969
- categoryGoalSource,
970
- categoryOriginGoals,
971
- customGoal,
972
- conversionActions: [...included.values()],
973
- ...missingCustomGoalResourceName ? { missingCustomGoalResourceName } : {},
974
- missingConversionActionResourceNames
975
- };
976
- });
977
- }
978
-
979
895
  // ../integration-google-ads/src/types.ts
980
896
  var GoogleAdsApiError = class extends Error {
981
897
  constructor(message, status, providerStatus, requestId, retryAfter) {
@@ -1576,8 +1492,7 @@ var GoogleAdsClient = class {
1576
1492
  ...raw,
1577
1493
  // A result exactly at the cap may have more rows upstream. Treat it
1578
1494
  // as incomplete rather than silently deriving absent campaign goals.
1579
- campaignGoalsComplete: campaignGoals.data.length < GOOGLE_ADS_MAX_RESULT_ROWS,
1580
- effectiveCampaignGoalInputs: resolveEffectiveCampaignGoalInputs(raw)
1495
+ campaignGoalsComplete: campaignGoals.data.length < GOOGLE_ADS_MAX_RESULT_ROWS
1581
1496
  },
1582
1497
  metadata: {
1583
1498
  apiVersion: GOOGLE_ADS_API_VERSION,
@@ -4237,7 +4152,7 @@ function parseTrackedQueryResponse(body, model) {
4237
4152
  provider: "gemini",
4238
4153
  rawResponse,
4239
4154
  model,
4240
- servedModel: extractServedModel(rawResponse),
4155
+ servedModel: normalizeServedModel(rawResponse.modelVersion),
4241
4156
  groundingSources: parsed.groundingSources,
4242
4157
  searchQueries: parsed.searchQueries,
4243
4158
  usage: extractUsageFromRaw(rawResponse),
@@ -4261,9 +4176,6 @@ function normalizeResult(raw) {
4261
4176
  function hasParsedResponseContent(rawResponse) {
4262
4177
  return Array.isArray(rawResponse.candidates) && rawResponse.candidates.length > 0;
4263
4178
  }
4264
- function extractServedModel(rawResponse) {
4265
- return normalizeServedModel(rawResponse.modelVersion);
4266
- }
4267
4179
  function reparseStoredResult(rawResponse) {
4268
4180
  const groundingSources = extractGroundingMetadataFromRaw(rawResponse);
4269
4181
  const searchQueries = extractSearchQueriesFromRaw(rawResponse);
@@ -4447,49 +4359,25 @@ var DEFAULT_OUTPUT_DIMENSIONALITY = 768;
4447
4359
  var CLUSTERING_TASK_TYPE = "CLUSTERING";
4448
4360
  async function embedQueries(queries2, options) {
4449
4361
  if (queries2.length === 0) return [];
4450
- if (!options.apiKey && !options.client) {
4451
- throw new Error("embedQueries: missing apiKey");
4452
- }
4453
- const client = options.client ?? createGeminiEmbedClient(options.apiKey, options.baseUrl);
4454
- return client.embedBatch(queries2, {
4362
+ if (!options.apiKey) throw new Error("embedQueries: missing apiKey");
4363
+ const genai = new GoogleGenAI2({ apiKey: options.apiKey, ...options.baseUrl ? { httpOptions: { baseUrl: options.baseUrl } } : {} });
4364
+ const response = await genai.models.embedContent({
4455
4365
  model: options.model ?? DEFAULT_EMBED_MODEL,
4456
- taskType: CLUSTERING_TASK_TYPE,
4457
- outputDimensionality: options.outputDimensionality ?? DEFAULT_OUTPUT_DIMENSIONALITY
4366
+ contents: queries2,
4367
+ config: { taskType: CLUSTERING_TASK_TYPE, outputDimensionality: options.outputDimensionality ?? DEFAULT_OUTPUT_DIMENSIONALITY }
4458
4368
  });
4369
+ return extractEmbeddingVectors(response, queries2.length);
4459
4370
  }
4460
4371
  function extractEmbeddingVectors(response, expectedLength) {
4461
4372
  const embeddings = response?.embeddings ?? [];
4462
4373
  if (embeddings.length !== expectedLength) {
4463
- throw new Error(
4464
- `embedQueries: expected ${expectedLength} embeddings, got ${embeddings.length}`
4465
- );
4374
+ throw new Error(`embedQueries: expected ${expectedLength} embeddings, got ${embeddings.length}`);
4466
4375
  }
4467
4376
  return embeddings.map((e, i) => {
4468
- if (!e.values || e.values.length === 0) {
4469
- throw new Error(`embedQueries: missing values for query at index ${i}`);
4470
- }
4377
+ if (!e.values || e.values.length === 0) throw new Error(`embedQueries: missing values for query at index ${i}`);
4471
4378
  return e.values;
4472
4379
  });
4473
4380
  }
4474
- function createEmbedGenAI(apiKey, baseUrl) {
4475
- return new GoogleGenAI2({ apiKey, ...baseUrl ? { httpOptions: { baseUrl } } : {} });
4476
- }
4477
- function createGeminiEmbedClient(apiKey, baseUrl) {
4478
- const genai = createEmbedGenAI(apiKey, baseUrl);
4479
- return {
4480
- async embedBatch(queries2, opts) {
4481
- const response = await genai.models.embedContent({
4482
- model: opts.model,
4483
- contents: queries2,
4484
- config: {
4485
- taskType: opts.taskType,
4486
- outputDimensionality: opts.outputDimensionality
4487
- }
4488
- });
4489
- return extractEmbeddingVectors(response, queries2.length);
4490
- }
4491
- };
4492
- }
4493
4381
 
4494
4382
  // ../provider-gemini/src/list-models.ts
4495
4383
  function listModels(config, signal) {
@@ -4727,7 +4615,7 @@ function buildTrackedQueryRequest2(input) {
4727
4615
  // search-required-v1: web_search is the only tool, so requiring a tool
4728
4616
  // call requires a search. See OPENAI_RETRIEVAL_CONTRACT.
4729
4617
  tool_choice: "required",
4730
- input: buildPrompt2(input.query)
4618
+ input: input.query
4731
4619
  };
4732
4620
  return { endpoint: OPENAI_RESPONSES_ENDPOINT, body };
4733
4621
  }
@@ -4751,7 +4639,7 @@ function parseTrackedQueryResponse2(body, model) {
4751
4639
  provider: "openai",
4752
4640
  rawResponse,
4753
4641
  model,
4754
- servedModel: extractServedModel2(rawResponse),
4642
+ servedModel: normalizeServedModel(rawResponse.model),
4755
4643
  groundingSources: parsed.groundingSources,
4756
4644
  searchQueries: parsed.searchQueries,
4757
4645
  retrievalStatus: parsed.retrievalStatus,
@@ -4778,9 +4666,6 @@ function normalizeResult2(raw) {
4778
4666
  function hasParsedResponseContent2(rawResponse) {
4779
4667
  return Array.isArray(rawResponse.output) && rawResponse.output.length > 0;
4780
4668
  }
4781
- function extractServedModel2(rawResponse) {
4782
- return normalizeServedModel(rawResponse.model);
4783
- }
4784
4669
  function reparseStoredResult2(rawResponse) {
4785
4670
  const groundingSources = extractGroundingSourcesFromRaw(rawResponse);
4786
4671
  const searchQueries = extractSearchQueriesFromRaw2(rawResponse);
@@ -4805,9 +4690,6 @@ function extractRetrievalStatusFromRaw(rawResponse) {
4805
4690
  }
4806
4691
  return RetrievalStatuses["not-used"];
4807
4692
  }
4808
- function buildPrompt2(query) {
4809
- return query;
4810
- }
4811
4693
  function extractResponseText(response) {
4812
4694
  try {
4813
4695
  const parts = [];
@@ -5235,7 +5117,7 @@ function parseTrackedQueryResponse3(body, model) {
5235
5117
  provider: "claude",
5236
5118
  rawResponse,
5237
5119
  model,
5238
- servedModel: extractServedModel3(rawResponse),
5120
+ servedModel: extractServedModel(rawResponse),
5239
5121
  groundingSources: parsed.groundingSources,
5240
5122
  searchQueries: parsed.searchQueries,
5241
5123
  retrievalStatus: parsed.retrievalStatus,
@@ -5264,7 +5146,7 @@ function normalizeResult3(raw) {
5264
5146
  function hasParsedResponseContent3(rawResponse) {
5265
5147
  return Array.isArray(rawResponse.content) && rawResponse.content.length > 0;
5266
5148
  }
5267
- function extractServedModel3(rawResponse) {
5149
+ function extractServedModel(rawResponse) {
5268
5150
  return normalizeServedModel(rawResponse.model);
5269
5151
  }
5270
5152
  function reparseStoredResult3(rawResponse) {
@@ -5802,7 +5684,7 @@ function buildTrackedQueryRequest4(input) {
5802
5684
  },
5803
5685
  {
5804
5686
  role: "user",
5805
- content: buildPrompt3(input.query, input.location)
5687
+ content: buildPrompt2(input.query, input.location)
5806
5688
  }
5807
5689
  ]
5808
5690
  };
@@ -5830,7 +5712,7 @@ function parseTrackedQueryResponse4(body, model) {
5830
5712
  provider: "local",
5831
5713
  rawResponse,
5832
5714
  model,
5833
- servedModel: extractServedModel4(rawResponse),
5715
+ servedModel: normalizeServedModel(rawResponse.model),
5834
5716
  groundingSources: [],
5835
5717
  searchQueries: [],
5836
5718
  usage: extractUsageFromRaw4(rawResponse),
@@ -5851,7 +5733,7 @@ function normalizeResult4(raw) {
5851
5733
  searchQueries: raw.searchQueries
5852
5734
  };
5853
5735
  }
5854
- function buildPrompt3(query, location) {
5736
+ function buildPrompt2(query, location) {
5855
5737
  const locationContext = location ? ` The user is searching from ${location.city}, ${location.region}, ${location.country}.` : "";
5856
5738
  return `Based on your training knowledge, what websites, services, or organizations are commonly associated with "${query}"?${locationContext} List the most relevant ones and include their domain names (e.g. example.com) where you know them.`;
5857
5739
  }
@@ -5878,9 +5760,6 @@ async function generateText4(prompt, config) {
5878
5760
  );
5879
5761
  return response.choices[0]?.message?.content ?? "";
5880
5762
  }
5881
- function extractServedModel4(rawResponse) {
5882
- return normalizeServedModel(rawResponse.model);
5883
- }
5884
5763
  function extractUsageFromRaw4(rawResponse) {
5885
5764
  const usage = rawResponse.usage;
5886
5765
  if (usage === null || typeof usage !== "object") return void 0;
@@ -6723,7 +6602,7 @@ function parseTrackedQueryResponse5(body, model) {
6723
6602
  provider: "perplexity",
6724
6603
  rawResponse: body,
6725
6604
  model: resolveModel3(model),
6726
- servedModel: extractServedModel5(body),
6605
+ servedModel: normalizeServedModel(body.model),
6727
6606
  groundingSources: parsed.groundingSources,
6728
6607
  searchQueries: parsed.searchQueries,
6729
6608
  retrievalStatus: parsed.retrievalStatus,
@@ -6756,9 +6635,6 @@ function hasParsedResponseContent4(rawResponse) {
6756
6635
  if (!nestedResponse) return false;
6757
6636
  return Array.isArray(nestedResponse.choices) && nestedResponse.choices.length > 0 || Array.isArray(nestedResponse.search_results) && nestedResponse.search_results.length > 0 || Array.isArray(nestedResponse.citations) && nestedResponse.citations.length > 0;
6758
6637
  }
6759
- function extractServedModel5(rawResponse) {
6760
- return normalizeServedModel(rawResponse.model);
6761
- }
6762
6638
  function reparseStoredResult4(rawResponse) {
6763
6639
  const agent = agentResponseOf(rawResponse);
6764
6640
  if (agent) return parseAgentResponse(agent);
@@ -7197,7 +7073,7 @@ async function executeTrackedQuery6(input) {
7197
7073
  provider: "muse",
7198
7074
  rawResponse,
7199
7075
  model,
7200
- servedModel: extractServedModel6(rawResponse),
7076
+ servedModel: normalizeServedModel(rawResponse.model),
7201
7077
  groundingSources: parsed.groundingSources,
7202
7078
  searchQueries: parsed.searchQueries,
7203
7079
  retrievalStatus: parsed.retrievalStatus,
@@ -7208,9 +7084,6 @@ async function executeTrackedQuery6(input) {
7208
7084
  throw new Error(`[provider-muse] ${describeError(err)}`);
7209
7085
  }
7210
7086
  }
7211
- function extractServedModel6(rawResponse) {
7212
- return normalizeServedModel(rawResponse.model);
7213
- }
7214
7087
  function extractUsage(rawResponse) {
7215
7088
  const usage = asRecord(rawResponse.usage);
7216
7089
  if (!usage) return void 0;
@@ -7422,7 +7295,7 @@ var museAdapter = {
7422
7295
 
7423
7296
  // src/embed.ts
7424
7297
  var DEFAULT_EMBED_PROJECT_TABS = ["overview"];
7425
- var SERVER_ENFORCED_EMBED_PROJECT_TABS = ["overview", "technical-aeo", "report"];
7298
+ var SERVER_ENFORCED_EMBED_PROJECT_TABS = ["overview", "technical-aeo"];
7426
7299
  function unsupportedEmbedProjectTabs(projectTabs) {
7427
7300
  if (!projectTabs) return [];
7428
7301
  const supported = new Set(SERVER_ENFORCED_EMBED_PROJECT_TABS);
@@ -7437,6 +7310,8 @@ function resolveEmbedConfig(env, config) {
7437
7310
  const views = normalizeIdTokens(rawViews);
7438
7311
  const rawProjectTabs = env.CANONRY_EMBED_PROJECT_TABS !== void 0 ? splitList(env.CANONRY_EMBED_PROJECT_TABS) : splitList(embed?.projectTabs);
7439
7312
  const projectTabs = normalizeIdTokens(rawProjectTabs) ?? (enabled ? DEFAULT_EMBED_PROJECT_TABS : void 0);
7313
+ const projectTabsError = enabled ? embedProjectTabsError(projectTabs) : void 0;
7314
+ if (projectTabsError) throw new Error(projectTabsError);
7440
7315
  return {
7441
7316
  enabled,
7442
7317
  allowedOrigins,
@@ -7976,13 +7851,38 @@ function fitToByteBudget(payload) {
7976
7851
  return JSON.stringify(current);
7977
7852
  }
7978
7853
 
7854
+ // src/ui-telemetry-gate.ts
7855
+ var UI_EVENT_MINUTE_CAPACITY = 60;
7856
+ var UI_EVENT_HOUR_CAPACITY = 600;
7857
+ function createUiTelemetryGate(options = {}) {
7858
+ const now = options.now ?? Date.now;
7859
+ const enabled = options.enabled ?? isTelemetryEnabled;
7860
+ const record2 = options.record ?? recordDashboardEvent;
7861
+ const buckets = [
7862
+ { capacity: UI_EVENT_MINUTE_CAPACITY, perMs: UI_EVENT_MINUTE_CAPACITY / 6e4, tokens: UI_EVENT_MINUTE_CAPACITY },
7863
+ { capacity: UI_EVENT_HOUR_CAPACITY, perMs: UI_EVENT_HOUR_CAPACITY / 36e5, tokens: UI_EVENT_HOUR_CAPACITY }
7864
+ ];
7865
+ let refilledAt = now();
7866
+ return (event) => {
7867
+ if (!enabled()) return false;
7868
+ const at = now();
7869
+ const elapsed = Math.max(0, at - refilledAt);
7870
+ refilledAt = at;
7871
+ for (const bucket of buckets) bucket.tokens = Math.min(bucket.capacity, bucket.tokens + elapsed * bucket.perMs);
7872
+ if (buckets.some((bucket) => bucket.tokens < 1)) return false;
7873
+ for (const bucket of buckets) bucket.tokens -= 1;
7874
+ record2(event);
7875
+ return true;
7876
+ };
7877
+ }
7878
+
7979
7879
  // src/instance-identity.ts
7980
7880
  function nonBlank(value) {
7981
7881
  const trimmed = value?.trim();
7982
7882
  return trimmed ? trimmed : void 0;
7983
7883
  }
7984
7884
  function resolveBuildCommit(env = process.env) {
7985
- const embedded = true ? "a9545eefb45af8bb1a00366b6e75ce25bb3f4c2b" : void 0;
7885
+ const embedded = true ? "9ddd0d5e4575e0983aae488bd457b664c8b9fd4a" : void 0;
7986
7886
  return nonBlank(embedded) ?? nonBlank(env.CANONRY_COMMIT);
7987
7887
  }
7988
7888
  function resolveInstanceIdentity(env = process.env) {
@@ -12949,18 +12849,17 @@ function withAttemptTimeout(promise, timeoutMs, label) {
12949
12849
  );
12950
12850
  });
12951
12851
  }
12952
- async function embedWithRetry(fn, opts = {}) {
12953
- const attemptTimeoutMs = opts.attemptTimeoutMs ?? EMBED_ATTEMPT_TIMEOUT_MS;
12852
+ async function embedWithRetry(fn) {
12853
+ const attemptTimeoutMs = EMBED_ATTEMPT_TIMEOUT_MS;
12954
12854
  return withRetry(
12955
12855
  () => withAttemptTimeout(fn(), attemptTimeoutMs, "Discovery embedding call"),
12956
12856
  {
12957
- maxRetries: opts.maxRetries ?? EMBED_RETRY_MAX_RETRIES,
12857
+ maxRetries: EMBED_RETRY_MAX_RETRIES,
12958
12858
  isRetryable: isRetryableHttpError,
12959
12859
  maxDelayMs: EMBED_RETRY_MAX_DELAY_MS,
12960
- sleep: opts.sleep,
12961
- onRetry: opts.onRetry ?? (({ attempt, delayMs }) => {
12860
+ onRetry: ({ attempt, delayMs }) => {
12962
12861
  log13.warn("discovery.embed.retry", { attempt, delayMs });
12963
- })
12862
+ }
12964
12863
  }
12965
12864
  );
12966
12865
  }
@@ -12975,7 +12874,7 @@ async function executeDiscoveryRun(opts) {
12975
12874
  const canonicalDomains = effectiveDomains({
12976
12875
  canonicalDomain: projectRow.canonicalDomain,
12977
12876
  ownedDomains: projectRow.ownedDomains
12978
- });
12877
+ }).map(normalizeProjectDomain);
12979
12878
  const brandNames = effectiveBrandNames({
12980
12879
  displayName: projectRow.displayName,
12981
12880
  aliases: projectRow.aliases
@@ -12987,7 +12886,7 @@ async function executeDiscoveryRun(opts) {
12987
12886
  canonicalDomains,
12988
12887
  competitorDomains: projectCompetitors
12989
12888
  };
12990
- const deps = opts.deps ?? buildDefaultDeps(opts.registry);
12889
+ const deps = buildDefaultDeps(opts.registry);
12991
12890
  const result2 = await executeDiscovery({
12992
12891
  db: opts.db,
12993
12892
  runId: opts.runId,
@@ -13049,8 +12948,8 @@ function buildDefaultDeps(registry) {
13049
12948
  async seed(input) {
13050
12949
  const prompt = buildSeedPrompt(input);
13051
12950
  const providerNames = input.seedProviders && input.seedProviders.length > 0 ? [...input.seedProviders] : ["gemini"];
13052
- const perProvider = await Promise.all(providerNames.map(async (name) => {
13053
- const seedProvider = seedProviderFor(name);
12951
+ const admittedProviders = providerNames.map((name) => ({ name, seedProvider: seedProviderFor(name) }));
12952
+ const perProvider = await Promise.all(admittedProviders.map(async ({ name, seedProvider }) => {
13054
12953
  const raw = await seedProvider.adapter.executeTrackedQuery(
13055
12954
  {
13056
12955
  query: prompt,
@@ -14795,7 +14694,7 @@ function readStoredGroundingSources(rawResponse) {
14795
14694
  return result2;
14796
14695
  }
14797
14696
  async function backfillInsightsCommand(project, opts) {
14798
- const { IntelligenceService: IntelligenceService2 } = await import("./intelligence-service-SYISPW25.js");
14697
+ const { IntelligenceService: IntelligenceService2 } = await import("./intelligence-service-YCMRTVCI.js");
14799
14698
  const config = loadConfig();
14800
14699
  const db = createClient(config.database);
14801
14700
  migrate(db);
@@ -16554,8 +16453,9 @@ var Notifier = class {
16554
16453
  })),
16555
16454
  dashboardUrl: `${this.serverUrl}/projects/${project.name}`
16556
16455
  };
16557
- await this.sendWebhook(config.url, payload, notif.id, projectId, notif.webhookSecret ?? null);
16558
- for (const insight of relevantInsights) this.rememberInsightNotified(projectId, insight);
16456
+ if (await this.sendWebhook(config.url, payload, notif.id, projectId, notif.webhookSecret ?? null)) {
16457
+ for (const insight of relevantInsights) this.rememberInsightNotified(projectId, insight);
16458
+ }
16559
16459
  }
16560
16460
  }
16561
16461
  }
@@ -16725,7 +16625,8 @@ var Notifier = class {
16725
16625
  const groupSiblings = this.db.select().from(runs).where(and18(
16726
16626
  eq20(runs.projectId, projectId),
16727
16627
  eq20(runs.kind, thisRun.kind),
16728
- eq20(runs.createdAt, thisRun.createdAt)
16628
+ eq20(runs.createdAt, thisRun.createdAt),
16629
+ notProbeRun()
16729
16630
  )).all();
16730
16631
  const stillPending = groupSiblings.some((r) => r.status === "queued" || r.status === "running");
16731
16632
  if (stillPending) return [];
@@ -16751,7 +16652,8 @@ var Notifier = class {
16751
16652
  and18(
16752
16653
  eq20(runs.projectId, projectId),
16753
16654
  eq20(runs.kind, thisRun.kind),
16754
- or(eq20(runs.status, "completed"), eq20(runs.status, "partial"))
16655
+ or(eq20(runs.status, "completed"), eq20(runs.status, "partial")),
16656
+ notProbeRun()
16755
16657
  )
16756
16658
  ).orderBy(desc9(runs.createdAt), desc9(runs.id)).limit(RECENT_FETCH_LIMIT).all();
16757
16659
  const groups = groupRunsByCreatedAt(recentRuns);
@@ -19236,11 +19138,12 @@ function truncateToByteLimit(text, maxBytes) {
19236
19138
  if (Buffer.byteLength(text, "utf8") <= maxBytes) return text;
19237
19139
  const suffix = "\u2026[truncated]";
19238
19140
  const budget = maxBytes - Buffer.byteLength(suffix, "utf8");
19239
- let buf = Buffer.from(text, "utf8").subarray(0, budget);
19240
- while (buf.length > 0 && (buf[buf.length - 1] & 192) === 128) {
19241
- buf = buf.subarray(0, buf.length - 1);
19141
+ const buf = Buffer.from(text, "utf8");
19142
+ let end = budget;
19143
+ while (end > 0 && (buf[end] & 192) === 128) {
19144
+ end -= 1;
19242
19145
  }
19243
- return buf.toString("utf8") + suffix;
19146
+ return buf.subarray(0, end).toString("utf8") + suffix;
19244
19147
  }
19245
19148
  async function runSummaryLlm(args) {
19246
19149
  const context = {
@@ -19261,8 +19164,7 @@ async function compactMessages(args) {
19261
19164
  if (split === 0) return null;
19262
19165
  const chunk = messages.slice(0, split);
19263
19166
  const suffix = messages.slice(split);
19264
- const summarize = args.summarize ?? runSummaryLlm;
19265
- const rawSummary = await summarize({ model: args.model, chunk, getApiKey: args.getApiKey });
19167
+ const rawSummary = await runSummaryLlm({ model: args.model, chunk, getApiKey: args.getApiKey });
19266
19168
  const summary = truncateToByteLimit(rawSummary, AGENT_MEMORY_VALUE_MAX_BYTES);
19267
19169
  writeCompactionNote(args.db, {
19268
19170
  projectId: args.projectId,
@@ -22197,6 +22099,7 @@ function createGoogleMarketingConfigCredentialStore(input) {
22197
22099
  };
22198
22100
  }
22199
22101
  async function createServer(opts) {
22102
+ const embed = resolveEmbedConfig(process.env, opts.config);
22200
22103
  const operatorApiKeyIds = resolveOperatorApiKeyIds(process.env);
22201
22104
  const dashboardManagedRunKinds = resolveDashboardManagedRunKinds(process.env, opts.config);
22202
22105
  const operationalLogs = new OperationalLogStore(opts.db, {
@@ -23025,7 +22928,6 @@ async function createServer(opts) {
23025
22928
  const rawBasePath = process.env.CANONRY_BASE_PATH ?? opts.config.basePath;
23026
22929
  const normalizedBasePath = rawBasePath ? "/" + rawBasePath.replace(/^\//, "").replace(/\/?$/, "/") : void 0;
23027
22930
  const basePath = normalizedBasePath === "/" ? void 0 : normalizedBasePath;
23028
- const embed = resolveEmbedConfig(process.env, opts.config);
23029
22931
  const embedCsp = embed.enabled ? frameAncestorsHeaderValue(embed.allowedOrigins) : void 0;
23030
22932
  const unsupportedProjectTabs = unsupportedEmbedProjectTabs(embed.projectTabs);
23031
22933
  if (embed.enabled && unsupportedProjectTabs.length > 0) {
@@ -23209,14 +23111,19 @@ async function createServer(opts) {
23209
23111
  password,
23210
23112
  opts.config.dashboardPasswordHash
23211
23113
  );
23212
- if (!verification.ok) {
23114
+ const onDisk = verification.ok && verification.needsRehash ? loadConfigRaw() : null;
23115
+ if (!verification.ok || onDisk && onDisk.dashboardPasswordHash !== opts.config.dashboardPasswordHash) {
23213
23116
  return reply.status(401).send({
23214
23117
  error: { code: "AUTH_INVALID", message: "Incorrect password" }
23215
23118
  });
23216
23119
  }
23217
23120
  if (verification.needsRehash) {
23218
- opts.config.dashboardPasswordHash = hashDashboardPassword(password);
23219
- saveConfigPatch(opts.config);
23121
+ if (fs9.existsSync(getConfigPath()) && (!onDisk || typeof onDisk !== "object" || Array.isArray(onDisk) || !onDisk.apiUrl || !onDisk.database || !onDisk.apiKey)) {
23122
+ throw new Error("Cannot migrate dashboard password: config.yaml is unreadable or invalid");
23123
+ }
23124
+ const migratedHash = hashDashboardPassword(password);
23125
+ saveConfig({ ...onDisk ?? opts.config, dashboardPasswordHash: migratedHash });
23126
+ opts.config.dashboardPasswordHash = migratedHash;
23220
23127
  }
23221
23128
  if (!createPasswordSession(reply)) {
23222
23129
  return reply.status(401).send({
@@ -23899,10 +23806,10 @@ async function createServer(opts) {
23899
23806
  void setTelemetryPreference(enabled, "api");
23900
23807
  opts.config.telemetry = enabled;
23901
23808
  },
23902
- recordOnboardingEvent: (event) => {
23903
- const { event: eventName, eventId, ...properties } = event;
23904
- trackEvent(eventName, properties, { source: "dashboard", eventId });
23905
- },
23809
+ recordOnboardingEvent: (event) => recordDashboardEvent(event),
23810
+ // Answers false while telemetry is off or the per-process cap is spent, so
23811
+ // the dashboard stops sending for the session.
23812
+ recordUiEvent: createUiTelemetryGate(),
23906
23813
  submitFeedback: (submission, context) => sendFeedback(submission, context),
23907
23814
  onCdpConfigure: async (host, port2) => {
23908
23815
  if (!opts.config.cdp) opts.config.cdp = {};
@@ -24017,6 +23924,8 @@ async function createServer(opts) {
24017
23924
  }
24018
23925
  if (embed.enabled) {
24019
23926
  const embedClient = embedClientConfigForRequest(embed, projectTabsOverride, themeOverride, renderTokenOverride);
23927
+ const projectTabsError = embedProjectTabsError(embedClient?.projectTabs);
23928
+ if (projectTabsError) throw validationError(projectTabsError);
24020
23929
  if (embedClient) clientConfig.embed = embedClient;
24021
23930
  }
24022
23931
  const configScript = `<script>window.__CANONRY_CONFIG__=${serializeForInlineScript(clientConfig)}</script>`;