brakit 0.10.1 → 0.10.2

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.
@@ -10,7 +10,7 @@ var __export = (target, all) => {
10
10
  };
11
11
 
12
12
  // src/constants/config.ts
13
- var PROJECT_HASH_LENGTH, SECRET_SCAN_ARRAY_LIMIT, PII_SCAN_ARRAY_LIMIT, MIN_SECRET_VALUE_LENGTH, FULL_RECORD_MIN_FIELDS, LIST_PII_MIN_ITEMS, MAX_OBJECT_SCAN_DEPTH, ISSUE_PRUNE_TTL_MS, OVERFETCH_UNWRAP_MIN_SIZE, STALE_ISSUE_TTL_MS, METRICS_DIR, PORT_FILE, VALID_ISSUE_STATES, VALID_AI_FIX_STATUSES, VALID_SECURITY_SEVERITIES, TELEMETRY_EVENT_CLI_INVOKED, TELEMETRY_EVENT_CLI_UNINSTALL, DETAIL_PREVIEW_LENGTH;
13
+ var PROJECT_HASH_LENGTH, SECRET_SCAN_ARRAY_LIMIT, PII_SCAN_ARRAY_LIMIT, MIN_SECRET_VALUE_LENGTH, FULL_RECORD_MIN_FIELDS, LIST_PII_MIN_ITEMS, MAX_OBJECT_SCAN_DEPTH, ISSUE_PRUNE_TTL_MS, OVERFETCH_UNWRAP_MIN_SIZE, STALE_ISSUE_TTL_MS, METRICS_DIR, PORT_FILE, VALID_ISSUE_STATES, VALID_AI_FIX_STATUSES, VALID_SECURITY_SEVERITIES, DETAIL_PREVIEW_LENGTH;
14
14
  var init_config = __esm({
15
15
  "src/constants/config.ts"() {
16
16
  "use strict";
@@ -29,8 +29,6 @@ var init_config = __esm({
29
29
  VALID_ISSUE_STATES = /* @__PURE__ */ new Set(["open", "fixing", "resolved", "stale", "regressed"]);
30
30
  VALID_AI_FIX_STATUSES = /* @__PURE__ */ new Set(["fixed", "wont_fix"]);
31
31
  VALID_SECURITY_SEVERITIES = /* @__PURE__ */ new Set(["critical", "warning"]);
32
- TELEMETRY_EVENT_CLI_INVOKED = "cli_invoked";
33
- TELEMETRY_EVENT_CLI_UNINSTALL = "cli_uninstall";
34
32
  DETAIL_PREVIEW_LENGTH = 120;
35
33
  }
36
34
  });
@@ -72,8 +70,91 @@ var init_type_guards = __esm({
72
70
  }
73
71
  });
74
72
 
73
+ // src/constants/detection.ts
74
+ var KNOWN_DEPENDENCY_NAMES, KNOWN_DEPENDENCY_SET;
75
+ var init_detection = __esm({
76
+ "src/constants/detection.ts"() {
77
+ "use strict";
78
+ KNOWN_DEPENDENCY_NAMES = [
79
+ // -- Frameworks (meta) --
80
+ "next",
81
+ "@remix-run/dev",
82
+ "nuxt",
83
+ "astro",
84
+ // -- Frameworks (backend) --
85
+ "@nestjs/core",
86
+ "@adonisjs/core",
87
+ "sails",
88
+ "express",
89
+ "fastify",
90
+ "hono",
91
+ "koa",
92
+ "@hapi/hapi",
93
+ "elysia",
94
+ "h3",
95
+ "nitro",
96
+ "@trpc/server",
97
+ // -- Bundlers --
98
+ "vite",
99
+ // -- ORM / query builders --
100
+ "prisma",
101
+ "@prisma/client",
102
+ "drizzle-orm",
103
+ "typeorm",
104
+ "sequelize",
105
+ "mongoose",
106
+ "kysely",
107
+ "knex",
108
+ "@mikro-orm/core",
109
+ "objection",
110
+ // -- DB drivers --
111
+ "pg",
112
+ "mysql2",
113
+ "mongodb",
114
+ "better-sqlite3",
115
+ "@libsql/client",
116
+ "@planetscale/database",
117
+ "ioredis",
118
+ "redis",
119
+ // -- Auth --
120
+ "lucia",
121
+ "next-auth",
122
+ "@auth/core",
123
+ "passport",
124
+ // -- Queues / messaging --
125
+ "bullmq",
126
+ "amqplib",
127
+ "kafkajs",
128
+ // -- Validation --
129
+ "zod",
130
+ "joi",
131
+ "yup",
132
+ "arktype",
133
+ "valibot",
134
+ // -- HTTP clients --
135
+ "axios",
136
+ "got",
137
+ "ky",
138
+ "undici",
139
+ // -- Realtime --
140
+ "socket.io",
141
+ "ws",
142
+ // -- CSS / styling --
143
+ "tailwindcss",
144
+ // -- Testing --
145
+ "vitest",
146
+ "jest",
147
+ "mocha",
148
+ // -- Runtime indicators --
149
+ "bun-types",
150
+ "@types/bun"
151
+ ];
152
+ KNOWN_DEPENDENCY_SET = new Set(KNOWN_DEPENDENCY_NAMES);
153
+ }
154
+ });
155
+
75
156
  // src/constants/labels.ts
76
- var DASHBOARD_PREFIX, DASHBOARD_API_REQUESTS, DASHBOARD_API_EVENTS, DASHBOARD_API_FLOWS, DASHBOARD_API_CLEAR, DASHBOARD_API_LOGS, DASHBOARD_API_FETCHES, DASHBOARD_API_ERRORS, DASHBOARD_API_QUERIES, DASHBOARD_API_INGEST, DASHBOARD_API_METRICS, DASHBOARD_API_ACTIVITY, DASHBOARD_API_METRICS_LIVE, DASHBOARD_API_INSIGHTS, DASHBOARD_API_SECURITY, DASHBOARD_API_TAB, DASHBOARD_API_FINDINGS, DASHBOARD_API_FINDINGS_REPORT, DASHBOARD_API_GRAPH, VALID_TABS_TUPLE, VALID_TABS, POSTHOG_HOST, POSTHOG_CAPTURE_PATH, POSTHOG_REQUEST_TIMEOUT_MS;
157
+ var DASHBOARD_PREFIX, DASHBOARD_API_REQUESTS, DASHBOARD_API_EVENTS, DASHBOARD_API_FLOWS, DASHBOARD_API_CLEAR, DASHBOARD_API_LOGS, DASHBOARD_API_FETCHES, DASHBOARD_API_ERRORS, DASHBOARD_API_QUERIES, DASHBOARD_API_INGEST, DASHBOARD_API_METRICS, DASHBOARD_API_ACTIVITY, DASHBOARD_API_METRICS_LIVE, DASHBOARD_API_INSIGHTS, DASHBOARD_API_SECURITY, DASHBOARD_API_TAB, DASHBOARD_API_FINDINGS, DASHBOARD_API_FINDINGS_REPORT, DASHBOARD_API_GRAPH, VALID_TABS_TUPLE, VALID_TABS;
77
158
  var init_labels = __esm({
78
159
  "src/constants/labels.ts"() {
79
160
  "use strict";
@@ -105,9 +186,6 @@ var init_labels = __esm({
105
186
  "explorer"
106
187
  ];
107
188
  VALID_TABS = new Set(VALID_TABS_TUPLE);
108
- POSTHOG_HOST = "https://us.i.posthog.com";
109
- POSTHOG_CAPTURE_PATH = "/i/v0/e/";
110
- POSTHOG_REQUEST_TIMEOUT_MS = 3e3;
111
189
  }
112
190
  });
113
191
 
@@ -136,7 +214,7 @@ var init_features = __esm({
136
214
  MAX_TIMELINE_EVENTS = 20;
137
215
  MAX_RESOLVED_DISPLAY = 5;
138
216
  ENRICHMENT_SEVERITY_FILTER = ["critical", "warning"];
139
- MCP_SERVER_VERSION = "0.10.1";
217
+ MCP_SERVER_VERSION = "0.10.2";
140
218
  RECOVERY_WINDOW_MS = 5 * 60 * 1e3;
141
219
  PORT_MIN = 1;
142
220
  PORT_MAX = 65535;
@@ -145,13 +223,32 @@ var init_features = __esm({
145
223
  }
146
224
  });
147
225
 
226
+ // src/constants/telemetry.ts
227
+ var POSTHOG_HOST, POSTHOG_CAPTURE_PATH, POSTHOG_REQUEST_TIMEOUT_MS, TELEMETRY_EVENT_CLI_INVOKED, TELEMETRY_EVENT_CLI_UNINSTALL, TELEMETRY_EVENT_DASHBOARD_VIEWED, TELEMETRY_EVENT_SESSION, TELEMETRY_SDK_NAME, SPEED_BUCKET_THRESHOLDS;
228
+ var init_telemetry = __esm({
229
+ "src/constants/telemetry.ts"() {
230
+ "use strict";
231
+ POSTHOG_HOST = "https://us.i.posthog.com";
232
+ POSTHOG_CAPTURE_PATH = "/i/v0/e/";
233
+ POSTHOG_REQUEST_TIMEOUT_MS = 3e3;
234
+ TELEMETRY_EVENT_CLI_INVOKED = "cli_invoked";
235
+ TELEMETRY_EVENT_CLI_UNINSTALL = "cli_uninstall";
236
+ TELEMETRY_EVENT_DASHBOARD_VIEWED = "dashboard_viewed";
237
+ TELEMETRY_EVENT_SESSION = "session";
238
+ TELEMETRY_SDK_NAME = "node";
239
+ SPEED_BUCKET_THRESHOLDS = [200, 500, 1e3, 2e3, 5e3];
240
+ }
241
+ });
242
+
148
243
  // src/constants/index.ts
149
244
  var init_constants = __esm({
150
245
  "src/constants/index.ts"() {
151
246
  "use strict";
152
247
  init_config();
248
+ init_detection();
153
249
  init_labels();
154
250
  init_features();
251
+ init_telemetry();
155
252
  }
156
253
  });
157
254
 
@@ -1206,6 +1303,7 @@ import { createHash as createHash2 } from "crypto";
1206
1303
  import { readFile as readFile3, readdir } from "fs/promises";
1207
1304
  import { existsSync as existsSync4 } from "fs";
1208
1305
  import { join as join2, relative } from "path";
1306
+ init_detection();
1209
1307
  var FRAMEWORKS = [
1210
1308
  // Meta-frameworks first (they bundle Express/Vite internally)
1211
1309
  { name: "nextjs", dep: "next", devCmd: "next dev", bin: "next", defaultPort: 3e3, devArgs: ["dev", "--port"] },
@@ -1234,23 +1332,22 @@ async function detectProject(rootDir) {
1234
1332
  const devCommand = matched?.devCmd ?? "";
1235
1333
  const devBin = matched ? join2(rootDir, "node_modules", ".bin", matched.bin) : "";
1236
1334
  const defaultPort = matched?.defaultPort ?? 3e3;
1237
- const packageManager = await detectPackageManager(rootDir);
1335
+ const packageManager = detectPackageManager(rootDir);
1238
1336
  return { framework, devCommand, devBin, defaultPort, packageManager };
1239
1337
  }
1240
- async function detectPackageManager(rootDir) {
1241
- if (await fileExists(join2(rootDir, "bun.lockb"))) return "bun";
1242
- if (await fileExists(join2(rootDir, "bun.lock"))) return "bun";
1243
- if (await fileExists(join2(rootDir, "pnpm-lock.yaml"))) return "pnpm";
1244
- if (await fileExists(join2(rootDir, "yarn.lock"))) return "yarn";
1245
- if (await fileExists(join2(rootDir, "package-lock.json"))) return "npm";
1246
- return "unknown";
1247
- }
1248
1338
  function detectFrameworkFromDeps(allDeps) {
1249
1339
  for (const f of FRAMEWORKS) {
1250
1340
  if (allDeps[f.dep]) return f.name;
1251
1341
  }
1252
1342
  return "unknown";
1253
1343
  }
1344
+ function detectPackageManager(rootDir) {
1345
+ if (existsSync4(join2(rootDir, "bun.lockb")) || existsSync4(join2(rootDir, "bun.lock"))) return "bun";
1346
+ if (existsSync4(join2(rootDir, "pnpm-lock.yaml"))) return "pnpm";
1347
+ if (existsSync4(join2(rootDir, "yarn.lock"))) return "yarn";
1348
+ if (existsSync4(join2(rootDir, "package-lock.json"))) return "npm";
1349
+ return "unknown";
1350
+ }
1254
1351
  var PYTHON_ENTRY_CANDIDATES = [
1255
1352
  "app.py",
1256
1353
  "main.py",
@@ -2005,7 +2102,7 @@ init_constants();
2005
2102
  init_endpoint();
2006
2103
 
2007
2104
  // src/index.ts
2008
- var VERSION = "0.10.1";
2105
+ var VERSION = "0.10.2";
2009
2106
 
2010
2107
  // src/cli/commands/install.ts
2011
2108
  init_constants();
@@ -2346,10 +2443,6 @@ init_constants();
2346
2443
  init_log();
2347
2444
  init_type_guards();
2348
2445
 
2349
- // src/telemetry/index.ts
2350
- import { platform as platform2, release, arch } from "os";
2351
- import { spawn } from "child_process";
2352
-
2353
2446
  // src/telemetry/config.ts
2354
2447
  init_features();
2355
2448
  import { homedir as homedir2, platform } from "os";
@@ -2359,10 +2452,14 @@ import { randomUUID as randomUUID2 } from "crypto";
2359
2452
  var IS_WINDOWS = platform() === "win32";
2360
2453
  var CONFIG_DIR = join4(homedir2(), ".brakit");
2361
2454
  var CONFIG_PATH = join4(CONFIG_DIR, "config.json");
2455
+ function isValidTelemetryConfig(value) {
2456
+ return typeof value === "object" && value !== null && typeof value.telemetry === "boolean" && typeof value.anonymousId === "string" && value.anonymousId.length > 0;
2457
+ }
2362
2458
  function readConfig() {
2363
2459
  try {
2364
2460
  if (!existsSync6(CONFIG_PATH)) return null;
2365
- return JSON.parse(readFileSync4(CONFIG_PATH, "utf-8"));
2461
+ const parsed = JSON.parse(readFileSync4(CONFIG_PATH, "utf-8"));
2462
+ return isValidTelemetryConfig(parsed) ? parsed : null;
2366
2463
  } catch {
2367
2464
  return null;
2368
2465
  }
@@ -2385,9 +2482,7 @@ function writeConfig(config) {
2385
2482
  }
2386
2483
  function getOrCreateConfig() {
2387
2484
  const existing = readConfig();
2388
- if (existing && typeof existing.telemetry === "boolean" && existing.anonymousId) {
2389
- return existing;
2390
- }
2485
+ if (existing) return existing;
2391
2486
  const config = { telemetry: true, anonymousId: randomUUID2() };
2392
2487
  writeConfig(config);
2393
2488
  return config;
@@ -2397,16 +2492,19 @@ function isTelemetryEnabled() {
2397
2492
  if (cachedEnabled !== null) return cachedEnabled;
2398
2493
  const env = process.env.BRAKIT_TELEMETRY;
2399
2494
  if (env !== void 0) {
2400
- cachedEnabled = env !== "false" && env !== "0" && env !== "off";
2495
+ const normalized = env.toLowerCase().trim();
2496
+ cachedEnabled = normalized !== "false" && normalized !== "0" && normalized !== "off";
2401
2497
  return cachedEnabled;
2402
2498
  }
2403
2499
  cachedEnabled = readConfig()?.telemetry ?? true;
2404
2500
  return cachedEnabled;
2405
2501
  }
2406
2502
 
2407
- // src/telemetry/index.ts
2408
- init_labels();
2409
- init_config();
2503
+ // src/telemetry/transport.ts
2504
+ import { platform as platform2, release, arch } from "os";
2505
+ import { spawn } from "child_process";
2506
+ init_telemetry();
2507
+ init_log();
2410
2508
  var POSTHOG_KEY = "phc_E9TwydCGnSfPLIUhNxChpeg32TSowjk31KiPhnLPP0x";
2411
2509
  function commonProperties() {
2412
2510
  return {
@@ -2420,7 +2518,7 @@ function commonProperties() {
2420
2518
  };
2421
2519
  }
2422
2520
  function sendToPosthog(event, properties) {
2423
- if (!isTelemetryEnabled()) return;
2521
+ if (!isTelemetryEnabled() || !POSTHOG_KEY) return;
2424
2522
  const config = getOrCreateConfig();
2425
2523
  const payload = {
2426
2524
  api_key: POSTHOG_KEY,
@@ -2430,26 +2528,198 @@ function sendToPosthog(event, properties) {
2430
2528
  properties: { ...commonProperties(), ...properties }
2431
2529
  };
2432
2530
  try {
2433
- const body = JSON.stringify(payload);
2531
+ const serializedPayload = JSON.stringify(payload);
2434
2532
  const url = `${POSTHOG_HOST}${POSTHOG_CAPTURE_PATH}`;
2435
2533
  const child = spawn(
2436
2534
  process.execPath,
2437
2535
  [
2438
2536
  "-e",
2439
- `fetch(${JSON.stringify(url)},{method:"POST",headers:{"content-type":"application/json"},body:${JSON.stringify(body)},signal:AbortSignal.timeout(${POSTHOG_REQUEST_TIMEOUT_MS})}).catch(()=>{})`
2537
+ `fetch(${JSON.stringify(url)},{method:"POST",headers:{"content-type":"application/json"},body:${JSON.stringify(serializedPayload)},signal:AbortSignal.timeout(${POSTHOG_REQUEST_TIMEOUT_MS})}).catch(()=>{})`
2440
2538
  ],
2441
2539
  { detached: true, stdio: "ignore" }
2442
2540
  );
2443
2541
  child.unref();
2444
- } catch {
2542
+ } catch (err) {
2543
+ brakitDebug(`telemetry send failed: ${err}`);
2445
2544
  }
2446
2545
  }
2447
2546
  function trackEvent(event, properties) {
2448
- sendToPosthog(event, { sdk: "node", ...properties });
2547
+ sendToPosthog(event, { sdk: TELEMETRY_SDK_NAME, ...properties });
2449
2548
  }
2450
2549
 
2550
+ // src/telemetry/session.ts
2551
+ init_telemetry();
2552
+ var defaultTransport = { send: sendToPosthog, track: trackEvent };
2553
+ var Session = class {
2554
+ constructor(transport = defaultTransport) {
2555
+ // ── Setup phase ──
2556
+ this.startTime = 0;
2557
+ this.framework = "unknown";
2558
+ this.packageManager = "";
2559
+ this.isCustomCommand = false;
2560
+ this.adapters = [];
2561
+ this.setupDurationMs = 0;
2562
+ this.setupSucceeded = false;
2563
+ // ── Detection ──
2564
+ this.detectedDependencies = [];
2565
+ this.adaptersFailed = [];
2566
+ this.configFilesDetected = [];
2567
+ this.jsRuntime = "node";
2568
+ this.loadedPackages = [];
2569
+ // ── Python SDK ──
2570
+ this.pythonConnected = false;
2571
+ this.pythonFramework = "unknown";
2572
+ this.pythonAdapters = [];
2573
+ this.pythonVersion = "";
2574
+ // ── Runtime accumulation ──
2575
+ this.requestCount = 0;
2576
+ this.insightTypes = /* @__PURE__ */ new Set();
2577
+ this.rulesTriggered = /* @__PURE__ */ new Set();
2578
+ this.tabsViewed = /* @__PURE__ */ new Set();
2579
+ this.dashboardOpened = false;
2580
+ this.explainUsed = false;
2581
+ this.firstRequestAt = 0;
2582
+ this.dashboardOpenedAt = 0;
2583
+ this.exitReason = "unknown";
2584
+ this.transport = transport;
2585
+ }
2586
+ // ── Setup phase ──
2587
+ init(framework, packageManager, isCustomCommand, adapters) {
2588
+ getOrCreateConfig();
2589
+ this.startTime = Date.now();
2590
+ this.framework = framework;
2591
+ this.packageManager = packageManager;
2592
+ this.isCustomCommand = isCustomCommand;
2593
+ this.adapters = adapters;
2594
+ }
2595
+ recordSetup(detection, durationMs) {
2596
+ this.detectedDependencies = detection.detectedDependencies;
2597
+ this.adaptersFailed = detection.adaptersFailed;
2598
+ this.configFilesDetected = detection.configFilesDetected;
2599
+ this.jsRuntime = detection.jsRuntime;
2600
+ this.setupDurationMs = durationMs;
2601
+ this.setupSucceeded = true;
2602
+ }
2603
+ // ── Runtime events ──
2604
+ recordFirstRequest(loadedPackages) {
2605
+ if (!this.firstRequestAt) this.firstRequestAt = Date.now();
2606
+ this.loadedPackages = loadedPackages;
2607
+ }
2608
+ recordPythonStack(info) {
2609
+ this.pythonConnected = true;
2610
+ this.pythonFramework = info.framework;
2611
+ this.pythonAdapters = info.adapters;
2612
+ this.pythonVersion = info.pythonVersion;
2613
+ }
2614
+ recordDashboardOpened() {
2615
+ if (this.dashboardOpened) return;
2616
+ this.dashboardOpened = true;
2617
+ this.dashboardOpenedAt = Date.now();
2618
+ this.transport.track(TELEMETRY_EVENT_DASHBOARD_VIEWED, {
2619
+ time_to_dashboard_ms: this.startTime > 0 ? Date.now() - this.startTime : null,
2620
+ request_count_at_open: this.requestCount
2621
+ });
2622
+ }
2623
+ recordTabViewed(tab) {
2624
+ this.tabsViewed.add(tab);
2625
+ }
2626
+ recordExplainUsed() {
2627
+ this.explainUsed = true;
2628
+ }
2629
+ recordExitReason(reason) {
2630
+ if (this.exitReason === "unknown") this.exitReason = reason;
2631
+ }
2632
+ // ── Pre-flush snapshot from services ──
2633
+ recordCounts(requestCount, insightTypes, rulesTriggered) {
2634
+ this.requestCount = requestCount;
2635
+ for (const t of insightTypes) this.insightTypes.add(t);
2636
+ for (const r of rulesTriggered) this.rulesTriggered.add(r);
2637
+ }
2638
+ // ── Serialization ──
2639
+ /** Build the full PostHog session payload. Single source of truth for all fields. */
2640
+ toPostHogPayload(services) {
2641
+ const metricsStore = services.metricsStore;
2642
+ const analysisEngine = services.analysisEngine;
2643
+ const live = metricsStore.getLiveEndpoints();
2644
+ const insights = analysisEngine.getInsights();
2645
+ const findings = analysisEngine.getFindings();
2646
+ let totalRequests = 0;
2647
+ let totalDuration = 0;
2648
+ let slowestP95 = 0;
2649
+ for (const ep of live) {
2650
+ totalRequests += ep.summary.totalRequests;
2651
+ totalDuration += ep.summary.p95Ms * ep.summary.totalRequests;
2652
+ if (ep.summary.p95Ms > slowestP95) slowestP95 = ep.summary.p95Ms;
2653
+ }
2654
+ const now = Date.now();
2655
+ return {
2656
+ sdk: TELEMETRY_SDK_NAME,
2657
+ // Stack detection
2658
+ framework: this.framework,
2659
+ package_manager: this.packageManager,
2660
+ js_runtime: this.jsRuntime,
2661
+ framework_detection_candidates: this.detectedDependencies,
2662
+ config_files_detected: this.configFilesDetected,
2663
+ loaded_packages: this.loadedPackages,
2664
+ loaded_package_count: this.loadedPackages.length,
2665
+ adapters_detected: this.adapters,
2666
+ adapters_failed: this.adaptersFailed,
2667
+ // Python SDK
2668
+ python_connected: this.pythonConnected,
2669
+ python_framework: this.pythonFramework,
2670
+ python_adapters: this.pythonAdapters,
2671
+ python_version: this.pythonVersion,
2672
+ // Session metadata
2673
+ is_custom_command: this.isCustomCommand,
2674
+ first_session: readConfig() === null,
2675
+ setup_succeeded: this.setupSucceeded,
2676
+ setup_duration_ms: this.setupDurationMs,
2677
+ session_duration_s: Math.ceil((now - this.startTime) / 1e3),
2678
+ session_duration_ms: now - this.startTime,
2679
+ exit_reason: this.exitReason,
2680
+ // Usage
2681
+ request_count: this.requestCount,
2682
+ error_count: services.errorStore.getAll().length,
2683
+ query_count: services.queryStore.getAll().length,
2684
+ fetch_count: services.fetchStore.getAll().length,
2685
+ endpoint_count: live.length,
2686
+ avg_duration_ms: totalRequests > 0 ? Math.round(totalDuration / totalRequests) : 0,
2687
+ slowest_endpoint_bucket: speedBucket(slowestP95),
2688
+ // Analysis
2689
+ insight_count: insights.length,
2690
+ finding_count: findings.length,
2691
+ insight_types: [...this.insightTypes],
2692
+ rules_triggered: [...this.rulesTriggered],
2693
+ // Dashboard engagement
2694
+ tabs_viewed: [...this.tabsViewed],
2695
+ dashboard_opened: this.dashboardOpened,
2696
+ explain_used: this.explainUsed,
2697
+ // Timing
2698
+ time_to_first_request_ms: this.firstRequestAt ? this.firstRequestAt - this.startTime : null,
2699
+ time_to_dashboard_ms: this.dashboardOpenedAt ? this.dashboardOpenedAt - this.startTime : null
2700
+ };
2701
+ }
2702
+ flush(services) {
2703
+ this.transport.send(TELEMETRY_EVENT_SESSION, this.toPostHogPayload(services));
2704
+ getOrCreateConfig();
2705
+ }
2706
+ };
2707
+ function speedBucket(ms) {
2708
+ if (ms === 0) return "none";
2709
+ const t = SPEED_BUCKET_THRESHOLDS;
2710
+ if (ms < t[0]) return `<${t[0]}ms`;
2711
+ for (let i = 1; i < t.length; i++) {
2712
+ if (ms < t[i]) return `${t[i - 1]}-${t[i]}ms`;
2713
+ }
2714
+ return `>${t[t.length - 1]}ms`;
2715
+ }
2716
+
2717
+ // src/telemetry/index.ts
2718
+ init_telemetry();
2719
+ var session = new Session();
2720
+
2451
2721
  // src/cli/commands/uninstall.ts
2452
- init_config();
2722
+ init_telemetry();
2453
2723
  var PREPENDED_FILES = [
2454
2724
  "app/entry.server.tsx",
2455
2725
  "app/entry.server.ts",
@@ -2708,7 +2978,7 @@ async function clearBuildCaches(rootDir) {
2708
2978
  }
2709
2979
 
2710
2980
  // bin/brakit.ts
2711
- init_config();
2981
+ init_telemetry();
2712
2982
  var sub = process.argv[2];
2713
2983
  var command = sub === "uninstall" ? "uninstall" : sub === "mcp" ? "mcp" : "install";
2714
2984
  var cwd = process.cwd();