@canonry/canonry 6.2.0 → 6.3.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 (29) hide show
  1. package/assets/agent-workspace/skills/canonry/references/canonry-cli.md +12 -0
  2. package/assets/assets/{AuditHistoryPanel-CuEMfkaA.js → AuditHistoryPanel-BUYWIjlG.js} +1 -1
  3. package/assets/assets/{BacklinksPage-CftadZ1-.js → BacklinksPage-aBcxpN_9.js} +1 -1
  4. package/assets/assets/{HistoryPage-DouRgshN.js → HistoryPage-PoBuxiY_.js} +1 -1
  5. package/assets/assets/{MeasurementPropertyPage-qfqv2qs9.js → MeasurementPropertyPage-DyjyqHac.js} +1 -1
  6. package/assets/assets/{ProjectPage-DqEVwe4t.js → ProjectPage-Mmv5YW-K.js} +1 -1
  7. package/assets/assets/{RunsPage-CUkMs0gB.js → RunsPage-CHHxOpzo.js} +1 -1
  8. package/assets/assets/{SettingsPage-LLQ40tSh.js → SettingsPage-CNKnrLXC.js} +1 -1
  9. package/assets/assets/{SiteHealthSection-Ba7foDiU.js → SiteHealthSection-C9RivT7G.js} +3 -3
  10. package/assets/assets/{TrafficPage-Cu_ZR3--.js → TrafficPage-CY-ibXnb.js} +1 -1
  11. package/assets/assets/{TrafficSourceDetailPage-NKZq7jf9.js → TrafficSourceDetailPage-BgiPXubs.js} +1 -1
  12. package/assets/assets/{extract-error-message-BdQYrz9N.js → extract-error-message-H1dzzfBP.js} +1 -1
  13. package/assets/assets/{index-HOeLz1ZL.js → index-DSCun3I9.js} +21 -21
  14. package/assets/assets/{react-sigma_core.esm.min-CZaoE5cU.js → react-sigma_core.esm.min-uiYtR_DU.js} +1 -1
  15. package/assets/assets/{v2-overview-adapter-BVx4nI49.js → v2-overview-adapter-BQokN2eb.js} +1 -1
  16. package/assets/index.html +1 -1
  17. package/dist/{chunk-Y2B7JRSB.js → chunk-5GY5WBAF.js} +3 -3
  18. package/dist/{chunk-W3GDZZNF.js → chunk-DERWXLHX.js} +15 -1
  19. package/dist/{chunk-6EPN4XY5.js → chunk-EV5G5QRR.js} +324 -280
  20. package/dist/{chunk-4EKOKWQT.js → chunk-FSRVG2H7.js} +2 -2
  21. package/dist/{chunk-2RFHQ6XT.js → chunk-OTROA7CN.js} +199 -106
  22. package/dist/{chunk-ENI3GOWW.js → chunk-QVGG76UW.js} +78 -24
  23. package/dist/{chunk-V6JUBTNL.js → chunk-ZZEPF3A5.js} +23 -3
  24. package/dist/cli.js +53 -8
  25. package/dist/{demo-server-CH7MOBXW.js → demo-server-5MNLI6GC.js} +4 -4
  26. package/dist/index.js +6 -6
  27. package/dist/{intelligence-service-4IONMOFB.js → intelligence-service-5J36RBEM.js} +2 -2
  28. package/dist/mcp.js +4 -4
  29. package/package.json +11 -11
@@ -19,21 +19,21 @@ import {
19
19
  runWithUsageTags,
20
20
  saveConfigPatch,
21
21
  sentimentInstallReadiness
22
- } from "./chunk-V6JUBTNL.js";
22
+ } from "./chunk-ZZEPF3A5.js";
23
23
  import {
24
24
  computeFactorAverages,
25
25
  deleteSiteCrawlGraphLayout,
26
26
  persistSiteCrawlGraphLayout,
27
27
  prepareSiteCrawlGraphLayout,
28
28
  recordedSharePct
29
- } from "./chunk-4EKOKWQT.js";
29
+ } from "./chunk-FSRVG2H7.js";
30
30
  import {
31
31
  CanonryMcpToolNames,
32
32
  CliError,
33
33
  PACKAGE_VERSION,
34
34
  canonryMcpTools,
35
35
  isMachineFormat
36
- } from "./chunk-W3GDZZNF.js";
36
+ } from "./chunk-DERWXLHX.js";
37
37
  import {
38
38
  CC_CACHE_DIR,
39
39
  DUCKDB_SPEC,
@@ -214,7 +214,7 @@ import {
214
214
  siteLivenessState,
215
215
  toAlertView,
216
216
  usageCounters
217
- } from "./chunk-ENI3GOWW.js";
217
+ } from "./chunk-QVGG76UW.js";
218
218
  import {
219
219
  AGENT_MEMORY_VALUE_MAX_BYTES,
220
220
  AGENT_NONE,
@@ -232,6 +232,7 @@ import {
232
232
  CheckNotificationPolicies,
233
233
  DEFAULT_VIEWER_RESEARCH_DAILY_RUN_LIMIT,
234
234
  DiscoveryCompetitorTypes,
235
+ FEEDBACK_LIMITS,
235
236
  GOOGLE_ADS_CAMPAIGN_METRICS_MAX_CAMPAIGNS,
236
237
  GOOGLE_ADS_CAMPAIGN_METRICS_MAX_DAYS,
237
238
  GOOGLE_ADS_CAMPAIGN_METRICS_MAX_ROWS,
@@ -316,6 +317,7 @@ import {
316
317
  contentBriefDtoSchema,
317
318
  createTemplateLinkDetectionTally,
318
319
  createTemplateLinkPairIndex,
320
+ deliveryFailed,
319
321
  deriveCitedUrlCandidates,
320
322
  deriveGoogleAdsEffectiveGoalGraph,
321
323
  deriveIndexCoverage,
@@ -385,7 +387,9 @@ import {
385
387
  percentOf,
386
388
  providerError,
387
389
  providerSupportsLocationContext,
390
+ quotaExceeded,
388
391
  ratioUnitSchema,
392
+ redactFeedbackText,
389
393
  registrableDomain,
390
394
  reportMonthsForDoctor,
391
395
  resolveNegativeReviewMaxStars,
@@ -416,7 +420,7 @@ import {
416
420
  visibilityReportRequestSchema,
417
421
  winnabilityClassLabel,
418
422
  withRetry
419
- } from "./chunk-6EPN4XY5.js";
423
+ } from "./chunk-EV5G5QRR.js";
420
424
 
421
425
  // src/runtime-context.ts
422
426
  function cliRuntimeContext(env = process.env, stdio = process) {
@@ -3631,7 +3635,7 @@ function createGoogleMarketingRuntime(options) {
3631
3635
 
3632
3636
  // src/server.ts
3633
3637
  import { createRequire as createRequire3 } from "module";
3634
- import crypto28 from "crypto";
3638
+ import crypto29 from "crypto";
3635
3639
  import fs9 from "fs";
3636
3640
  import path8 from "path";
3637
3641
  import { fileURLToPath as fileURLToPath3 } from "url";
@@ -7854,13 +7858,101 @@ function createApiUsageTelemetry(options = {}) {
7854
7858
  };
7855
7859
  }
7856
7860
 
7861
+ // src/feedback.ts
7862
+ import crypto4 from "crypto";
7863
+ var FEEDBACK_ENDPOINT = "https://canonry.ai/api/feedback";
7864
+ var TIMEOUT_MS2 = 1e4;
7865
+ var FEEDBACK_MAX_BODY_BYTES = 8e3;
7866
+ function feedbackSource(context) {
7867
+ const surface = classifyUsageSurface({
7868
+ userAgent: context.userAgent,
7869
+ usageLabels: { surface: context.surface }
7870
+ });
7871
+ if (surface === "cli" || surface === "dashboard") return surface;
7872
+ if (surface === "mcp-stdio" || surface === "mcp-http") return "mcp";
7873
+ return "api";
7874
+ }
7875
+ async function sendFeedback(submission, context, deps = {}) {
7876
+ const doFetch = deps.fetch ?? fetch;
7877
+ const telemetryOn = (deps.telemetryEnabled ?? isTelemetryEnabled)();
7878
+ const anonymousId = telemetryOn ? (deps.anonymousId ?? getOrCreateAnonymousId)() : void 0;
7879
+ const agent = [context.agent, context.mcpClient].map((label) => normalizeAgentSlug(label)).find((slug) => !!slug && slug !== "none");
7880
+ const payload = {
7881
+ feedbackId: crypto4.randomUUID(),
7882
+ ...anonymousId ? { anonymousId } : {},
7883
+ kind: submission.kind,
7884
+ summary: redactFeedbackText(submission.summary, FEEDBACK_LIMITS.summary),
7885
+ ...submission.details ? { details: redactFeedbackText(submission.details, FEEDBACK_LIMITS.details) } : {},
7886
+ ...submission.area ? { area: redactFeedbackText(submission.area, FEEDBACK_LIMITS.area) } : {},
7887
+ ...submission.command ? { command: redactFeedbackText(submission.command, FEEDBACK_LIMITS.command) } : {},
7888
+ ...submission.errorCode ? { errorCode: redactFeedbackText(submission.errorCode, FEEDBACK_LIMITS.errorCode) } : {},
7889
+ source: feedbackSource(context),
7890
+ ...agent ? { agent } : {},
7891
+ version: PACKAGE_VERSION.slice(0, 20),
7892
+ nodeVersion: process.versions.node.slice(0, 20),
7893
+ os: process.platform.slice(0, 20),
7894
+ arch: process.arch.slice(0, 20),
7895
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
7896
+ };
7897
+ const body = fitToByteBudget(payload);
7898
+ let response;
7899
+ try {
7900
+ response = await doFetch(FEEDBACK_ENDPOINT, {
7901
+ method: "POST",
7902
+ headers: { "Content-Type": "application/json" },
7903
+ body,
7904
+ signal: AbortSignal.timeout(TIMEOUT_MS2)
7905
+ });
7906
+ } catch {
7907
+ throw deliveryFailed("Could not reach canonry.ai to send feedback. Check the network and try again.");
7908
+ }
7909
+ if (response.status === 202 || response.ok) {
7910
+ const body2 = await response.json().catch(() => ({}));
7911
+ return { accepted: body2.accepted ?? true, id: typeof body2.id === "string" ? body2.id : payload.feedbackId };
7912
+ }
7913
+ if (response.status === 429) throw quotaExceeded("feedback submissions", { retryLater: true });
7914
+ if (response.status === 400 || response.status === 413) {
7915
+ const body2 = await response.json().catch(() => ({}));
7916
+ throw validationError("canonry.ai rejected the feedback", body2.issues ? { issues: body2.issues } : void 0);
7917
+ }
7918
+ throw deliveryFailed(`canonry.ai could not store the feedback (HTTP ${response.status}). Try again later.`);
7919
+ }
7920
+ function truncateCodePoints(value, maxCodePoints) {
7921
+ return Array.from(value).slice(0, Math.max(0, maxCodePoints)).join("");
7922
+ }
7923
+ function fitToByteBudget(payload) {
7924
+ let current = { ...payload };
7925
+ for (const field of ["details", "summary"]) {
7926
+ let serialized = JSON.stringify(current);
7927
+ let bytes = Buffer.byteLength(serialized, "utf8");
7928
+ while (bytes > FEEDBACK_MAX_BODY_BYTES) {
7929
+ const text = current[field];
7930
+ if (typeof text !== "string" || text.length === 0) break;
7931
+ const points = Array.from(text).length;
7932
+ const target = points - Math.max(1, Math.ceil((bytes - FEEDBACK_MAX_BODY_BYTES) / 4));
7933
+ if (field === "summary" && target < 1) break;
7934
+ const shorter = truncateCodePoints(text, target);
7935
+ if (field === "details" && shorter.length === 0) {
7936
+ const { details: _dropped, ...rest } = current;
7937
+ current = rest;
7938
+ } else {
7939
+ current = { ...current, [field]: shorter };
7940
+ }
7941
+ serialized = JSON.stringify(current);
7942
+ bytes = Buffer.byteLength(serialized, "utf8");
7943
+ }
7944
+ if (bytes <= FEEDBACK_MAX_BODY_BYTES) return serialized;
7945
+ }
7946
+ return JSON.stringify(current);
7947
+ }
7948
+
7857
7949
  // src/instance-identity.ts
7858
7950
  function nonBlank(value) {
7859
7951
  const trimmed = value?.trim();
7860
7952
  return trimmed ? trimmed : void 0;
7861
7953
  }
7862
7954
  function resolveBuildCommit(env = process.env) {
7863
- const embedded = true ? "633bd63832cf6af1da610e63f376dfc872975b49" : void 0;
7955
+ const embedded = true ? "a0351a3c7ac5eb8e0e4028ee004ddd5a12874575" : void 0;
7864
7956
  return nonBlank(embedded) ?? nonBlank(env.CANONRY_COMMIT);
7865
7957
  }
7866
7958
  function resolveInstanceIdentity(env = process.env) {
@@ -7871,7 +7963,7 @@ function resolveInstanceIdentity(env = process.env) {
7871
7963
  }
7872
7964
 
7873
7965
  // src/job-runner.ts
7874
- import crypto6 from "crypto";
7966
+ import crypto7 from "crypto";
7875
7967
  import fs4 from "fs";
7876
7968
  import path3 from "path";
7877
7969
  import os3 from "os";
@@ -7879,7 +7971,7 @@ import { setImmediate as yieldToEventLoop } from "timers/promises";
7879
7971
  import { and as and3, asc as asc2, count, desc, eq as eq3, inArray, isNotNull, isNull, lt, ne, sql as sql2 } from "drizzle-orm";
7880
7972
 
7881
7973
  // src/run-telemetry.ts
7882
- import crypto4 from "crypto";
7974
+ import crypto5 from "crypto";
7883
7975
  function extractRegistrableHost(input) {
7884
7976
  if (!input) return null;
7885
7977
  const trimmed = input.trim();
@@ -7899,7 +7991,7 @@ function extractRegistrableHost(input) {
7899
7991
  function hashDomain(input) {
7900
7992
  const host = extractRegistrableHost(input);
7901
7993
  if (!host) return null;
7902
- return crypto4.createHash("sha256").update(host).digest("hex");
7994
+ return crypto5.createHash("sha256").update(host).digest("hex");
7903
7995
  }
7904
7996
  function buildRunCompletedProps(input) {
7905
7997
  const totalMs = input.phases?.total_ms ?? Date.now() - input.startTime;
@@ -7980,7 +8072,7 @@ function failureStreakSampling(status, priorStreak, runId) {
7980
8072
  if (priorStreak < FAILURE_STREAK_SAMPLE_AFTER) {
7981
8073
  return { report: true, props: { failureStreak: priorStreak } };
7982
8074
  }
7983
- const bucket = crypto4.createHash("sha256").update(runId).digest().readUInt32BE(0) % FAILURE_STREAK_SAMPLE_RATE;
8075
+ const bucket = crypto5.createHash("sha256").update(runId).digest().readUInt32BE(0) % FAILURE_STREAK_SAMPLE_RATE;
7984
8076
  return {
7985
8077
  report: bucket === 0,
7986
8078
  props: { failureStreak: priorStreak, sampleRate: FAILURE_STREAK_SAMPLE_RATE }
@@ -8053,7 +8145,7 @@ function getSharedProviderExecutionGate(providerName, maxConcurrency, maxPerMinu
8053
8145
  }
8054
8146
 
8055
8147
  // src/usage-quota.ts
8056
- import crypto5 from "crypto";
8148
+ import crypto6 from "crypto";
8057
8149
  import { and as and2, eq as eq2, lte, sql } from "drizzle-orm";
8058
8150
  function getCurrentUsageDay() {
8059
8151
  return (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
@@ -8070,7 +8162,7 @@ function reserveDailyQueryQuota(db, input) {
8070
8162
  )).run();
8071
8163
  if (reserveExisting().changes === 1) return { reserved: true, used: 0 };
8072
8164
  const inserted = tx.insert(usageCounters).values({
8073
- id: crypto5.randomUUID(),
8165
+ id: crypto6.randomUUID(),
8074
8166
  scope: input.scope,
8075
8167
  period: input.period,
8076
8168
  metric: "queries",
@@ -8665,7 +8757,7 @@ var JobRunner = class {
8665
8757
  const answerLocation = runLocation && isSearchLocationIgnored(providerName, normalized.retrievalStatus) ? { location: null, requestedContext: runLocation, supportedContext: { status: "ignored" } } : { location: runLocation?.label ?? null };
8666
8758
  let screenshotRelPath = null;
8667
8759
  if (raw.screenshotPath && fs4.existsSync(raw.screenshotPath)) {
8668
- const snapshotId = crypto6.randomUUID();
8760
+ const snapshotId = crypto7.randomUUID();
8669
8761
  const screenshotDir = path3.join(os3.homedir(), ".canonry", "screenshots", runId);
8670
8762
  if (!fs4.existsSync(screenshotDir)) fs4.mkdirSync(screenshotDir, { recursive: true });
8671
8763
  const destPath = path3.join(screenshotDir, `${snapshotId}.png`);
@@ -8709,7 +8801,7 @@ var JobRunner = class {
8709
8801
  }).run();
8710
8802
  } else {
8711
8803
  this.db.insert(querySnapshots).values({
8712
- id: crypto6.randomUUID(),
8804
+ id: crypto7.randomUUID(),
8713
8805
  runId,
8714
8806
  queryId: q.id,
8715
8807
  queryText: q.query,
@@ -9249,7 +9341,7 @@ var JobRunner = class {
9249
9341
  syncUnits.push(unit);
9250
9342
  continue;
9251
9343
  }
9252
- const customId = crypto6.randomUUID().replace(/-/g, "");
9344
+ const customId = crypto7.randomUUID().replace(/-/g, "");
9253
9345
  const lines = linesByModel.get(model) ?? [];
9254
9346
  lines.push({ unit, requestedModel, customId, request, bytes: Buffer.byteLength(JSON.stringify({ custom_id: customId, params: request.body })) });
9255
9347
  linesByModel.set(model, lines);
@@ -9285,7 +9377,7 @@ var JobRunner = class {
9285
9377
  if (!capability || !reservation) throw new Error(`Provider ${providerName} cannot submit a batch for run ${ctx.runId}`);
9286
9378
  const deadlineMs = (config.batch?.deadlineHours ?? capability.defaultDeadlineHours) * HOUR_MS;
9287
9379
  const created = /* @__PURE__ */ new Date();
9288
- const rowId = crypto6.randomUUID();
9380
+ const rowId = crypto7.randomUUID();
9289
9381
  const ledger = lines.map((line) => ({
9290
9382
  id: line.customId,
9291
9383
  batchId: rowId,
@@ -9978,7 +10070,7 @@ var JobRunner = class {
9978
10070
  competitorAliases
9979
10071
  );
9980
10072
  const answerContext = supportedContext && isSearchLocationIgnored(providerName, normalized.retrievalStatus) ? { status: "ignored" } : supportedContext;
9981
- const snapshotId = crypto6.randomUUID();
10073
+ const snapshotId = crypto7.randomUUID();
9982
10074
  let screenshotRelPath = null;
9983
10075
  if (raw.screenshotPath && fs4.existsSync(raw.screenshotPath)) {
9984
10076
  const screenshotDir = path3.join(os3.homedir(), ".canonry", "screenshots", ctx.runId);
@@ -10080,7 +10172,7 @@ var JobRunner = class {
10080
10172
  const now = (/* @__PURE__ */ new Date()).toISOString();
10081
10173
  const period = now.slice(0, 10);
10082
10174
  this.db.insert(usageCounters).values({
10083
- id: crypto6.randomUUID(),
10175
+ id: crypto7.randomUUID(),
10084
10176
  scope,
10085
10177
  period,
10086
10178
  metric,
@@ -10214,11 +10306,11 @@ function maybeShowActivationNotice(io = {}) {
10214
10306
  }
10215
10307
 
10216
10308
  // src/gsc-sync.ts
10217
- import crypto8 from "crypto";
10309
+ import crypto9 from "crypto";
10218
10310
  import { eq as eq5, and as and5, sql as sql3 } from "drizzle-orm";
10219
10311
 
10220
10312
  // src/gsc-coverage-snapshot.ts
10221
- import crypto7 from "crypto";
10313
+ import crypto8 from "crypto";
10222
10314
  import { and as and4, desc as desc2, eq as eq4, gte } from "drizzle-orm";
10223
10315
  var COVERAGE_IMPRESSION_WINDOW_DAYS = 30;
10224
10316
  function pageKey(raw) {
@@ -10280,7 +10372,7 @@ function writeCoverageSnapshot(db, projectId, runId, opts = {}) {
10280
10372
  const snapshotDate = now.toISOString().split("T")[0];
10281
10373
  db.delete(gscCoverageSnapshots).where(and4(eq4(gscCoverageSnapshots.projectId, projectId), eq4(gscCoverageSnapshots.date, snapshotDate))).run();
10282
10374
  db.insert(gscCoverageSnapshots).values({
10283
- id: crypto7.randomUUID(),
10375
+ id: crypto8.randomUUID(),
10284
10376
  projectId,
10285
10377
  syncRunId: runId,
10286
10378
  date: snapshotDate,
@@ -10359,7 +10451,7 @@ async function executeGscSync(db, runId, projectId, opts) {
10359
10451
  for (const row of batch) {
10360
10452
  const [query, page, country, device, date] = row.keys;
10361
10453
  db.insert(gscSearchData).values({
10362
- id: crypto8.randomUUID(),
10454
+ id: crypto9.randomUUID(),
10363
10455
  projectId,
10364
10456
  syncRunId: runId,
10365
10457
  date: date ?? "",
@@ -10391,7 +10483,7 @@ async function executeGscSync(db, runId, projectId, opts) {
10391
10483
  for (const row of totalRows) {
10392
10484
  const [date] = row.keys;
10393
10485
  db.insert(gscDailyTotals).values({
10394
- id: crypto8.randomUUID(),
10486
+ id: crypto9.randomUUID(),
10395
10487
  projectId,
10396
10488
  date: date ?? "",
10397
10489
  clicks: row.clicks,
@@ -10440,7 +10532,7 @@ async function executeGscSync(db, runId, projectId, opts) {
10440
10532
  const [date, query] = row.keys;
10441
10533
  if (!date || !query) continue;
10442
10534
  db.insert(gscQueryDailyTotals).values({
10443
- id: crypto8.randomUUID(),
10535
+ id: crypto9.randomUUID(),
10444
10536
  projectId,
10445
10537
  date,
10446
10538
  query,
@@ -10465,11 +10557,11 @@ async function executeGscSync(db, runId, projectId, opts) {
10465
10557
  }
10466
10558
 
10467
10559
  // src/gbp-sync.ts
10468
- import crypto10 from "crypto";
10560
+ import crypto11 from "crypto";
10469
10561
  import { eq as eq7, and as and7, desc as desc4, inArray as inArray3, lt as lt2 } from "drizzle-orm";
10470
10562
 
10471
10563
  // src/gbp-reviews.ts
10472
- import crypto9 from "crypto";
10564
+ import crypto10 from "crypto";
10473
10565
  import { and as and6, desc as desc3, eq as eq6, inArray as inArray2, sql as sql4 } from "drizzle-orm";
10474
10566
  var log4 = createLogger("GbpReviews");
10475
10567
  var MS_PER_DAY = 864e5;
@@ -10588,7 +10680,7 @@ function persistReviewObservation(tx, projectId, runId, obs, ctx) {
10588
10680
  let queuedRatingDrop = false;
10589
10681
  if (!latestRating) {
10590
10682
  tx.insert(gbpReviewRatings).values({
10591
- id: crypto9.randomUUID(),
10683
+ id: crypto10.randomUUID(),
10592
10684
  projectId,
10593
10685
  locationName: obs.locationName,
10594
10686
  origin: obs.origin,
@@ -10608,7 +10700,7 @@ function persistReviewObservation(tx, projectId, runId, obs, ctx) {
10608
10700
  const alertState = ratingAlertState(obs.origin, latestRating.rating, obs.rating);
10609
10701
  queuedRatingDrop = alertState === "pending";
10610
10702
  tx.insert(gbpReviewRatings).values({
10611
- id: crypto9.randomUUID(),
10703
+ id: crypto10.randomUUID(),
10612
10704
  projectId,
10613
10705
  locationName: obs.locationName,
10614
10706
  origin: obs.origin,
@@ -10658,7 +10750,7 @@ function persistReviewObservation(tx, projectId, runId, obs, ctx) {
10658
10750
  const alertState = reviewAlertState(review, { baseline, now, negativeMaxStars });
10659
10751
  if (alertState === "pending") queuedReviews++;
10660
10752
  tx.insert(gbpReviews).values({
10661
- id: crypto9.randomUUID(),
10753
+ id: crypto10.randomUUID(),
10662
10754
  projectId,
10663
10755
  origin: obs.origin,
10664
10756
  reviewName: review.reviewName,
@@ -10819,7 +10911,7 @@ async function executeGbpSync(db, runId, projectId, opts) {
10819
10911
  tx.delete(gbpDailyMetrics).where(and7(eq7(gbpDailyMetrics.projectId, projectId), eq7(gbpDailyMetrics.locationName, loc.locationName))).run();
10820
10912
  for (const row of metricRows) {
10821
10913
  tx.insert(gbpDailyMetrics).values({
10822
- id: crypto10.randomUUID(),
10914
+ id: crypto11.randomUUID(),
10823
10915
  projectId,
10824
10916
  locationName: loc.locationName,
10825
10917
  date: row.date,
@@ -10831,7 +10923,7 @@ async function executeGbpSync(db, runId, projectId, opts) {
10831
10923
  tx.delete(gbpKeywordImpressions).where(and7(eq7(gbpKeywordImpressions.projectId, projectId), eq7(gbpKeywordImpressions.locationName, loc.locationName))).run();
10832
10924
  for (const row of keywordRows) {
10833
10925
  tx.insert(gbpKeywordImpressions).values({
10834
- id: crypto10.randomUUID(),
10926
+ id: crypto11.randomUUID(),
10835
10927
  projectId,
10836
10928
  locationName: loc.locationName,
10837
10929
  periodStart: monthKey(keywordsStart),
@@ -10852,7 +10944,7 @@ async function executeGbpSync(db, runId, projectId, opts) {
10852
10944
  for (const { month, rows } of monthlyKeywordResults) {
10853
10945
  for (const row of rows) {
10854
10946
  tx.insert(gbpKeywordMonthly).values({
10855
- id: crypto10.randomUUID(),
10947
+ id: crypto11.randomUUID(),
10856
10948
  projectId,
10857
10949
  locationName: loc.locationName,
10858
10950
  month,
@@ -10873,7 +10965,7 @@ async function executeGbpSync(db, runId, projectId, opts) {
10873
10965
  tx.delete(gbpPlaceActions).where(and7(eq7(gbpPlaceActions.projectId, projectId), eq7(gbpPlaceActions.locationName, loc.locationName))).run();
10874
10966
  for (const row of placeActionRows) {
10875
10967
  tx.insert(gbpPlaceActions).values({
10876
- id: crypto10.randomUUID(),
10968
+ id: crypto11.randomUUID(),
10877
10969
  projectId,
10878
10970
  locationName: loc.locationName,
10879
10971
  placeActionLinkName: row.placeActionLinkName,
@@ -10886,7 +10978,7 @@ async function executeGbpSync(db, runId, projectId, opts) {
10886
10978
  }
10887
10979
  if (lodging !== null && lodgingChanged) {
10888
10980
  tx.insert(gbpLodgingSnapshots).values({
10889
- id: crypto10.randomUUID(),
10981
+ id: crypto11.randomUUID(),
10890
10982
  projectId,
10891
10983
  locationName: loc.locationName,
10892
10984
  contentHash: lodgingHash,
@@ -10900,7 +10992,7 @@ async function executeGbpSync(db, runId, projectId, opts) {
10900
10992
  }
10901
10993
  if (attributesChanged) {
10902
10994
  tx.insert(gbpAttributesSnapshots).values({
10903
- id: crypto10.randomUUID(),
10995
+ id: crypto11.randomUUID(),
10904
10996
  projectId,
10905
10997
  locationName: loc.locationName,
10906
10998
  contentHash: attributesHash,
@@ -10914,7 +11006,7 @@ async function executeGbpSync(db, runId, projectId, opts) {
10914
11006
  }
10915
11007
  if (placeToWrite) {
10916
11008
  tx.insert(gbpPlaceDetails).values({
10917
- id: crypto10.randomUUID(),
11009
+ id: crypto11.randomUUID(),
10918
11010
  projectId,
10919
11011
  locationName: loc.locationName,
10920
11012
  placeId: placeToWrite.placeId,
@@ -11019,7 +11111,7 @@ async function refreshSelectedLocationProfiles(db, projectId, accessToken, locat
11019
11111
  }
11020
11112
 
11021
11113
  // src/ads-sync.ts
11022
- import crypto11 from "crypto";
11114
+ import crypto12 from "crypto";
11023
11115
  import { and as and8, eq as eq8, inArray as inArray4, notInArray } from "drizzle-orm";
11024
11116
 
11025
11117
  // ../integration-openai-ads/src/constants.ts
@@ -11794,7 +11886,7 @@ async function executeAdsSync(db, runId, projectId, opts) {
11794
11886
  }
11795
11887
  for (const upsert of insightUpserts) {
11796
11888
  tx.insert(adsInsightsDaily).values({
11797
- id: crypto11.randomUUID(),
11889
+ id: crypto12.randomUUID(),
11798
11890
  projectId,
11799
11891
  level: upsert.level,
11800
11892
  entityId: upsert.entityId,
@@ -11862,7 +11954,7 @@ async function executeAdsSync(db, runId, projectId, opts) {
11862
11954
  }
11863
11955
 
11864
11956
  // src/gsc-inspect-sitemap.ts
11865
- import crypto13 from "crypto";
11957
+ import crypto14 from "crypto";
11866
11958
  import { eq as eq9 } from "drizzle-orm";
11867
11959
 
11868
11960
  // src/sitemap-parser.ts
@@ -11962,7 +12054,7 @@ async function parseSitemapRecursive(url, urls, visited, depth, isChild) {
11962
12054
  }
11963
12055
 
11964
12056
  // src/inspect-rate-gate.ts
11965
- import crypto12 from "crypto";
12057
+ import crypto13 from "crypto";
11966
12058
  var gates = /* @__PURE__ */ new Map();
11967
12059
  function sharedRateGate(key) {
11968
12060
  let entry = gates.get(key);
@@ -11981,7 +12073,7 @@ function sharedRateGate(key) {
11981
12073
  };
11982
12074
  }
11983
12075
  function credentialGateKey(prefix, secret) {
11984
- const digest = crypto12.createHash("sha256").update(secret).digest("hex").slice(0, 12);
12076
+ const digest = crypto13.createHash("sha256").update(secret).digest("hex").slice(0, 12);
11985
12077
  return `${prefix}:${digest}`;
11986
12078
  }
11987
12079
 
@@ -12136,7 +12228,7 @@ async function executeInspectSitemap(db, runId, projectId, opts) {
12136
12228
  const rich = ir.richResultsResult;
12137
12229
  const inspectedAt = (/* @__PURE__ */ new Date()).toISOString();
12138
12230
  db.insert(gscUrlInspections).values({
12139
- id: crypto13.randomUUID(),
12231
+ id: crypto14.randomUUID(),
12140
12232
  projectId,
12141
12233
  syncRunId: runId,
12142
12234
  url: pageUrl,
@@ -12194,7 +12286,7 @@ async function executeInspectSitemap(db, runId, projectId, opts) {
12194
12286
  }
12195
12287
 
12196
12288
  // src/bing-inspect-sitemap.ts
12197
- import crypto14 from "crypto";
12289
+ import crypto15 from "crypto";
12198
12290
  import { eq as eq10, desc as desc5 } from "drizzle-orm";
12199
12291
  var log9 = createLogger("BingInspectSitemap");
12200
12292
  var BING_INSPECT_SPACING_MS = 2e3;
@@ -12299,7 +12391,7 @@ async function executeBingInspectSitemap(db, runId, projectId, opts) {
12299
12391
  derivedInIndex = false;
12300
12392
  }
12301
12393
  db.insert(bingUrlInspections).values({
12302
- id: crypto14.randomUUID(),
12394
+ id: crypto15.randomUUID(),
12303
12395
  projectId,
12304
12396
  url: pageUrl,
12305
12397
  httpCode,
@@ -12383,7 +12475,7 @@ async function executeBingInspectSitemap(db, runId, projectId, opts) {
12383
12475
  const snapshotDate = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
12384
12476
  const snapNow = (/* @__PURE__ */ new Date()).toISOString();
12385
12477
  db.insert(bingCoverageSnapshots).values({
12386
- id: crypto14.randomUUID(),
12478
+ id: crypto15.randomUUID(),
12387
12479
  projectId,
12388
12480
  syncRunId: runId,
12389
12481
  date: snapshotDate,
@@ -12424,7 +12516,7 @@ async function executeBingInspectSitemap(db, runId, projectId, opts) {
12424
12516
  }
12425
12517
 
12426
12518
  // src/coverage-refresh.ts
12427
- import crypto15 from "crypto";
12519
+ import crypto16 from "crypto";
12428
12520
  import { and as and9, desc as desc6, eq as eq11, inArray as inArray5 } from "drizzle-orm";
12429
12521
  var log10 = createLogger("CoverageRefresh");
12430
12522
  var COVERAGE_REFRESH_MIN_INTERVAL_MS = 60 * 60 * 1e3;
@@ -12474,7 +12566,7 @@ async function maybeRefreshGscCoverage(db, config, projectId, deps = defaultDeps
12474
12566
  return null;
12475
12567
  }
12476
12568
  }
12477
- const runId = crypto15.randomUUID();
12569
+ const runId = crypto16.randomUUID();
12478
12570
  db.insert(runs).values({
12479
12571
  id: runId,
12480
12572
  projectId,
@@ -12497,7 +12589,7 @@ async function maybeRefreshGscCoverage(db, config, projectId, deps = defaultDeps
12497
12589
  }
12498
12590
 
12499
12591
  // src/commoncrawl-sync.ts
12500
- import crypto16 from "crypto";
12592
+ import crypto17 from "crypto";
12501
12593
  import path4 from "path";
12502
12594
  import { and as and10, eq as eq12, sql as sql5 } from "drizzle-orm";
12503
12595
  var log11 = createLogger("CommonCrawlSync");
@@ -12572,7 +12664,7 @@ async function executeReleaseSync(db, syncId, opts) {
12572
12664
  if (!projectIds) continue;
12573
12665
  for (const projectId of projectIds) {
12574
12666
  expanded.push({
12575
- id: crypto16.randomUUID(),
12667
+ id: crypto17.randomUUID(),
12576
12668
  projectId,
12577
12669
  releaseSyncId: syncId,
12578
12670
  release,
@@ -12592,7 +12684,7 @@ async function executeReleaseSync(db, syncId, opts) {
12592
12684
  const projectRows = rowsByProject.get(p.id) ?? [];
12593
12685
  const summary = computeSummary(projectRows);
12594
12686
  tx.insert(backlinkSummaries).values({
12595
- id: crypto16.randomUUID(),
12687
+ id: crypto17.randomUUID(),
12596
12688
  projectId: p.id,
12597
12689
  releaseSyncId: syncId,
12598
12690
  source: BacklinkSources.commoncrawl,
@@ -12689,7 +12781,7 @@ function computeSummary(rows) {
12689
12781
  }
12690
12782
 
12691
12783
  // src/backlink-extract.ts
12692
- import crypto17 from "crypto";
12784
+ import crypto18 from "crypto";
12693
12785
  import fs5 from "fs";
12694
12786
  import { and as and11, desc as desc7, eq as eq13 } from "drizzle-orm";
12695
12787
  var log12 = createLogger("BacklinkExtract");
@@ -12745,7 +12837,7 @@ async function executeBacklinkExtract(db, runId, projectId, opts = {}) {
12745
12837
  ).run();
12746
12838
  if (rows.length > 0) {
12747
12839
  const values = rows.map((r) => ({
12748
- id: crypto17.randomUUID(),
12840
+ id: crypto18.randomUUID(),
12749
12841
  projectId,
12750
12842
  releaseSyncId: syncId,
12751
12843
  source: BacklinkSources.commoncrawl,
@@ -12759,7 +12851,7 @@ async function executeBacklinkExtract(db, runId, projectId, opts = {}) {
12759
12851
  }
12760
12852
  const summary = computeSummary2(rows);
12761
12853
  tx.insert(backlinkSummaries).values({
12762
- id: crypto17.randomUUID(),
12854
+ id: crypto18.randomUUID(),
12763
12855
  projectId,
12764
12856
  releaseSyncId: syncId,
12765
12857
  source: BacklinkSources.commoncrawl,
@@ -12802,7 +12894,7 @@ function computeSummary2(rows) {
12802
12894
  }
12803
12895
 
12804
12896
  // src/discovery-run.ts
12805
- import crypto18 from "crypto";
12897
+ import crypto19 from "crypto";
12806
12898
  import { and as and12, eq as eq14 } from "drizzle-orm";
12807
12899
  var log13 = createLogger("DiscoveryRun");
12808
12900
  var DEFAULT_SEED_COUNT = 30;
@@ -13157,7 +13249,7 @@ function writeDiscoveryInsight(db, input) {
13157
13249
  eq14(insights.dismissed, false)
13158
13250
  )).run();
13159
13251
  tx.insert(insights).values({
13160
- id: crypto18.randomUUID(),
13252
+ id: crypto19.randomUUID(),
13161
13253
  projectId: input.projectId,
13162
13254
  runId: input.runId,
13163
13255
  type: "discovery.basket-divergence",
@@ -13193,7 +13285,7 @@ function buildDiscoveryInsightTitle(input) {
13193
13285
  }
13194
13286
 
13195
13287
  // src/execute-site-audit.ts
13196
- import crypto19 from "crypto";
13288
+ import crypto20 from "crypto";
13197
13289
  import { and as and14, eq as eq16, ne as ne2, sql as sql6 } from "drizzle-orm";
13198
13290
  import { runSiteCrawl } from "@canonry/aeo-audit";
13199
13291
 
@@ -13644,7 +13736,7 @@ async function executeSiteAudit(db, runId, projectId, opts = {}) {
13644
13736
  const trigger = db.select({ trigger: runs.trigger }).from(runs).where(eq16(runs.id, runId)).get()?.trigger ?? null;
13645
13737
  let canonicalDomain = null;
13646
13738
  const attemptNumber = (db.select({ value: sql6`coalesce(max(${siteCrawlAttempts.attemptNumber}), 0)` }).from(siteCrawlAttempts).where(eq16(siteCrawlAttempts.runId, runId)).get()?.value ?? 0) + 1;
13647
- const attemptId = crypto19.randomUUID();
13739
+ const attemptId = crypto20.randomUUID();
13648
13740
  db.insert(siteCrawlAttempts).values({
13649
13741
  id: attemptId,
13650
13742
  projectId,
@@ -13722,7 +13814,7 @@ async function executeSiteAudit(db, runId, projectId, opts = {}) {
13722
13814
  nodeKey: page.key
13723
13815
  });
13724
13816
  tx.insert(siteCrawlPages).values({
13725
- id: crypto19.randomUUID(),
13817
+ id: crypto20.randomUUID(),
13726
13818
  projectId,
13727
13819
  runId,
13728
13820
  attemptId,
@@ -13815,7 +13907,7 @@ async function executeSiteAudit(db, runId, projectId, opts = {}) {
13815
13907
  if (isSelfLink(edge.from, edge.to)) return;
13816
13908
  observedEdges.set(edge.key, edge);
13817
13909
  tx.insert(siteCrawlEdges).values({
13818
- id: crypto19.randomUUID(),
13910
+ id: crypto20.randomUUID(),
13819
13911
  projectId,
13820
13912
  runId,
13821
13913
  attemptId,
@@ -13885,7 +13977,7 @@ async function executeSiteAudit(db, runId, projectId, opts = {}) {
13885
13977
  return;
13886
13978
  }
13887
13979
  tx.insert(siteCrawlEventReceipts).values({
13888
- id: crypto19.randomUUID(),
13980
+ id: crypto20.randomUUID(),
13889
13981
  projectId,
13890
13982
  runId,
13891
13983
  attemptId,
@@ -14021,7 +14113,7 @@ async function executeSiteAudit(db, runId, projectId, opts = {}) {
14021
14113
  if (claim2.changes === 0) return false;
14022
14114
  if (hasAuditedPages) {
14023
14115
  tx.insert(siteAuditSnapshots).values({
14024
- id: crypto19.randomUUID(),
14116
+ id: crypto20.randomUUID(),
14025
14117
  projectId,
14026
14118
  runId,
14027
14119
  sitemapUrl: opts.sitemapUrl ?? new URL("/sitemap.xml", crawlRootUrl).href,
@@ -14039,7 +14131,7 @@ async function executeSiteAudit(db, runId, projectId, opts = {}) {
14039
14131
  for (const page of observedPages.values()) {
14040
14132
  if (!isLegacyScorecardPage(page)) continue;
14041
14133
  tx.insert(siteAuditPages).values({
14042
- id: crypto19.randomUUID(),
14134
+ id: crypto20.randomUUID(),
14043
14135
  projectId,
14044
14136
  runId,
14045
14137
  url: page.finalUrl ?? page.requestedUrl,
@@ -14052,7 +14144,7 @@ async function executeSiteAudit(db, runId, projectId, opts = {}) {
14052
14144
  }
14053
14145
  }
14054
14146
  tx.insert(siteCrawlSnapshots).values({
14055
- id: crypto19.randomUUID(),
14147
+ id: crypto20.randomUUID(),
14056
14148
  projectId,
14057
14149
  runId,
14058
14150
  attemptId,
@@ -14098,7 +14190,7 @@ async function executeSiteAudit(db, runId, projectId, opts = {}) {
14098
14190
  if (opts.checkDeadLinks) {
14099
14191
  for (const finding of deadLinkFindings) {
14100
14192
  tx.insert(siteCrawlFindings).values({
14101
- id: crypto19.randomUUID(),
14193
+ id: crypto20.randomUUID(),
14102
14194
  projectId,
14103
14195
  runId,
14104
14196
  attemptId,
@@ -14673,7 +14765,7 @@ function readStoredGroundingSources(rawResponse) {
14673
14765
  return result2;
14674
14766
  }
14675
14767
  async function backfillInsightsCommand(project, opts) {
14676
- const { IntelligenceService: IntelligenceService2 } = await import("./intelligence-service-4IONMOFB.js");
14768
+ const { IntelligenceService: IntelligenceService2 } = await import("./intelligence-service-5J36RBEM.js");
14677
14769
  const config = loadConfig();
14678
14770
  const db = createClient(config.database);
14679
14771
  migrate(db);
@@ -15263,7 +15355,7 @@ var ProviderRegistry = class {
15263
15355
  import { createHash as createHash4 } from "crypto";
15264
15356
  var TTL_MS = 60 * 60 * 1e3;
15265
15357
  var RETRY_MS = 60 * 1e3;
15266
- var TIMEOUT_MS2 = 3e3;
15358
+ var TIMEOUT_MS3 = 3e3;
15267
15359
  function createProviderModelCatalog(registry) {
15268
15360
  const cache = /* @__PURE__ */ new Map();
15269
15361
  const read = async (name) => {
@@ -15289,7 +15381,7 @@ function createProviderModelCatalog(registry) {
15289
15381
  timer = setTimeout(() => {
15290
15382
  controller.abort();
15291
15383
  reject(new Error("Model discovery timed out"));
15292
- }, TIMEOUT_MS2);
15384
+ }, TIMEOUT_MS3);
15293
15385
  });
15294
15386
  current.pending = Promise.race([
15295
15387
  Promise.resolve().then(() => provider.adapter.listModels(provider.config, controller.signal)),
@@ -15320,14 +15412,14 @@ function createProviderModelCatalog(registry) {
15320
15412
  }
15321
15413
 
15322
15414
  // src/scheduler.ts
15323
- import crypto20 from "crypto";
15415
+ import crypto21 from "crypto";
15324
15416
  import cron from "node-cron";
15325
15417
  import { and as and16, eq as eq18, inArray as inArray8, notExists, sql as sql8 } from "drizzle-orm";
15326
15418
  var log15 = createLogger("Scheduler");
15327
15419
  var DEFAULT_HEALTH_CRON = "0 */6 * * *";
15328
15420
  function ensureDefaultHealthSchedule(db, projectId, now = (/* @__PURE__ */ new Date()).toISOString()) {
15329
15421
  const result2 = db.insert(schedules).values({
15330
- id: crypto20.randomUUID(),
15422
+ id: crypto21.randomUUID(),
15331
15423
  projectId,
15332
15424
  kind: SchedulableRunKinds.doctor,
15333
15425
  cronExpr: DEFAULT_HEALTH_CRON,
@@ -15645,7 +15737,7 @@ var Scheduler = class {
15645
15737
  log15.warn("gbp-sync.no-callback", { scheduleId, projectId, msg: "host did not register onGbpSyncRequested" });
15646
15738
  return;
15647
15739
  }
15648
- const runId2 = crypto20.randomUUID();
15740
+ const runId2 = crypto21.randomUUID();
15649
15741
  this.db.insert(runs).values({
15650
15742
  id: runId2,
15651
15743
  projectId,
@@ -15677,7 +15769,7 @@ var Scheduler = class {
15677
15769
  this.updateScheduleTiming(currentSchedule.id, { nextRunAt });
15678
15770
  return;
15679
15771
  }
15680
- const runId2 = crypto20.randomUUID();
15772
+ const runId2 = crypto21.randomUUID();
15681
15773
  this.db.insert(runs).values({
15682
15774
  id: runId2,
15683
15775
  projectId,
@@ -15748,7 +15840,7 @@ var Scheduler = class {
15748
15840
  this.updateScheduleTiming(currentSchedule.id, { nextRunAt });
15749
15841
  return;
15750
15842
  }
15751
- const runId2 = crypto20.randomUUID();
15843
+ const runId2 = crypto21.randomUUID();
15752
15844
  const effectiveRequest = normalizeSiteAuditRunRequest({ maxPages: SITE_AUDIT_MAX_PAGE_LIMIT });
15753
15845
  this.db.transaction((tx) => {
15754
15846
  tx.insert(runs).values({
@@ -16091,7 +16183,7 @@ async function refreshAllIntegrations(client, projectName, now = /* @__PURE__ */
16091
16183
 
16092
16184
  // src/notifier.ts
16093
16185
  import { eq as eq20, desc as desc9, and as and18, inArray as inArray10, or } from "drizzle-orm";
16094
- import crypto21 from "crypto";
16186
+ import crypto22 from "crypto";
16095
16187
  var log19 = createLogger("Notifier");
16096
16188
  var MATERIAL_MAGNITUDE_DELTA = 20;
16097
16189
  var SEVERITY_RANK = { low: 0, medium: 1, high: 2, critical: 3 };
@@ -16718,7 +16810,7 @@ var Notifier = class {
16718
16810
  }
16719
16811
  logDelivery(projectId, notificationId, event, status, error) {
16720
16812
  this.db.insert(auditLog).values({
16721
- id: crypto21.randomUUID(),
16813
+ id: crypto22.randomUUID(),
16722
16814
  projectId,
16723
16815
  actor: "scheduler",
16724
16816
  action: `notification.${status}`,
@@ -16894,7 +16986,7 @@ function analysisResultFromInsights(insights2) {
16894
16986
  }
16895
16987
 
16896
16988
  // src/agent/session-registry.ts
16897
- import crypto25 from "crypto";
16989
+ import crypto26 from "crypto";
16898
16990
  import { eq as eq24 } from "drizzle-orm";
16899
16991
 
16900
16992
  // src/agent/session.ts
@@ -18147,7 +18239,7 @@ function buildAeroStateTools(ctx, opts = {}) {
18147
18239
  }
18148
18240
 
18149
18241
  // src/agent/llm-usage.ts
18150
- import crypto22 from "crypto";
18242
+ import crypto23 from "crypto";
18151
18243
  var AeroLlmUsageFeatures = {
18152
18244
  turn: "aero.turn"
18153
18245
  };
@@ -18166,7 +18258,7 @@ function recordLlmUsageEvent(args) {
18166
18258
  const usage = args.message.usage;
18167
18259
  const now = (/* @__PURE__ */ new Date()).toISOString();
18168
18260
  args.db.insert(llmUsageEvents).values({
18169
- id: crypto22.randomUUID(),
18261
+ id: crypto23.randomUUID(),
18170
18262
  projectId: args.projectId,
18171
18263
  runId: args.runId,
18172
18264
  agentSessionId: args.agentSessionId,
@@ -18536,7 +18628,7 @@ This context applies to this turn. Explicit user scope takes precedence; do not
18536
18628
  }
18537
18629
 
18538
18630
  // src/agent/tool-usage.ts
18539
- import crypto23 from "crypto";
18631
+ import crypto24 from "crypto";
18540
18632
  var AeroToolEventStatuses = {
18541
18633
  success: "success",
18542
18634
  error: "error"
@@ -18599,7 +18691,7 @@ function createAeroToolUsageHooks(args) {
18599
18691
  function recordAgentToolEvent(args) {
18600
18692
  try {
18601
18693
  args.db.insert(agentToolEvents).values({
18602
- id: crypto23.randomUUID(),
18694
+ id: crypto24.randomUUID(),
18603
18695
  projectId: args.projectId,
18604
18696
  agentSessionId: args.agentSessionId,
18605
18697
  toolCallId: args.toolCallId,
@@ -18854,7 +18946,7 @@ async function loadExternalMcpTools(servers, opts = {}) {
18854
18946
  }
18855
18947
 
18856
18948
  // src/agent/memory-store.ts
18857
- import crypto24 from "crypto";
18949
+ import crypto25 from "crypto";
18858
18950
  import { and as and19, desc as desc10, eq as eq22, like, sql as sql10, or as or2 } from "drizzle-orm";
18859
18951
  var COMPACTION_KEY_PREFIX = "compaction:";
18860
18952
  var COMPACTION_NOTES_PER_SESSION = 3;
@@ -18883,7 +18975,7 @@ function upsertMemoryEntry(db, args) {
18883
18975
  throw new Error(`memory key prefix "${COMPACTION_KEY_PREFIX}" is reserved for compaction notes`);
18884
18976
  }
18885
18977
  const now = (/* @__PURE__ */ new Date()).toISOString();
18886
- const id = crypto24.randomUUID();
18978
+ const id = crypto25.randomUUID();
18887
18979
  db.insert(agentMemory).values({
18888
18980
  id,
18889
18981
  projectId: args.projectId,
@@ -18925,7 +19017,7 @@ function writeCompactionNote(db, args) {
18925
19017
  }
18926
19018
  const now = (/* @__PURE__ */ new Date()).toISOString();
18927
19019
  const key = `${COMPACTION_KEY_PREFIX}${args.sessionId}:${now}`;
18928
- const id = crypto24.randomUUID();
19020
+ const id = crypto25.randomUUID();
18929
19021
  let inserted;
18930
19022
  db.transaction((tx) => {
18931
19023
  tx.insert(agentMemory).values({
@@ -19297,7 +19389,7 @@ var SessionRegistry = class {
19297
19389
  return agent2;
19298
19390
  }
19299
19391
  const { provider, modelId } = resolveSessionProviderAndModel(this.opts.config, preferences);
19300
- const sessionId = crypto25.randomUUID();
19392
+ const sessionId = crypto26.randomUUID();
19301
19393
  const agent = createAeroSession({
19302
19394
  projectName,
19303
19395
  client: this.opts.client,
@@ -19749,7 +19841,7 @@ ${lines.join("\n")}
19749
19841
  insertRow(params) {
19750
19842
  const now = (/* @__PURE__ */ new Date()).toISOString();
19751
19843
  this.opts.db.insert(agentSessions).values({
19752
- id: params.id ?? crypto25.randomUUID(),
19844
+ id: params.id ?? crypto26.randomUUID(),
19753
19845
  projectId: params.projectId,
19754
19846
  systemPrompt: params.systemPrompt,
19755
19847
  modelProvider: params.provider ?? params.modelProvider ?? AgentProviderIds.claude,
@@ -19776,7 +19868,7 @@ ${lines.join("\n")}
19776
19868
  };
19777
19869
 
19778
19870
  // src/agent/viewer-sessions.ts
19779
- import crypto26 from "crypto";
19871
+ import crypto27 from "crypto";
19780
19872
  import { and as and21, eq as eq25, isNotNull as isNotNull3, like as like2 } from "drizzle-orm";
19781
19873
  var AERO_VIEWER_EXCLUDED_MCP_TOOLS = /* @__PURE__ */ new Set([
19782
19874
  CanonryMcpToolNames.canonry_ads_account,
@@ -19830,8 +19922,8 @@ function trimViewerTranscript(messages, max = MAX_VIEWER_MESSAGES) {
19830
19922
  }
19831
19923
  var VIEWER_IDLE_MS = 12 * 60 * 60 * 1e3;
19832
19924
  function mintViewerAeroKey(db, userId, now = /* @__PURE__ */ new Date()) {
19833
- const raw = `cnry_${crypto26.randomBytes(24).toString("hex")}`;
19834
- const id = crypto26.randomUUID();
19925
+ const raw = `cnry_${crypto27.randomBytes(24).toString("hex")}`;
19926
+ const id = crypto27.randomUUID();
19835
19927
  db.insert(apiKeys).values({
19836
19928
  id,
19837
19929
  name: `${VIEWER_AERO_KEY_PREFIX}${userId}`,
@@ -19983,15 +20075,15 @@ var ViewerAeroSessions = class {
19983
20075
  };
19984
20076
 
19985
20077
  // src/mcp-http.ts
19986
- import crypto27 from "crypto";
20078
+ import crypto28 from "crypto";
19987
20079
  import { eq as eq26 } from "drizzle-orm";
19988
20080
  import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
19989
20081
  import { isInitializeRequest } from "@modelcontextprotocol/sdk/types.js";
19990
20082
  var SESSION_IDLE_MS = 10 * 60 * 1e3;
19991
20083
  var SWEEP_INTERVAL_MS = 60 * 1e3;
19992
20084
  function mintSessionKey(db, scopes, userId) {
19993
- const raw = `cnry_${crypto27.randomBytes(24).toString("hex")}`;
19994
- const id = crypto27.randomUUID();
20085
+ const raw = `cnry_${crypto28.randomBytes(24).toString("hex")}`;
20086
+ const id = crypto28.randomUUID();
19995
20087
  db.insert(apiKeys).values({
19996
20088
  id,
19997
20089
  name: `mcp-session:${userId}`,
@@ -20075,7 +20167,7 @@ function registerMcpHttpRoutes(scope, opts) {
20075
20167
  clientName: `canonry-mcp/${PACKAGE_VERSION}`,
20076
20168
  surface: "mcp-http",
20077
20169
  // Correlation only: this is never accepted as caller identity or authority.
20078
- actorSession: crypto27.randomUUID()
20170
+ actorSession: crypto28.randomUUID()
20079
20171
  });
20080
20172
  let server;
20081
20173
  try {
@@ -20092,7 +20184,7 @@ function registerMcpHttpRoutes(scope, opts) {
20092
20184
  throw error;
20093
20185
  }
20094
20186
  const transport = new StreamableHTTPServerTransport({
20095
- sessionIdGenerator: () => crypto27.randomUUID(),
20187
+ sessionIdGenerator: () => crypto28.randomUUID(),
20096
20188
  onsessioninitialized: (id) => {
20097
20189
  sessions.set(id, { transport, close, authorizationId, segmentId: segment.id, lastSeenAt: now() });
20098
20190
  }
@@ -21801,14 +21893,14 @@ function summarizeProviderConfig(config) {
21801
21893
  };
21802
21894
  }
21803
21895
  function hashApiKey2(key) {
21804
- return crypto28.createHash("sha256").update(key).digest("hex");
21896
+ return crypto29.createHash("sha256").update(key).digest("hex");
21805
21897
  }
21806
21898
  var DASHBOARD_SCRYPT_KEYLEN = 64;
21807
21899
  var DASHBOARD_SCRYPT_COST = 1 << 15;
21808
21900
  var DASHBOARD_SCRYPT_MAXMEM = 64 * 1024 * 1024;
21809
21901
  function hashDashboardPassword(password) {
21810
- const salt = crypto28.randomBytes(16);
21811
- const derived = crypto28.scryptSync(password, salt, DASHBOARD_SCRYPT_KEYLEN, {
21902
+ const salt = crypto29.randomBytes(16);
21903
+ const derived = crypto29.scryptSync(password, salt, DASHBOARD_SCRYPT_KEYLEN, {
21812
21904
  N: DASHBOARD_SCRYPT_COST,
21813
21905
  maxmem: DASHBOARD_SCRYPT_MAXMEM
21814
21906
  });
@@ -21829,14 +21921,14 @@ function verifyDashboardPassword(password, storedHash) {
21829
21921
  } catch {
21830
21922
  return { ok: false, needsRehash: false };
21831
21923
  }
21832
- const derived = crypto28.scryptSync(password, salt, expected.length, {
21924
+ const derived = crypto29.scryptSync(password, salt, expected.length, {
21833
21925
  N: DASHBOARD_SCRYPT_COST,
21834
21926
  maxmem: DASHBOARD_SCRYPT_MAXMEM
21835
21927
  });
21836
21928
  if (derived.length !== expected.length)
21837
21929
  return { ok: false, needsRehash: false };
21838
21930
  return {
21839
- ok: crypto28.timingSafeEqual(derived, expected),
21931
+ ok: crypto29.timingSafeEqual(derived, expected),
21840
21932
  needsRehash: false
21841
21933
  };
21842
21934
  }
@@ -21845,7 +21937,7 @@ function verifyDashboardPassword(password, storedHash) {
21845
21937
  const expected = Buffer.from(storedHash, "hex");
21846
21938
  if (candidate.length !== expected.length)
21847
21939
  return { ok: false, needsRehash: false };
21848
- const ok = crypto28.timingSafeEqual(candidate, expected);
21940
+ const ok = crypto29.timingSafeEqual(candidate, expected);
21849
21941
  return { ok, needsRehash: ok };
21850
21942
  }
21851
21943
  return { ok: false, needsRehash: false };
@@ -21981,7 +22073,7 @@ function cloneGtmConfig(config) {
21981
22073
  function createGoogleMarketingConfigCredentialStore(input) {
21982
22074
  const persistConfigPatch = input.saveConfigPatch ?? saveConfigPatch;
21983
22075
  const env = input.env ?? process.env;
21984
- const randomUUID3 = input.randomUUID ?? crypto28.randomUUID;
22076
+ const randomUUID3 = input.randomUUID ?? crypto29.randomUUID;
21985
22077
  const snapshot = () => ({
21986
22078
  googleAds: cloneGoogleAdsConfig(input.config.googleAds),
21987
22079
  gtm: cloneGtmConfig(input.config.gtm)
@@ -22084,7 +22176,7 @@ async function createServer(opts) {
22084
22176
  const trustProxy = resolveTrustProxy(process.env.CANONRY_TRUST_PROXY);
22085
22177
  const app = Fastify({
22086
22178
  loggerInstance: logger,
22087
- genReqId: () => crypto28.randomUUID(),
22179
+ genReqId: () => crypto29.randomUUID(),
22088
22180
  trustProxy
22089
22181
  });
22090
22182
  const registry = new ProviderRegistry();
@@ -22851,7 +22943,7 @@ async function createServer(opts) {
22851
22943
  return removed;
22852
22944
  }
22853
22945
  };
22854
- const googleStateSecret = process.env.GOOGLE_STATE_SECRET ?? crypto28.randomBytes(32).toString("hex");
22946
+ const googleStateSecret = process.env.GOOGLE_STATE_SECRET ?? crypto29.randomBytes(32).toString("hex");
22855
22947
  const googleConnectionStore = {
22856
22948
  listConnections: (domain) => listGoogleConnections(opts.config, domain),
22857
22949
  getConnection: (domain, connectionType) => getGoogleConnection(opts.config, domain, connectionType),
@@ -22945,7 +23037,7 @@ async function createServer(opts) {
22945
23037
  if (!existing) {
22946
23038
  const prefix = opts.config.apiKey.slice(0, 12);
22947
23039
  opts.db.insert(apiKeys).values({
22948
- id: `key_${crypto28.randomBytes(8).toString("hex")}`,
23040
+ id: `key_${crypto29.randomBytes(8).toString("hex")}`,
22949
23041
  name: "default",
22950
23042
  keyHash,
22951
23043
  keyPrefix: prefix,
@@ -22969,7 +23061,7 @@ async function createServer(opts) {
22969
23061
  };
22970
23062
  const createSession = (apiKeyId) => {
22971
23063
  pruneExpiredSessions();
22972
- const sessionId = crypto28.randomBytes(32).toString("hex");
23064
+ const sessionId = crypto29.randomBytes(32).toString("hex");
22973
23065
  sessions.set(sessionId, {
22974
23066
  apiKeyId,
22975
23067
  expiresAt: Date.now() + SESSION_TTL_MS
@@ -23442,7 +23534,7 @@ async function createServer(opts) {
23442
23534
  deps: {
23443
23535
  enqueueAutoExtract: ({ projectId, release: r }) => {
23444
23536
  const now = (/* @__PURE__ */ new Date()).toISOString();
23445
- const runId = crypto28.randomUUID();
23537
+ const runId = crypto29.randomUUID();
23446
23538
  opts.db.insert(runs).values({
23447
23539
  id: runId,
23448
23540
  projectId,
@@ -23686,7 +23778,7 @@ async function createServer(opts) {
23686
23778
  const createdAt = (/* @__PURE__ */ new Date()).toISOString();
23687
23779
  opts.db.insert(auditLog).values(
23688
23780
  targetProjectIds.map((projectId) => ({
23689
- id: crypto28.randomUUID(),
23781
+ id: crypto29.randomUUID(),
23690
23782
  projectId,
23691
23783
  actor: auditContext?.actor ?? "api",
23692
23784
  userAgent: auditContext?.userAgent ?? null,
@@ -23783,6 +23875,7 @@ async function createServer(opts) {
23783
23875
  const { event: eventName, eventId, ...properties } = event;
23784
23876
  trackEvent(eventName, properties, { source: "dashboard", eventId });
23785
23877
  },
23878
+ submitFeedback: (submission, context) => sendFeedback(submission, context),
23786
23879
  onCdpConfigure: async (host, port2) => {
23787
23880
  if (!opts.config.cdp) opts.config.cdp = {};
23788
23881
  opts.config.cdp.host = host;