@ainyc/canonry 4.14.0 → 4.15.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.
@@ -1959,6 +1959,7 @@ export {
1959
1959
  getConfigDir,
1960
1960
  getConfigPath,
1961
1961
  loadConfig,
1962
+ loadConfigRaw,
1962
1963
  saveConfig,
1963
1964
  saveConfigPatch,
1964
1965
  configExists,
@@ -3,8 +3,9 @@ import {
3
3
  canonryMcpTools,
4
4
  configExists,
5
5
  loadConfig,
6
+ loadConfigRaw,
6
7
  saveConfigPatch
7
- } from "./chunk-5NYG5EC7.js";
8
+ } from "./chunk-C32VL5BB.js";
8
9
  import {
9
10
  DEFAULT_RUN_HISTORY_LIMIT,
10
11
  IntelligenceService,
@@ -163,6 +164,11 @@ var TELEMETRY_ENDPOINT = "https://ainyc.ai/api/telemetry";
163
164
  var TIMEOUT_MS = 3e3;
164
165
  var ANON_ID_ENV_VAR = "CANONRY_ANONYMOUS_ID";
165
166
  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;
167
+ var SESSION_ID = crypto.randomUUID();
168
+ var CURRENT_SOURCE = "cli";
169
+ function setTelemetrySource(source) {
170
+ CURRENT_SOURCE = source;
171
+ }
166
172
  function isTelemetryEnabled() {
167
173
  if (process.env.CANONRY_TELEMETRY_DISABLED === "1") return false;
168
174
  if (process.env.DO_NOT_TRACK === "1") return false;
@@ -250,19 +256,42 @@ function showFirstRunNotice() {
250
256
  "\nCanonry collects anonymous telemetry to prioritize features.\nDisable any time: canonry telemetry disable\nLearn more: https://ainyc.ai/telemetry\n\n"
251
257
  );
252
258
  }
253
- function trackEvent(event, properties) {
259
+ function detectAndTrackUpgrade() {
260
+ if (!isTelemetryEnabled()) return;
261
+ if (!configExists()) return;
262
+ let lastSeen;
263
+ try {
264
+ const raw = loadConfigRaw();
265
+ lastSeen = raw?.lastSeenVersion;
266
+ } catch {
267
+ return;
268
+ }
269
+ if (lastSeen === VERSION) return;
270
+ try {
271
+ saveConfigPatch({ lastSeenVersion: VERSION });
272
+ } catch {
273
+ return;
274
+ }
275
+ if (!lastSeen) return;
276
+ trackEvent("cli.upgraded", { fromVersion: lastSeen, toVersion: VERSION });
277
+ }
278
+ function trackEvent(event, properties, options) {
254
279
  if (!isTelemetryEnabled()) return;
255
280
  const anonymousId = getOrCreateAnonymousId();
256
281
  if (!anonymousId) return;
257
282
  const payload = {
258
283
  anonymousId,
284
+ sessionId: SESSION_ID,
285
+ source: options?.source ?? CURRENT_SOURCE,
259
286
  event,
260
287
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
261
288
  version: VERSION,
262
289
  nodeVersion: process.versions.node,
263
290
  os: process.platform,
264
291
  arch: process.arch,
265
- properties
292
+ ...options?.sourceContext ? { sourceContext: options.sourceContext } : {},
293
+ ...options?.errorCode ? { errorCode: options.errorCode } : {},
294
+ ...properties ? { properties } : {}
266
295
  };
267
296
  const controller = new AbortController();
268
297
  const timeout = setTimeout(() => controller.abort(), TIMEOUT_MS);
@@ -278,7 +307,7 @@ function trackEvent(event, properties) {
278
307
 
279
308
  // src/server.ts
280
309
  import { createRequire as createRequire3 } from "module";
281
- import crypto30 from "crypto";
310
+ import crypto31 from "crypto";
282
311
  import fs12 from "fs";
283
312
  import path14 from "path";
284
313
  import { fileURLToPath as fileURLToPath2 } from "url";
@@ -20165,12 +20194,52 @@ function removeWordpressConnection(config, projectName) {
20165
20194
  }
20166
20195
 
20167
20196
  // src/job-runner.ts
20168
- import crypto21 from "crypto";
20197
+ import crypto22 from "crypto";
20169
20198
  import fs7 from "fs";
20170
20199
  import path9 from "path";
20171
20200
  import os5 from "os";
20172
20201
  import { and as and12, eq as eq24, inArray as inArray7, sql as sql8 } from "drizzle-orm";
20173
20202
 
20203
+ // src/run-telemetry.ts
20204
+ import crypto21 from "crypto";
20205
+ function extractRegistrableHost(input) {
20206
+ if (!input) return null;
20207
+ const trimmed = input.trim();
20208
+ if (!trimmed) return null;
20209
+ let host;
20210
+ try {
20211
+ const candidate = /^[a-z][a-z0-9+.-]*:\/\//i.test(trimmed) ? trimmed : `https://${trimmed}`;
20212
+ host = new URL(candidate).hostname;
20213
+ } catch {
20214
+ return null;
20215
+ }
20216
+ host = host.toLowerCase();
20217
+ if (host.startsWith("www.")) host = host.slice(4);
20218
+ if (!host || !host.includes(".")) return null;
20219
+ return host;
20220
+ }
20221
+ function hashDomain(input) {
20222
+ const host = extractRegistrableHost(input);
20223
+ if (!host) return null;
20224
+ return crypto21.createHash("sha256").update(host).digest("hex");
20225
+ }
20226
+ function buildRunCompletedProps(input) {
20227
+ const totalMs = input.phases?.total_ms ?? Date.now() - input.startTime;
20228
+ const props = {
20229
+ status: input.status,
20230
+ providerCount: input.providerCount,
20231
+ providers: [...input.providers],
20232
+ queryCount: input.queryCount,
20233
+ durationMs: totalMs
20234
+ };
20235
+ if (input.trigger) props.trigger = input.trigger;
20236
+ const domainHash = hashDomain(input.canonicalDomain ?? null);
20237
+ if (domainHash) props.domainHash = domainHash;
20238
+ if (input.phases) props.phases = input.phases;
20239
+ if (input.location) props.location = input.location;
20240
+ return props;
20241
+ }
20242
+
20174
20243
  // src/citation-utils.ts
20175
20244
  function domainMatches(domain, canonicalDomain) {
20176
20245
  const normalized = normalizeProjectDomain(canonicalDomain);
@@ -20481,20 +20550,26 @@ var JobRunner = class {
20481
20550
  async executeRun(runId, projectId, providerOverride, locationOverride) {
20482
20551
  const now = (/* @__PURE__ */ new Date()).toISOString();
20483
20552
  const startTime = Date.now();
20553
+ let providerCallStart;
20554
+ let providerCallEnd;
20484
20555
  let runLocation;
20485
20556
  let activeProviders = [];
20486
20557
  let projectQueries = [];
20558
+ let runTrigger;
20559
+ let canonicalDomain;
20487
20560
  const providerDispatchCounts = /* @__PURE__ */ new Map();
20488
20561
  try {
20489
20562
  const existingRun = this.getRunState(runId);
20490
20563
  if (!existingRun) {
20491
20564
  throw new Error(`Run ${runId} not found`);
20492
20565
  }
20566
+ runTrigger = existingRun.trigger ?? void 0;
20493
20567
  if (existingRun.status === "cancelled") {
20494
20568
  this.handleCancelledRun(runId, projectId, startTime, {
20495
20569
  providerCount: 0,
20496
20570
  providers: [],
20497
- queryCount: 0
20571
+ queryCount: 0,
20572
+ ...runTrigger ? { trigger: runTrigger } : {}
20498
20573
  });
20499
20574
  return;
20500
20575
  }
@@ -20509,6 +20584,7 @@ var JobRunner = class {
20509
20584
  if (!project) {
20510
20585
  throw new Error(`Project ${projectId} not found`);
20511
20586
  }
20587
+ canonicalDomain = project.canonicalDomain;
20512
20588
  if (locationOverride === null) {
20513
20589
  runLocation = void 0;
20514
20590
  } else if (locationOverride) {
@@ -20536,7 +20612,9 @@ var JobRunner = class {
20536
20612
  providerCount: activeProviders.length,
20537
20613
  providers: activeProviders.map((provider) => provider.adapter.name),
20538
20614
  queryCount: projectQueries.length,
20539
- ...runLocation ? { location: runLocation.label } : {}
20615
+ ...runLocation ? { location: runLocation.label } : {},
20616
+ ...runTrigger ? { trigger: runTrigger } : {},
20617
+ ...canonicalDomain ? { canonicalDomain } : {}
20540
20618
  };
20541
20619
  const queriesPerProvider = projectQueries.length;
20542
20620
  const todayPeriod = getCurrentUsageDay();
@@ -20602,7 +20680,7 @@ var JobRunner = class {
20602
20680
  );
20603
20681
  let screenshotRelPath = null;
20604
20682
  if (raw.screenshotPath && fs7.existsSync(raw.screenshotPath)) {
20605
- const snapshotId = crypto21.randomUUID();
20683
+ const snapshotId = crypto22.randomUUID();
20606
20684
  const screenshotDir = path9.join(os5.homedir(), ".canonry", "screenshots", runId);
20607
20685
  if (!fs7.existsSync(screenshotDir)) fs7.mkdirSync(screenshotDir, { recursive: true });
20608
20686
  const destPath = path9.join(screenshotDir, `${snapshotId}.png`);
@@ -20632,7 +20710,7 @@ var JobRunner = class {
20632
20710
  }).run();
20633
20711
  } else {
20634
20712
  this.db.insert(querySnapshots).values({
20635
- id: crypto21.randomUUID(),
20713
+ id: crypto22.randomUUID(),
20636
20714
  runId,
20637
20715
  queryId: q.id,
20638
20716
  provider: providerName,
@@ -20668,6 +20746,7 @@ var JobRunner = class {
20668
20746
  }
20669
20747
  }
20670
20748
  };
20749
+ providerCallStart = Date.now();
20671
20750
  await runWithConcurrency(apiProviders, resolveProviderFanout(), async (registeredProvider) => {
20672
20751
  await Promise.all(projectQueries.map(async (q) => {
20673
20752
  await processQueryForProvider(registeredProvider, q);
@@ -20678,6 +20757,7 @@ var JobRunner = class {
20678
20757
  await processQueryForProvider(registeredProvider, q);
20679
20758
  }
20680
20759
  }
20760
+ providerCallEnd = Date.now();
20681
20761
  this.throwIfRunCancelled(runId);
20682
20762
  const allFailed = totalSnapshotsInserted === 0 && providerErrors.size > 0;
20683
20763
  const someFailed = providerErrors.size > 0;
@@ -20693,15 +20773,22 @@ var JobRunner = class {
20693
20773
  this.flushProviderUsage(projectId, providerDispatchCounts);
20694
20774
  const finalStatus = allFailed ? "failed" : someFailed ? "partial" : "completed";
20695
20775
  const failureCode = providerErrors.size > 0 ? classifyProviderErrors(providerErrors) : void 0;
20696
- trackEvent("run.completed", {
20697
- status: finalStatus,
20698
- providerCount: executionContext.providerCount,
20699
- providers: executionContext.providers,
20700
- queryCount: executionContext.queryCount,
20701
- durationMs: Date.now() - startTime,
20702
- ...failureCode ? { errorCode: failureCode } : {},
20703
- ...executionContext.location ? { location: executionContext.location } : {}
20704
- });
20776
+ const phases = buildPhases({ startTime, providerCallStart, providerCallEnd });
20777
+ trackEvent(
20778
+ "run.completed",
20779
+ buildRunCompletedProps({
20780
+ status: finalStatus,
20781
+ providerCount: executionContext.providerCount,
20782
+ providers: executionContext.providers,
20783
+ queryCount: executionContext.queryCount,
20784
+ startTime,
20785
+ trigger: executionContext.trigger,
20786
+ canonicalDomain: executionContext.canonicalDomain,
20787
+ phases,
20788
+ location: executionContext.location
20789
+ }),
20790
+ failureCode ? { errorCode: failureCode } : void 0
20791
+ );
20705
20792
  this.incrementUsage(projectId, "runs", 1);
20706
20793
  if (this.onRunCompleted) {
20707
20794
  this.onRunCompleted(runId, projectId).catch((err) => {
@@ -20713,7 +20800,9 @@ var JobRunner = class {
20713
20800
  providerCount: activeProviders.length,
20714
20801
  providers: activeProviders.map((provider) => provider.adapter.name),
20715
20802
  queryCount: projectQueries.length,
20716
- ...runLocation ? { location: runLocation.label } : {}
20803
+ ...runLocation ? { location: runLocation.label } : {},
20804
+ ...runTrigger ? { trigger: runTrigger } : {},
20805
+ ...canonicalDomain ? { canonicalDomain } : {}
20717
20806
  };
20718
20807
  if (err instanceof RunCancelledError || this.isRunCancelled(runId)) {
20719
20808
  this.flushProviderUsage(projectId, providerDispatchCounts);
@@ -20728,25 +20817,36 @@ var JobRunner = class {
20728
20817
  }).where(eq24(runs.id, runId)).run();
20729
20818
  this.flushProviderUsage(projectId, providerDispatchCounts);
20730
20819
  const abortReason = classifyRunAbortReason(errorMessage);
20820
+ const phases = buildPhases({ startTime, providerCallStart, providerCallEnd });
20731
20821
  if (abortReason) {
20822
+ const domainHash = hashDomain(executionContext.canonicalDomain ?? null);
20732
20823
  trackEvent("run.aborted", {
20733
20824
  reason: abortReason,
20734
20825
  providerCount: executionContext.providerCount,
20735
20826
  providers: executionContext.providers,
20736
20827
  queryCount: executionContext.queryCount,
20737
20828
  durationMs: Date.now() - startTime,
20829
+ ...executionContext.trigger ? { trigger: executionContext.trigger } : {},
20830
+ ...domainHash ? { domainHash } : {},
20831
+ ...phases ? { phases } : {},
20738
20832
  ...executionContext.location ? { location: executionContext.location } : {}
20739
20833
  });
20740
20834
  } else {
20741
- trackEvent("run.completed", {
20742
- status: "failed",
20743
- errorCode: "UNKNOWN",
20744
- providerCount: executionContext.providerCount,
20745
- providers: executionContext.providers,
20746
- queryCount: executionContext.queryCount,
20747
- durationMs: Date.now() - startTime,
20748
- ...executionContext.location ? { location: executionContext.location } : {}
20749
- });
20835
+ trackEvent(
20836
+ "run.completed",
20837
+ buildRunCompletedProps({
20838
+ status: "failed",
20839
+ providerCount: executionContext.providerCount,
20840
+ providers: executionContext.providers,
20841
+ queryCount: executionContext.queryCount,
20842
+ startTime,
20843
+ trigger: executionContext.trigger,
20844
+ canonicalDomain: executionContext.canonicalDomain,
20845
+ phases,
20846
+ location: executionContext.location
20847
+ }),
20848
+ { errorCode: "UNKNOWN" }
20849
+ );
20750
20850
  }
20751
20851
  if (this.onRunCompleted) {
20752
20852
  this.onRunCompleted(runId, projectId).catch((notifErr) => {
@@ -20759,7 +20859,7 @@ var JobRunner = class {
20759
20859
  const now = (/* @__PURE__ */ new Date()).toISOString();
20760
20860
  const period = now.slice(0, 10);
20761
20861
  this.db.insert(usageCounters).values({
20762
- id: crypto21.randomUUID(),
20862
+ id: crypto22.randomUUID(),
20763
20863
  scope,
20764
20864
  period,
20765
20865
  metric,
@@ -20780,7 +20880,8 @@ var JobRunner = class {
20780
20880
  return this.db.select({
20781
20881
  status: runs.status,
20782
20882
  finishedAt: runs.finishedAt,
20783
- error: runs.error
20883
+ error: runs.error,
20884
+ trigger: runs.trigger
20784
20885
  }).from(runs).where(eq24(runs.id, runId)).get();
20785
20886
  }
20786
20887
  isRunCancelled(runId) {
@@ -20799,14 +20900,20 @@ var JobRunner = class {
20799
20900
  error: currentRun.error ?? "Cancelled by user"
20800
20901
  }).where(eq24(runs.id, runId)).run();
20801
20902
  }
20802
- trackEvent("run.completed", {
20803
- status: "cancelled",
20804
- providerCount: context.providerCount,
20805
- providers: context.providers,
20806
- queryCount: context.queryCount,
20807
- durationMs: Date.now() - startTime,
20808
- ...context.location ? { location: context.location } : {}
20809
- });
20903
+ trackEvent(
20904
+ "run.completed",
20905
+ buildRunCompletedProps({
20906
+ status: "cancelled",
20907
+ providerCount: context.providerCount,
20908
+ providers: context.providers,
20909
+ queryCount: context.queryCount,
20910
+ startTime,
20911
+ trigger: context.trigger,
20912
+ canonicalDomain: context.canonicalDomain,
20913
+ location: context.location
20914
+ }),
20915
+ { errorCode: "RUN_CANCELLED" }
20916
+ );
20810
20917
  if (this.onRunCompleted) {
20811
20918
  this.onRunCompleted(runId, projectId).catch((err) => {
20812
20919
  log.error("notification.callback-failed", { runId, error: err instanceof Error ? err.message : String(err) });
@@ -20817,9 +20924,18 @@ var JobRunner = class {
20817
20924
  function getCurrentUsageDay() {
20818
20925
  return (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
20819
20926
  }
20927
+ function buildPhases(input) {
20928
+ const total_ms = Date.now() - input.startTime;
20929
+ if (input.providerCallStart === void 0) {
20930
+ return { setup_ms: total_ms, provider_call_ms: 0, total_ms };
20931
+ }
20932
+ const setup_ms = input.providerCallStart - input.startTime;
20933
+ const provider_call_ms = (input.providerCallEnd ?? Date.now()) - input.providerCallStart;
20934
+ return { setup_ms, provider_call_ms, total_ms };
20935
+ }
20820
20936
 
20821
20937
  // src/gsc-sync.ts
20822
- import crypto22 from "crypto";
20938
+ import crypto23 from "crypto";
20823
20939
  import { eq as eq25, and as and13, sql as sql9 } from "drizzle-orm";
20824
20940
  var log2 = createLogger("GscSync");
20825
20941
  function formatDate3(d) {
@@ -20885,7 +21001,7 @@ async function executeGscSync(db, runId, projectId, opts) {
20885
21001
  for (const row of batch) {
20886
21002
  const [query, page, country, device, date] = row.keys;
20887
21003
  db.insert(gscSearchData).values({
20888
- id: crypto22.randomUUID(),
21004
+ id: crypto23.randomUUID(),
20889
21005
  projectId,
20890
21006
  syncRunId: runId,
20891
21007
  date: date ?? "",
@@ -20919,7 +21035,7 @@ async function executeGscSync(db, runId, projectId, opts) {
20919
21035
  const rich = ir.richResultsResult;
20920
21036
  const inspectedAt = (/* @__PURE__ */ new Date()).toISOString();
20921
21037
  db.insert(gscUrlInspections).values({
20922
- id: crypto22.randomUUID(),
21038
+ id: crypto23.randomUUID(),
20923
21039
  projectId,
20924
21040
  syncRunId: runId,
20925
21041
  url: pageUrl,
@@ -20963,7 +21079,7 @@ async function executeGscSync(db, runId, projectId, opts) {
20963
21079
  const snapshotDate = formatDate3(/* @__PURE__ */ new Date());
20964
21080
  db.delete(gscCoverageSnapshots).where(and13(eq25(gscCoverageSnapshots.projectId, projectId), eq25(gscCoverageSnapshots.date, snapshotDate))).run();
20965
21081
  db.insert(gscCoverageSnapshots).values({
20966
- id: crypto22.randomUUID(),
21082
+ id: crypto23.randomUUID(),
20967
21083
  projectId,
20968
21084
  syncRunId: runId,
20969
21085
  date: snapshotDate,
@@ -20983,7 +21099,7 @@ async function executeGscSync(db, runId, projectId, opts) {
20983
21099
  }
20984
21100
 
20985
21101
  // src/gsc-inspect-sitemap.ts
20986
- import crypto23 from "crypto";
21102
+ import crypto24 from "crypto";
20987
21103
  import { eq as eq26, and as and14 } from "drizzle-orm";
20988
21104
 
20989
21105
  // src/sitemap-parser.ts
@@ -21152,7 +21268,7 @@ async function executeInspectSitemap(db, runId, projectId, opts) {
21152
21268
  const rich = ir.richResultsResult;
21153
21269
  const inspectedAt = (/* @__PURE__ */ new Date()).toISOString();
21154
21270
  db.insert(gscUrlInspections).values({
21155
- id: crypto23.randomUUID(),
21271
+ id: crypto24.randomUUID(),
21156
21272
  projectId,
21157
21273
  syncRunId: runId,
21158
21274
  url: pageUrl,
@@ -21202,7 +21318,7 @@ async function executeInspectSitemap(db, runId, projectId, opts) {
21202
21318
  const snapshotDate = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
21203
21319
  db.delete(gscCoverageSnapshots).where(and14(eq26(gscCoverageSnapshots.projectId, projectId), eq26(gscCoverageSnapshots.date, snapshotDate))).run();
21204
21320
  db.insert(gscCoverageSnapshots).values({
21205
- id: crypto23.randomUUID(),
21321
+ id: crypto24.randomUUID(),
21206
21322
  projectId,
21207
21323
  syncRunId: runId,
21208
21324
  date: snapshotDate,
@@ -21223,7 +21339,7 @@ async function executeInspectSitemap(db, runId, projectId, opts) {
21223
21339
  }
21224
21340
 
21225
21341
  // src/bing-inspect-sitemap.ts
21226
- import crypto24 from "crypto";
21342
+ import crypto25 from "crypto";
21227
21343
  import { eq as eq27, desc as desc12 } from "drizzle-orm";
21228
21344
  var log5 = createLogger("BingInspectSitemap");
21229
21345
  function parseBingDate2(value) {
@@ -21311,7 +21427,7 @@ async function executeBingInspectSitemap(db, runId, projectId, opts) {
21311
21427
  derivedInIndex = false;
21312
21428
  }
21313
21429
  db.insert(bingUrlInspections).values({
21314
- id: crypto24.randomUUID(),
21430
+ id: crypto25.randomUUID(),
21315
21431
  projectId,
21316
21432
  url: pageUrl,
21317
21433
  httpCode,
@@ -21369,7 +21485,7 @@ async function executeBingInspectSitemap(db, runId, projectId, opts) {
21369
21485
  const snapshotDate = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
21370
21486
  const snapNow = (/* @__PURE__ */ new Date()).toISOString();
21371
21487
  db.insert(bingCoverageSnapshots).values({
21372
- id: crypto24.randomUUID(),
21488
+ id: crypto25.randomUUID(),
21373
21489
  projectId,
21374
21490
  syncRunId: runId,
21375
21491
  date: snapshotDate,
@@ -21409,7 +21525,7 @@ async function executeBingInspectSitemap(db, runId, projectId, opts) {
21409
21525
  }
21410
21526
 
21411
21527
  // src/commoncrawl-sync.ts
21412
- import crypto25 from "crypto";
21528
+ import crypto26 from "crypto";
21413
21529
  import path10 from "path";
21414
21530
  import { and as and15, eq as eq28, sql as sql10 } from "drizzle-orm";
21415
21531
  var log6 = createLogger("CommonCrawlSync");
@@ -21484,7 +21600,7 @@ async function executeReleaseSync(db, syncId, opts) {
21484
21600
  if (!projectIds) continue;
21485
21601
  for (const projectId of projectIds) {
21486
21602
  expanded.push({
21487
- id: crypto25.randomUUID(),
21603
+ id: crypto26.randomUUID(),
21488
21604
  projectId,
21489
21605
  releaseSyncId: syncId,
21490
21606
  release,
@@ -21504,7 +21620,7 @@ async function executeReleaseSync(db, syncId, opts) {
21504
21620
  const projectRows = rowsByProject.get(p.id) ?? [];
21505
21621
  const summary = computeSummary(projectRows);
21506
21622
  tx.insert(backlinkSummaries).values({
21507
- id: crypto25.randomUUID(),
21623
+ id: crypto26.randomUUID(),
21508
21624
  projectId: p.id,
21509
21625
  releaseSyncId: syncId,
21510
21626
  release,
@@ -21600,7 +21716,7 @@ function computeSummary(rows) {
21600
21716
  }
21601
21717
 
21602
21718
  // src/backlink-extract.ts
21603
- import crypto26 from "crypto";
21719
+ import crypto27 from "crypto";
21604
21720
  import fs8 from "fs";
21605
21721
  import { and as and16, desc as desc13, eq as eq29 } from "drizzle-orm";
21606
21722
  var log7 = createLogger("BacklinkExtract");
@@ -21652,7 +21768,7 @@ async function executeBacklinkExtract(db, runId, projectId, opts = {}) {
21652
21768
  ).run();
21653
21769
  if (rows.length > 0) {
21654
21770
  const values = rows.map((r) => ({
21655
- id: crypto26.randomUUID(),
21771
+ id: crypto27.randomUUID(),
21656
21772
  projectId,
21657
21773
  releaseSyncId: syncId,
21658
21774
  release,
@@ -21665,7 +21781,7 @@ async function executeBacklinkExtract(db, runId, projectId, opts = {}) {
21665
21781
  }
21666
21782
  const summary = computeSummary2(rows);
21667
21783
  tx.insert(backlinkSummaries).values({
21668
- id: crypto26.randomUUID(),
21784
+ id: crypto27.randomUUID(),
21669
21785
  projectId,
21670
21786
  releaseSyncId: syncId,
21671
21787
  release,
@@ -21905,7 +22021,7 @@ var Scheduler = class {
21905
22021
 
21906
22022
  // src/notifier.ts
21907
22023
  import { eq as eq31, desc as desc14, and as and17, or as or4 } from "drizzle-orm";
21908
- import crypto27 from "crypto";
22024
+ import crypto28 from "crypto";
21909
22025
  var log9 = createLogger("Notifier");
21910
22026
  var Notifier = class {
21911
22027
  db;
@@ -22087,7 +22203,7 @@ var Notifier = class {
22087
22203
  }
22088
22204
  logDelivery(projectId, notificationId, event, status, error) {
22089
22205
  this.db.insert(auditLog).values({
22090
- id: crypto27.randomUUID(),
22206
+ id: crypto28.randomUUID(),
22091
22207
  projectId,
22092
22208
  actor: "scheduler",
22093
22209
  action: `notification.${status}`,
@@ -22145,7 +22261,7 @@ var RunCoordinator = class {
22145
22261
  };
22146
22262
 
22147
22263
  // src/agent/session-registry.ts
22148
- import crypto29 from "crypto";
22264
+ import crypto30 from "crypto";
22149
22265
  import { eq as eq33 } from "drizzle-orm";
22150
22266
 
22151
22267
  // src/agent/session.ts
@@ -22495,7 +22611,7 @@ function resolveSessionProviderAndModel(config, opts) {
22495
22611
  }
22496
22612
 
22497
22613
  // src/agent/memory-store.ts
22498
- import crypto28 from "crypto";
22614
+ import crypto29 from "crypto";
22499
22615
  import { and as and18, desc as desc15, eq as eq32, like as like2, sql as sql11 } from "drizzle-orm";
22500
22616
  var COMPACTION_KEY_PREFIX = "compaction:";
22501
22617
  var COMPACTION_NOTES_PER_SESSION = 3;
@@ -22524,7 +22640,7 @@ function upsertMemoryEntry(db, args) {
22524
22640
  throw new Error(`memory key prefix "${COMPACTION_KEY_PREFIX}" is reserved for compaction notes`);
22525
22641
  }
22526
22642
  const now = (/* @__PURE__ */ new Date()).toISOString();
22527
- const id = crypto28.randomUUID();
22643
+ const id = crypto29.randomUUID();
22528
22644
  db.insert(agentMemory).values({
22529
22645
  id,
22530
22646
  projectId: args.projectId,
@@ -22561,7 +22677,7 @@ function writeCompactionNote(db, args) {
22561
22677
  }
22562
22678
  const now = (/* @__PURE__ */ new Date()).toISOString();
22563
22679
  const key = `${COMPACTION_KEY_PREFIX}${args.sessionId}:${now}`;
22564
- const id = crypto28.randomUUID();
22680
+ const id = crypto29.randomUUID();
22565
22681
  let inserted;
22566
22682
  db.transaction((tx) => {
22567
22683
  tx.insert(agentMemory).values({
@@ -23152,7 +23268,7 @@ ${lines.join("\n")}
23152
23268
  insertRow(params) {
23153
23269
  const now = (/* @__PURE__ */ new Date()).toISOString();
23154
23270
  this.opts.db.insert(agentSessions).values({
23155
- id: crypto29.randomUUID(),
23271
+ id: crypto30.randomUUID(),
23156
23272
  projectId: params.projectId,
23157
23273
  systemPrompt: params.systemPrompt,
23158
23274
  modelProvider: params.provider ?? params.modelProvider ?? AgentProviderIds.claude,
@@ -24069,7 +24185,7 @@ function summarizeProviderConfig(provider, config) {
24069
24185
  };
24070
24186
  }
24071
24187
  function hashApiKey(key) {
24072
- return crypto30.createHash("sha256").update(key).digest("hex");
24188
+ return crypto31.createHash("sha256").update(key).digest("hex");
24073
24189
  }
24074
24190
  function parseCookies2(header) {
24075
24191
  if (!header) return {};
@@ -24336,7 +24452,7 @@ async function createServer(opts) {
24336
24452
  return removed;
24337
24453
  }
24338
24454
  };
24339
- const googleStateSecret = process.env.GOOGLE_STATE_SECRET ?? crypto30.randomBytes(32).toString("hex");
24455
+ const googleStateSecret = process.env.GOOGLE_STATE_SECRET ?? crypto31.randomBytes(32).toString("hex");
24340
24456
  const googleConnectionStore = {
24341
24457
  listConnections: (domain) => listGoogleConnections(opts.config, domain),
24342
24458
  getConnection: (domain, connectionType) => getGoogleConnection(opts.config, domain, connectionType),
@@ -24386,7 +24502,7 @@ async function createServer(opts) {
24386
24502
  if (!existing) {
24387
24503
  const prefix = opts.config.apiKey.slice(0, 12);
24388
24504
  opts.db.insert(apiKeys).values({
24389
- id: `key_${crypto30.randomBytes(8).toString("hex")}`,
24505
+ id: `key_${crypto31.randomBytes(8).toString("hex")}`,
24390
24506
  name: "default",
24391
24507
  keyHash,
24392
24508
  keyPrefix: prefix,
@@ -24410,7 +24526,7 @@ async function createServer(opts) {
24410
24526
  };
24411
24527
  const createSession = (apiKeyId) => {
24412
24528
  pruneExpiredSessions();
24413
- const sessionId = crypto30.randomBytes(32).toString("hex");
24529
+ const sessionId = crypto31.randomBytes(32).toString("hex");
24414
24530
  sessions.set(sessionId, {
24415
24531
  apiKeyId,
24416
24532
  expiresAt: Date.now() + SESSION_TTL_MS
@@ -24606,7 +24722,7 @@ async function createServer(opts) {
24606
24722
  deps: {
24607
24723
  enqueueAutoExtract: ({ projectId, release: r }) => {
24608
24724
  const now = (/* @__PURE__ */ new Date()).toISOString();
24609
- const runId = crypto30.randomUUID();
24725
+ const runId = crypto31.randomUUID();
24610
24726
  opts.db.insert(runs).values({
24611
24727
  id: runId,
24612
24728
  projectId,
@@ -24742,7 +24858,7 @@ async function createServer(opts) {
24742
24858
  const targetProjectIds = affectedProjectIds.length > 0 ? affectedProjectIds : [null];
24743
24859
  const createdAt = (/* @__PURE__ */ new Date()).toISOString();
24744
24860
  opts.db.insert(auditLog).values(targetProjectIds.map((projectId) => ({
24745
- id: crypto30.randomUUID(),
24861
+ id: crypto31.randomUUID(),
24746
24862
  projectId,
24747
24863
  actor: "api",
24748
24864
  action: existing ? "provider.updated" : "provider.created",
@@ -24985,10 +25101,12 @@ function parseQueryResponse(raw, count) {
24985
25101
  }
24986
25102
 
24987
25103
  export {
25104
+ setTelemetrySource,
24988
25105
  isTelemetryEnabled,
24989
25106
  getOrCreateAnonymousId,
24990
25107
  isFirstRun,
24991
25108
  showFirstRunNotice,
25109
+ detectAndTrackUpgrade,
24992
25110
  trackEvent,
24993
25111
  reparseStoredResult2 as reparseStoredResult,
24994
25112
  reparseStoredResult3 as reparseStoredResult2,