فهرست منبع

fix: Add telemetry opt-out via installer prompt and env var

Sentry error reporting can now be disabled by:
1. Declining during the interactive installer (sets CODEGRAPH_TELEMETRY=off
   in the MCP server config env)
2. Setting CODEGRAPH_TELEMETRY=off in your shell environment

README updated with a Telemetry section documenting what is collected
and how to opt out.

Closes #68

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Colby McHenry 2 ماه پیش
والد
کامیت
5a185eb736
4فایلهای تغییر یافته به همراه61 افزوده شده و 17 حذف شده
  1. 26 5
      README.md
  2. 8 4
      src/installer/config-writer.ts
  3. 20 8
      src/installer/index.ts
  4. 7 0
      src/sentry.ts

+ 26 - 5
README.md

@@ -165,6 +165,7 @@ The interactive installer will:
 - Prompt to install `codegraph` globally (needed for hooks & MCP server to work)
 - Configure the MCP server in `~/.claude.json`
 - Set up auto-allow permissions for CodeGraph tools
+- Ask about [anonymous error reporting](#-telemetry) (opt-out available)
 - Add global instructions to `~/.claude/CLAUDE.md` (teaches Claude how to use CodeGraph)
 - Install Claude Code hooks for automatic index syncing
 - Optionally initialize your current project
@@ -309,11 +310,12 @@ npx @colbymchenry/codegraph       # Run via npx (no global install needed)
 The installer will:
 1. Prompt to install `codegraph` globally (needed for hooks & MCP server)
 2. Ask for installation location (global `~/.claude` or local `./.claude`)
-3. Configure the MCP server in `claude.json`
-4. Optionally set up auto-allow permissions
-5. Add global instructions to `~/.claude/CLAUDE.md` (teaches Claude how to use CodeGraph)
-6. Install Claude Code hooks for automatic index syncing
-7. For local installs: initialize and index the current project
+3. Optionally set up auto-allow permissions
+4. Ask about [anonymous error reporting](#-telemetry) (opt-out available)
+5. Configure the MCP server in `claude.json`
+6. Add global instructions to `~/.claude/CLAUDE.md` (teaches Claude how to use CodeGraph)
+7. Install Claude Code hooks for automatic index syncing
+8. For local installs: initialize and index the current project
 
 ### `codegraph init [path]`
 
@@ -709,6 +711,25 @@ Run `codegraph init` in your project directory first.
 - Check if the file's language is supported
 - Verify the file isn't excluded by config patterns
 
+## 📡 Telemetry
+
+CodeGraph collects anonymous error reports via [Sentry](https://sentry.io) to help diagnose and fix bugs. This is **enabled by default** in production environments (disabled in development/test).
+
+**What is collected:**
+- Error type, message, and stack trace (includes local file paths in the trace)
+- CodeGraph version and process name (CLI or MCP server)
+
+**What is NOT collected:**
+- Source code contents
+- File contents or repository data
+- Personal information or environment variables
+
+**To opt out**, set the environment variable before running CodeGraph:
+
+```bash
+export CODEGRAPH_TELEMETRY=off
+```
+
 ---
 
 ## 📄 License

+ 8 - 4
src/installer/config-writer.ts

@@ -100,18 +100,22 @@ function writeJsonFile(filePath: string, data: Record<string, any>): void {
 /**
  * Get the MCP server configuration
  */
-function getMcpServerConfig(): Record<string, any> {
-  return {
+function getMcpServerConfig(options?: { telemetry?: boolean }): Record<string, any> {
+  const config: Record<string, any> = {
     type: 'stdio',
     command: 'codegraph',
     args: ['serve', '--mcp'],
   };
+  if (options?.telemetry === false) {
+    config.env = { CODEGRAPH_TELEMETRY: 'off' };
+  }
+  return config;
 }
 
 /**
  * Write the MCP server configuration to claude.json
  */
-export function writeMcpConfig(location: InstallLocation): void {
+export function writeMcpConfig(location: InstallLocation, options?: { telemetry?: boolean }): void {
   const claudeJsonPath = getClaudeJsonPath(location);
   const config = readJsonFile(claudeJsonPath);
 
@@ -121,7 +125,7 @@ export function writeMcpConfig(location: InstallLocation): void {
   }
 
   // Add or update codegraph server
-  config.mcpServers.codegraph = getMcpServerConfig();
+  config.mcpServers.codegraph = getMcpServerConfig(options);
 
   writeJsonFile(claudeJsonPath, config);
 }

+ 20 - 8
src/installer/index.ts

@@ -51,9 +51,25 @@ export async function runInstaller(): Promise<void> {
     const location = await promptInstallLocation();
     console.log();
 
-    // Step 3: Write MCP configuration (always uses npx for reliability)
+    // Step 3: Ask about auto-allow permissions
+    const autoAllow = await promptAutoAllow();
+    console.log();
+
+    // Step 4: Ask about anonymous error reporting
+    console.log(chalk.bold('  Send anonymous error reports?') + chalk.dim(' (Helps fix bugs — no source code collected)'));
+    console.log();
+    const enableTelemetry = await promptConfirm('Enable anonymous error reporting', true);
+
+    if (!enableTelemetry) {
+      info('Telemetry disabled');
+    } else {
+      success('Anonymous error reporting enabled');
+    }
+    console.log();
+
+    // Step 5: Write MCP configuration (includes telemetry env if opted out)
     const alreadyHasMcp = hasMcpConfig(location);
-    writeMcpConfig(location);
+    writeMcpConfig(location, { telemetry: enableTelemetry });
 
     if (alreadyHasMcp) {
       success(`Updated MCP server in ${location === 'global' ? '~/.claude.json' : './.claude.json'}`);
@@ -61,10 +77,6 @@ export async function runInstaller(): Promise<void> {
       success(`Added MCP server to ${location === 'global' ? '~/.claude.json' : './.claude.json'}`);
     }
 
-    // Step 4: Ask about auto-allow permissions
-    const autoAllow = await promptAutoAllow();
-    console.log();
-
     if (autoAllow) {
       const alreadyHasPerms = hasPermissions(location);
       writePermissions(location);
@@ -76,7 +88,7 @@ export async function runInstaller(): Promise<void> {
       }
     }
 
-    // Step 5: Write auto-sync hooks
+    // Step 6: Write auto-sync hooks
     const alreadyHasHooks = hasHooks(location);
     writeHooks(location);
 
@@ -86,7 +98,7 @@ export async function runInstaller(): Promise<void> {
       success(`Added auto-sync hooks to ${location === 'global' ? '~/.claude/settings.json' : './.claude/settings.json'}`);
     }
 
-    // Step 6: Write CLAUDE.md instructions
+    // Step 7: Write CLAUDE.md instructions
     const claudeMdResult = writeClaudeMd(location);
     const claudeMdPath = location === 'global' ? '~/.claude/CLAUDE.md' : './.claude/CLAUDE.md';
 

+ 7 - 0
src/sentry.ts

@@ -19,12 +19,19 @@ let _tags: Record<string, string> = {};
 /**
  * Initialize Sentry error reporting.
  * Safe to call multiple times — subsequent calls update tags/release.
+ *
+ * Opt out by setting the environment variable CODEGRAPH_TELEMETRY=off
  */
 export function initSentry({ processName, version }: { processName: string; version?: string }) {
   // Skip in development/test environments
   if (process.env.NODE_ENV === 'development' || process.env.NODE_ENV === 'test' || process.env.VITEST) {
     return;
   }
+  // Respect user opt-out
+  const telemetry = process.env.CODEGRAPH_TELEMETRY?.toLowerCase();
+  if (telemetry === 'off' || telemetry === '0' || telemetry === 'false') {
+    return;
+  }
   _enabled = true;
   _release = `codegraph@${version ?? process.env.npm_package_version ?? 'unknown'}`;
   _tags = { processName };