brakit 0.9.0 → 0.9.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/api.d.ts CHANGED
@@ -348,10 +348,12 @@ declare function detectProject(rootDir: string): Promise<DetectedProject>;
348
348
  declare class AdapterRegistry {
349
349
  private adapters;
350
350
  private active;
351
+ private failed;
351
352
  register(adapter: BrakitAdapter): void;
352
353
  patchAll(emit: (event: TelemetryEvent) => void): void;
353
354
  unpatchAll(): void;
354
355
  getActive(): readonly BrakitAdapter[];
356
+ getFailed(): readonly string[];
355
357
  }
356
358
 
357
359
  interface AnalysisUpdate {
package/dist/api.js CHANGED
@@ -54,6 +54,7 @@ var BASELINE_MIN_SESSIONS = 2;
54
54
  var BASELINE_MIN_REQUESTS_PER_SESSION = 3;
55
55
  var ISSUES_FILE = "issues.json";
56
56
  var ISSUES_FLUSH_INTERVAL_MS = 1e4;
57
+ var DETAIL_PREVIEW_LENGTH = 120;
57
58
 
58
59
  // src/utils/log.ts
59
60
  var PREFIX = "[brakit]";
@@ -429,6 +430,7 @@ var AdapterRegistry = class {
429
430
  constructor() {
430
431
  this.adapters = [];
431
432
  this.active = [];
433
+ this.failed = [];
432
434
  }
433
435
  register(adapter) {
434
436
  this.adapters.push(adapter);
@@ -441,6 +443,7 @@ var AdapterRegistry = class {
441
443
  this.active.push(adapter);
442
444
  }
443
445
  } catch {
446
+ this.failed.push(adapter.name);
444
447
  }
445
448
  }
446
449
  }
@@ -456,6 +459,9 @@ var AdapterRegistry = class {
456
459
  getActive() {
457
460
  return this.active;
458
461
  }
462
+ getFailed() {
463
+ return this.failed;
464
+ }
459
465
  };
460
466
 
461
467
  // src/utils/response.ts
@@ -774,7 +780,7 @@ var stackTraceLeakRule = {
774
780
  title: "Stack Trace Leaked to Client",
775
781
  desc: `${ep} \u2014 response exposes internal stack trace`,
776
782
  hint: this.hint,
777
- detail: firstLine ? `Stack trace: ${firstLine.slice(0, 120)}` : void 0,
783
+ detail: firstLine ? `Stack trace: ${firstLine.slice(0, DETAIL_PREVIEW_LENGTH)}` : void 0,
778
784
  endpoint: ep,
779
785
  count: 1
780
786
  }
@@ -1664,7 +1670,7 @@ var n1Rule = {
1664
1670
  title: "N+1 Query Pattern",
1665
1671
  desc: `${endpoint} runs ${shapeGroup.count}x ${info.op} ${info.table} with different params in a single request`,
1666
1672
  hint: "This typically happens when fetching related data in a loop. Use a batch query, JOIN, or include/eager-load to fetch all records at once.",
1667
- detail: `${shapeGroup.count} queries with ${shapeGroup.distinctSql.size} distinct param variations. Example: ${[...shapeGroup.distinctSql][0]?.slice(0, 100) ?? info.op + " " + info.table}`
1673
+ detail: `${shapeGroup.count} queries with ${shapeGroup.distinctSql.size} distinct param variations. Example: ${[...shapeGroup.distinctSql][0]?.slice(0, DETAIL_PREVIEW_LENGTH) ?? info.op + " " + info.table}`
1668
1674
  });
1669
1675
  }
1670
1676
  }
@@ -1703,7 +1709,7 @@ var redundantQueryRule = {
1703
1709
  title: "Redundant Query",
1704
1710
  desc: `${label} runs ${entry.count}x with identical params in ${endpoint}.`,
1705
1711
  hint: "The exact same query with identical parameters runs multiple times in one request. Cache the first result or lift the query to a shared function.",
1706
- detail: entry.first.sql ? `Query: ${entry.first.sql.slice(0, 120)}` : void 0
1712
+ detail: entry.first.sql ? `Query: ${entry.first.sql.slice(0, DETAIL_PREVIEW_LENGTH)}` : void 0
1707
1713
  });
1708
1714
  }
1709
1715
  }
@@ -2235,7 +2241,7 @@ var AnalysisEngine = class {
2235
2241
  };
2236
2242
 
2237
2243
  // src/index.ts
2238
- var VERSION = "0.9.0";
2244
+ var VERSION = "0.9.1";
2239
2245
  export {
2240
2246
  AdapterRegistry,
2241
2247
  AnalysisEngine,
@@ -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;
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;
14
14
  var init_config = __esm({
15
15
  "src/constants/config.ts"() {
16
16
  "use strict";
@@ -29,6 +29,9 @@ 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
+ DETAIL_PREVIEW_LENGTH = 120;
32
35
  }
33
36
  });
34
37
 
@@ -70,7 +73,7 @@ var init_type_guards = __esm({
70
73
  });
71
74
 
72
75
  // src/constants/labels.ts
73
- 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, VALID_TABS_TUPLE, VALID_TABS;
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, VALID_TABS_TUPLE, VALID_TABS, POSTHOG_HOST, POSTHOG_CAPTURE_PATH, POSTHOG_REQUEST_TIMEOUT_MS;
74
77
  var init_labels = __esm({
75
78
  "src/constants/labels.ts"() {
76
79
  "use strict";
@@ -104,11 +107,14 @@ var init_labels = __esm({
104
107
  "security"
105
108
  ];
106
109
  VALID_TABS = new Set(VALID_TABS_TUPLE);
110
+ POSTHOG_HOST = "https://us.i.posthog.com";
111
+ POSTHOG_CAPTURE_PATH = "/i/v0/e/";
112
+ POSTHOG_REQUEST_TIMEOUT_MS = 3e3;
107
113
  }
108
114
  });
109
115
 
110
116
  // src/constants/features.ts
111
- var SUPPORTED_SOURCE_EXTENSIONS, BUILD_CACHE_DIRS, FALLBACK_SCAN_DIRS, MCP_SERVER_NAME, INITIAL_DISCOVERY_TIMEOUT_MS, LAZY_DISCOVERY_TIMEOUT_MS, CLIENT_FETCH_TIMEOUT_MS, HEALTH_CHECK_TIMEOUT_MS, DISCOVERY_POLL_INTERVAL_MS, MAX_DISCOVERY_DEPTH, MAX_TIMELINE_EVENTS, MAX_RESOLVED_DISPLAY, ENRICHMENT_SEVERITY_FILTER, MCP_SERVER_VERSION, RECOVERY_WINDOW_MS, PORT_MIN, PORT_MAX;
117
+ var SUPPORTED_SOURCE_EXTENSIONS, BUILD_CACHE_DIRS, FALLBACK_SCAN_DIRS, MCP_SERVER_NAME, INITIAL_DISCOVERY_TIMEOUT_MS, LAZY_DISCOVERY_TIMEOUT_MS, CLIENT_FETCH_TIMEOUT_MS, HEALTH_CHECK_TIMEOUT_MS, DISCOVERY_POLL_INTERVAL_MS, MAX_DISCOVERY_DEPTH, MAX_TIMELINE_EVENTS, MAX_RESOLVED_DISPLAY, ENRICHMENT_SEVERITY_FILTER, MCP_SERVER_VERSION, RECOVERY_WINDOW_MS, PORT_MIN, PORT_MAX, DIR_MODE_OWNER_ONLY, FILE_MODE_OWNER_ONLY;
112
118
  var init_features = __esm({
113
119
  "src/constants/features.ts"() {
114
120
  "use strict";
@@ -132,10 +138,12 @@ var init_features = __esm({
132
138
  MAX_TIMELINE_EVENTS = 20;
133
139
  MAX_RESOLVED_DISPLAY = 5;
134
140
  ENRICHMENT_SEVERITY_FILTER = ["critical", "warning"];
135
- MCP_SERVER_VERSION = "0.9.0";
141
+ MCP_SERVER_VERSION = "0.9.1";
136
142
  RECOVERY_WINDOW_MS = 5 * 60 * 1e3;
137
143
  PORT_MIN = 1;
138
144
  PORT_MAX = 65535;
145
+ DIR_MODE_OWNER_ONLY = 448;
146
+ FILE_MODE_OWNER_ONLY = 384;
139
147
  }
140
148
  });
141
149
 
@@ -307,8 +315,8 @@ async function searchForPort(startDir) {
307
315
  }
308
316
  return null;
309
317
  }
310
- async function discoverBrakitPort(cwd) {
311
- const port = await searchForPort(cwd ?? process.cwd());
318
+ async function discoverBrakitPort(cwd2) {
319
+ const port = await searchForPort(cwd2 ?? process.cwd());
312
320
  if (!port) {
313
321
  throw new Error(
314
322
  "Brakit is not running. Start your app with brakit enabled first."
@@ -316,11 +324,11 @@ async function discoverBrakitPort(cwd) {
316
324
  }
317
325
  return { port, baseUrl: `http://localhost:${port}` };
318
326
  }
319
- async function waitForBrakit(cwd, timeoutMs = 1e4, pollMs = DISCOVERY_POLL_INTERVAL_MS) {
327
+ async function waitForBrakit(cwd2, timeoutMs = 1e4, pollMs = DISCOVERY_POLL_INTERVAL_MS) {
320
328
  const deadline = Date.now() + timeoutMs;
321
329
  while (Date.now() < deadline) {
322
330
  try {
323
- const result = await discoverBrakitPort(cwd);
331
+ const result = await discoverBrakitPort(cwd2);
324
332
  const res = await fetch(`${result.baseUrl}${DASHBOARD_API_REQUESTS}?limit=1`);
325
333
  if (res.ok) return result;
326
334
  } catch {
@@ -1047,6 +1055,8 @@ var init_server = __esm({
1047
1055
 
1048
1056
  // bin/brakit.ts
1049
1057
  import { runMain } from "citty";
1058
+ import { existsSync as existsSync7 } from "fs";
1059
+ import { resolve as resolve6 } from "path";
1050
1060
 
1051
1061
  // src/cli/commands/install.ts
1052
1062
  import { defineCommand } from "citty";
@@ -1563,7 +1573,7 @@ var stackTraceLeakRule = {
1563
1573
  title: "Stack Trace Leaked to Client",
1564
1574
  desc: `${ep} \u2014 response exposes internal stack trace`,
1565
1575
  hint: this.hint,
1566
- detail: firstLine ? `Stack trace: ${firstLine.slice(0, 120)}` : void 0,
1576
+ detail: firstLine ? `Stack trace: ${firstLine.slice(0, DETAIL_PREVIEW_LENGTH)}` : void 0,
1567
1577
  endpoint: ep,
1568
1578
  count: 1
1569
1579
  }
@@ -1802,7 +1812,7 @@ init_constants();
1802
1812
  init_endpoint();
1803
1813
 
1804
1814
  // src/index.ts
1805
- var VERSION = "0.9.0";
1815
+ var VERSION = "0.9.1";
1806
1816
 
1807
1817
  // src/cli/commands/install.ts
1808
1818
  init_constants();
@@ -2014,8 +2024,8 @@ async function setupNuxt(rootDir) {
2014
2024
  }
2015
2025
  const content = BRAKIT_TEMPLATES.nuxt + "\n";
2016
2026
  const dir = join3(rootDir, "server/plugins");
2017
- const { mkdirSync: mkdirSync3 } = await import("fs");
2018
- mkdirSync3(dir, { recursive: true });
2027
+ const { mkdirSync: mkdirSync4 } = await import("fs");
2028
+ mkdirSync4(dir, { recursive: true });
2019
2029
  await writeFile3(absPath, content);
2020
2030
  return { action: "created", file: relPath, content };
2021
2031
  }
@@ -2114,13 +2124,118 @@ function printManualInstructions(framework) {
2114
2124
 
2115
2125
  // src/cli/commands/uninstall.ts
2116
2126
  import { defineCommand as defineCommand2 } from "citty";
2117
- import { resolve as resolve4, join as join4, relative as relative2 } from "path";
2127
+ import { resolve as resolve4, join as join5, relative as relative2 } from "path";
2118
2128
  import { readFile as readFile5, writeFile as writeFile4, unlink, rm, readdir as readdir2 } from "fs/promises";
2119
2129
  import { execSync as execSync2 } from "child_process";
2120
2130
  import pc2 from "picocolors";
2121
2131
  init_constants();
2122
2132
  init_log();
2123
2133
  init_type_guards();
2134
+
2135
+ // src/telemetry/index.ts
2136
+ import { platform as platform2, release, arch } from "os";
2137
+ import { spawn } from "child_process";
2138
+
2139
+ // src/telemetry/config.ts
2140
+ init_features();
2141
+ import { homedir as homedir2, platform } from "os";
2142
+ import { join as join4 } from "path";
2143
+ import { existsSync as existsSync6, readFileSync as readFileSync3, writeFileSync as writeFileSync3, mkdirSync as mkdirSync3 } from "fs";
2144
+ import { randomUUID as randomUUID2 } from "crypto";
2145
+ var IS_WINDOWS = platform() === "win32";
2146
+ var CONFIG_DIR = join4(homedir2(), ".brakit");
2147
+ var CONFIG_PATH = join4(CONFIG_DIR, "config.json");
2148
+ function readConfig() {
2149
+ try {
2150
+ if (!existsSync6(CONFIG_PATH)) return null;
2151
+ return JSON.parse(readFileSync3(CONFIG_PATH, "utf-8"));
2152
+ } catch {
2153
+ return null;
2154
+ }
2155
+ }
2156
+ function writeConfig(config) {
2157
+ try {
2158
+ if (!existsSync6(CONFIG_DIR))
2159
+ mkdirSync3(CONFIG_DIR, { recursive: true, ...IS_WINDOWS ? {} : { mode: DIR_MODE_OWNER_ONLY } });
2160
+ writeFileSync3(
2161
+ CONFIG_PATH,
2162
+ JSON.stringify(config, null, 2) + "\n",
2163
+ IS_WINDOWS ? {} : { mode: FILE_MODE_OWNER_ONLY }
2164
+ );
2165
+ } catch (err) {
2166
+ if (process.env.BRAKIT_DEBUG) {
2167
+ process.stderr.write(`[brakit] config write failed: ${err?.message ?? err}
2168
+ `);
2169
+ }
2170
+ }
2171
+ }
2172
+ function getOrCreateConfig() {
2173
+ const existing = readConfig();
2174
+ if (existing && typeof existing.telemetry === "boolean" && existing.anonymousId) {
2175
+ return existing;
2176
+ }
2177
+ const config = { telemetry: true, anonymousId: randomUUID2() };
2178
+ writeConfig(config);
2179
+ return config;
2180
+ }
2181
+ var cachedEnabled = null;
2182
+ function isTelemetryEnabled() {
2183
+ if (cachedEnabled !== null) return cachedEnabled;
2184
+ const env = process.env.BRAKIT_TELEMETRY;
2185
+ if (env !== void 0) {
2186
+ cachedEnabled = env !== "false" && env !== "0" && env !== "off";
2187
+ return cachedEnabled;
2188
+ }
2189
+ cachedEnabled = readConfig()?.telemetry ?? true;
2190
+ return cachedEnabled;
2191
+ }
2192
+
2193
+ // src/telemetry/index.ts
2194
+ init_labels();
2195
+ init_config();
2196
+ var POSTHOG_KEY = "phc_E9TwydCGnSfPLIUhNxChpeg32TSowjk31KiPhnLPP0x";
2197
+ function commonProperties() {
2198
+ return {
2199
+ brakit_version: VERSION,
2200
+ node_version: process.version,
2201
+ os: `${platform2()}-${release()}`,
2202
+ arch: arch(),
2203
+ $lib: "brakit",
2204
+ $process_person_profile: false,
2205
+ $geoip_disable: true
2206
+ };
2207
+ }
2208
+ function sendToPosthog(event, properties) {
2209
+ if (!isTelemetryEnabled()) return;
2210
+ const config = getOrCreateConfig();
2211
+ const payload = {
2212
+ api_key: POSTHOG_KEY,
2213
+ event,
2214
+ distinct_id: config.anonymousId,
2215
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
2216
+ properties: { ...commonProperties(), ...properties }
2217
+ };
2218
+ try {
2219
+ const body = JSON.stringify(payload);
2220
+ const url = `${POSTHOG_HOST}${POSTHOG_CAPTURE_PATH}`;
2221
+ const child = spawn(
2222
+ process.execPath,
2223
+ [
2224
+ "-e",
2225
+ `fetch(${JSON.stringify(url)},{method:"POST",headers:{"content-type":"application/json"},body:${JSON.stringify(body)},signal:AbortSignal.timeout(${POSTHOG_REQUEST_TIMEOUT_MS})}).catch(()=>{})`
2226
+ ],
2227
+ { detached: true, stdio: "ignore" }
2228
+ );
2229
+ child.unref();
2230
+ } catch {
2231
+ }
2232
+ }
2233
+ function trackEvent(event, properties) {
2234
+ sendToPosthog(event, { sdk: "node", ...properties });
2235
+ }
2236
+
2237
+ // src/cli/commands/uninstall.ts
2238
+ init_config();
2124
2239
  var PREPENDED_FILES = [
2125
2240
  "app/entry.server.tsx",
2126
2241
  "app/entry.server.ts",
@@ -2155,16 +2270,20 @@ var uninstall_default = defineCommand2({
2155
2270
  console.log();
2156
2271
  console.log(pc2.bold(" \u25C6 brakit uninstall"));
2157
2272
  console.log();
2273
+ let anyInstrumentationRemoved = false;
2274
+ let anyPackageRemoved = false;
2158
2275
  for (const project of projects) {
2159
2276
  const suffix = projects.length > 1 ? ` in ${relative2(rootDir, project.dir) || "."}` : "";
2160
2277
  const removed = await removeInstrumentation(project.dir);
2161
2278
  if (removed) {
2279
+ anyInstrumentationRemoved = true;
2162
2280
  console.log(pc2.green(` \u2713 ${removed}${suffix}`));
2163
2281
  } else {
2164
2282
  console.log(pc2.dim(` No brakit instrumentation files found${suffix}.`));
2165
2283
  }
2166
2284
  const uninstalled = await uninstallPackage(project.dir, project.pm);
2167
2285
  if (uninstalled === true) {
2286
+ anyPackageRemoved = true;
2168
2287
  console.log(pc2.green(` \u2713 Removed brakit from devDependencies${suffix}`));
2169
2288
  } else if (uninstalled === "failed") {
2170
2289
  }
@@ -2185,6 +2304,12 @@ var uninstall_default = defineCommand2({
2185
2304
  if (cacheCleared) {
2186
2305
  console.log(pc2.green(" \u2713 Cleared build cache"));
2187
2306
  }
2307
+ trackEvent(TELEMETRY_EVENT_CLI_UNINSTALL, {
2308
+ instrumentation_removed: anyInstrumentationRemoved,
2309
+ package_removed: anyPackageRemoved,
2310
+ mcp_removed: mcpRemoved,
2311
+ data_removed: dataRemoved
2312
+ });
2188
2313
  console.log();
2189
2314
  }
2190
2315
  });
@@ -2195,7 +2320,7 @@ async function removeInstrumentation(projectDir) {
2195
2320
  }
2196
2321
  const candidates = [...PREPENDED_FILES];
2197
2322
  try {
2198
- const pkgRaw = await readFile5(join4(projectDir, "package.json"), "utf-8");
2323
+ const pkgRaw = await readFile5(join5(projectDir, "package.json"), "utf-8");
2199
2324
  const pkg = JSON.parse(pkgRaw);
2200
2325
  if (pkg.main) candidates.unshift(pkg.main);
2201
2326
  } catch (err) {
@@ -2210,7 +2335,7 @@ async function removeInstrumentation(projectDir) {
2210
2335
  return null;
2211
2336
  }
2212
2337
  async function tryRemoveBrakitFromFile(projectDir, relPath) {
2213
- const absPath = join4(projectDir, relPath);
2338
+ const absPath = join5(projectDir, relPath);
2214
2339
  if (!await fileExists(absPath)) return null;
2215
2340
  const content = await readFile5(absPath, "utf-8");
2216
2341
  if (!content.includes("brakit")) return null;
@@ -2227,7 +2352,7 @@ async function tryRemoveBrakitFromFile(projectDir, relPath) {
2227
2352
  return null;
2228
2353
  }
2229
2354
  async function tryRemoveImportLine(projectDir, relPath) {
2230
- const absPath = join4(projectDir, relPath);
2355
+ const absPath = join5(projectDir, relPath);
2231
2356
  if (!await fileExists(absPath)) return null;
2232
2357
  const content = await readFile5(absPath, "utf-8");
2233
2358
  if (!content.includes(IMPORT_LINE)) return null;
@@ -2238,7 +2363,7 @@ async function tryRemoveImportLine(projectDir, relPath) {
2238
2363
  async function fallbackSearchAndRemove(projectDir) {
2239
2364
  const dirsToScan = FALLBACK_SCAN_DIRS;
2240
2365
  for (const dir of dirsToScan) {
2241
- const absDir = join4(projectDir, dir);
2366
+ const absDir = join5(projectDir, dir);
2242
2367
  if (!await fileExists(absDir)) continue;
2243
2368
  let entries;
2244
2369
  try {
@@ -2251,7 +2376,7 @@ async function fallbackSearchAndRemove(projectDir) {
2251
2376
  const ext = entry.slice(entry.lastIndexOf("."));
2252
2377
  if (!SUPPORTED_SOURCE_EXTENSIONS.has(ext)) continue;
2253
2378
  const relPath = dir === "." ? entry : `${dir}/${entry}`;
2254
- const absPath = join4(projectDir, relPath);
2379
+ const absPath = join5(projectDir, relPath);
2255
2380
  try {
2256
2381
  const content = await readFile5(absPath, "utf-8");
2257
2382
  if (!containsBrakitImport(content)) continue;
@@ -2274,7 +2399,7 @@ async function fallbackSearchAndRemove(projectDir) {
2274
2399
  return null;
2275
2400
  }
2276
2401
  async function removeMcpConfig(rootDir) {
2277
- const mcpPath = join4(rootDir, ".mcp.json");
2402
+ const mcpPath = join5(rootDir, ".mcp.json");
2278
2403
  if (!await fileExists(mcpPath)) return false;
2279
2404
  try {
2280
2405
  const raw = await readFile5(mcpPath, "utf-8");
@@ -2294,7 +2419,7 @@ async function removeMcpConfig(rootDir) {
2294
2419
  }
2295
2420
  async function uninstallPackage(rootDir, pm) {
2296
2421
  try {
2297
- const pkgRaw = await readFile5(join4(rootDir, "package.json"), "utf-8");
2422
+ const pkgRaw = await readFile5(join5(rootDir, "package.json"), "utf-8");
2298
2423
  const pkg = JSON.parse(pkgRaw);
2299
2424
  if (!pkg.devDependencies?.brakit && !pkg.dependencies?.brakit) return false;
2300
2425
  } catch (err) {
@@ -2318,7 +2443,7 @@ async function uninstallPackage(rootDir, pm) {
2318
2443
  }
2319
2444
  async function removeBrakitData(rootDir) {
2320
2445
  let removed = false;
2321
- const projectDir = join4(rootDir, METRICS_DIR);
2446
+ const projectDir = join5(rootDir, METRICS_DIR);
2322
2447
  if (await fileExists(projectDir)) {
2323
2448
  try {
2324
2449
  await rm(projectDir, { recursive: true, force: true });
@@ -2339,7 +2464,7 @@ async function removeBrakitData(rootDir) {
2339
2464
  return removed;
2340
2465
  }
2341
2466
  async function cleanGitignore(rootDir) {
2342
- const gitignorePath = join4(rootDir, ".gitignore");
2467
+ const gitignorePath = join5(rootDir, ".gitignore");
2343
2468
  if (!await fileExists(gitignorePath)) return false;
2344
2469
  try {
2345
2470
  const content = await readFile5(gitignorePath, "utf-8");
@@ -2356,7 +2481,7 @@ async function cleanGitignore(rootDir) {
2356
2481
  async function clearBuildCaches(rootDir) {
2357
2482
  let cleared = false;
2358
2483
  for (const dir of BUILD_CACHE_DIRS) {
2359
- const absDir = join4(rootDir, dir);
2484
+ const absDir = join5(rootDir, dir);
2360
2485
  if (!await fileExists(absDir)) continue;
2361
2486
  try {
2362
2487
  await rm(absDir, { recursive: true, force: true });
@@ -2369,7 +2494,15 @@ async function clearBuildCaches(rootDir) {
2369
2494
  }
2370
2495
 
2371
2496
  // bin/brakit.ts
2497
+ init_config();
2372
2498
  var sub = process.argv[2];
2499
+ var command = sub === "uninstall" ? "uninstall" : sub === "mcp" ? "mcp" : "install";
2500
+ var cwd = process.cwd();
2501
+ trackEvent(TELEMETRY_EVENT_CLI_INVOKED, {
2502
+ command,
2503
+ has_package_json: existsSync7(resolve6(cwd, "package.json")),
2504
+ cwd_has_node_modules: existsSync7(resolve6(cwd, "node_modules"))
2505
+ });
2373
2506
  if (sub === "uninstall") {
2374
2507
  process.argv.splice(2, 1);
2375
2508
  runMain(uninstall_default);