Explorar o código

Installer now creates/updates CLAUDE.md with CodeGraph instructions

- Added claude-md-template.ts with the instructions template
- Installer writes to ~/.claude/CLAUDE.md (global) or ./.claude/CLAUDE.md (local)
- Smart detection: updates existing CodeGraph section or appends if not found
- Uses HTML comment markers for reliable section replacement on upgrades

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Colby McHenry hai 5 meses
pai
achega
8d1fb680e5
Modificáronse 4 ficheiros con 163 adicións e 4 borrados
  1. 1 1
      package.json
  2. 44 0
      src/installer/claude-md-template.ts
  3. 104 1
      src/installer/config-writer.ts
  4. 14 2
      src/installer/index.ts

+ 1 - 1
package.json

@@ -1,6 +1,6 @@
 {
 {
   "name": "@colbymchenry/codegraph",
   "name": "@colbymchenry/codegraph",
-  "version": "0.2.4",
+  "version": "0.2.5",
   "description": "A local-first code intelligence system that builds a semantic knowledge graph from any codebase",
   "description": "A local-first code intelligence system that builds a semantic knowledge graph from any codebase",
   "main": "dist/index.js",
   "main": "dist/index.js",
   "types": "dist/index.d.ts",
   "types": "dist/index.d.ts",

+ 44 - 0
src/installer/claude-md-template.ts

@@ -0,0 +1,44 @@
+/**
+ * CLAUDE.md template for CodeGraph instructions
+ *
+ * This template is injected into ~/.claude/CLAUDE.md (global) or ./.claude/CLAUDE.md (local)
+ * Keep this in sync with the README.md "Recommended: Add Global Instructions" section
+ */
+
+// Markers to identify CodeGraph section for updates
+export const CODEGRAPH_SECTION_START = '<!-- CODEGRAPH_START -->';
+export const CODEGRAPH_SECTION_END = '<!-- CODEGRAPH_END -->';
+
+export const CLAUDE_MD_TEMPLATE = `${CODEGRAPH_SECTION_START}
+## CodeGraph
+
+CodeGraph builds a semantic knowledge graph of codebases for faster, smarter code exploration.
+
+### If \`.codegraph/\` exists in the project
+
+**Use codegraph tools for faster exploration.** These tools provide instant lookups via the code graph instead of scanning files:
+
+| Tool | Use For |
+|------|---------|
+| \`codegraph_search\` | Find symbols by name (functions, classes, types) |
+| \`codegraph_context\` | Get relevant code context for a task |
+| \`codegraph_callers\` | Find what calls a function |
+| \`codegraph_callees\` | Find what a function calls |
+| \`codegraph_impact\` | See what's affected by changing a symbol |
+| \`codegraph_node\` | Get details + source code for a symbol |
+
+**When spawning Explore agents in a codegraph-enabled project:**
+
+Tell the Explore agent to use codegraph tools for faster exploration.
+
+**For quick lookups in the main session:**
+- Use \`codegraph_search\` instead of grep for finding symbols
+- Use \`codegraph_callers\`/\`codegraph_callees\` to trace code flow
+- Use \`codegraph_impact\` before making changes to see what's affected
+
+### If \`.codegraph/\` does NOT exist
+
+At the start of a session, ask the user if they'd like to initialize CodeGraph:
+
+"I notice this project doesn't have CodeGraph initialized. Would you like me to run \`codegraph init -i\` to build a code knowledge graph?"
+${CODEGRAPH_SECTION_END}`;

+ 104 - 1
src/installer/config-writer.ts

@@ -1,12 +1,17 @@
 /**
 /**
  * Config file writing for the CodeGraph installer
  * Config file writing for the CodeGraph installer
- * Writes to claude.json and settings.json
+ * Writes to claude.json, settings.json, and CLAUDE.md
  */
  */
 
 
 import * as fs from 'fs';
 import * as fs from 'fs';
 import * as path from 'path';
 import * as path from 'path';
 import * as os from 'os';
 import * as os from 'os';
 import { InstallLocation } from './prompts';
 import { InstallLocation } from './prompts';
+import {
+  CLAUDE_MD_TEMPLATE,
+  CODEGRAPH_SECTION_START,
+  CODEGRAPH_SECTION_END,
+} from './claude-md-template';
 
 
 /**
 /**
  * Get the path to the Claude config directory
  * Get the path to the Claude config directory
@@ -169,3 +174,101 @@ export function hasPermissions(location: InstallLocation): boolean {
   // Check if at least one CodeGraph permission exists
   // Check if at least one CodeGraph permission exists
   return permissions.some((p: string) => p.startsWith('mcp__codegraph__'));
   return permissions.some((p: string) => p.startsWith('mcp__codegraph__'));
 }
 }
+
+/**
+ * Get the path to CLAUDE.md
+ * - Global: ~/.claude/CLAUDE.md
+ * - Local: ./.claude/CLAUDE.md
+ */
+function getClaudeMdPath(location: InstallLocation): string {
+  const configDir = getClaudeConfigDir(location);
+  return path.join(configDir, 'CLAUDE.md');
+}
+
+/**
+ * Check if CLAUDE.md has CodeGraph section
+ */
+export function hasClaudeMdSection(location: InstallLocation): boolean {
+  const claudeMdPath = getClaudeMdPath(location);
+  try {
+    if (fs.existsSync(claudeMdPath)) {
+      const content = fs.readFileSync(claudeMdPath, 'utf-8');
+      return content.includes(CODEGRAPH_SECTION_START) || content.includes('## CodeGraph');
+    }
+  } catch {
+    // Ignore errors
+  }
+  return false;
+}
+
+/**
+ * Write or update CLAUDE.md with CodeGraph instructions
+ *
+ * If the file exists and has a CodeGraph section (marked or unmarked),
+ * it will be replaced. Otherwise, the template is appended.
+ */
+export function writeClaudeMd(location: InstallLocation): { created: boolean; updated: boolean } {
+  const claudeMdPath = getClaudeMdPath(location);
+  const configDir = getClaudeConfigDir(location);
+
+  // Ensure directory exists
+  if (!fs.existsSync(configDir)) {
+    fs.mkdirSync(configDir, { recursive: true });
+  }
+
+  // Check if file exists
+  if (!fs.existsSync(claudeMdPath)) {
+    // Create new file with just the CodeGraph section
+    fs.writeFileSync(claudeMdPath, CLAUDE_MD_TEMPLATE + '\n');
+    return { created: true, updated: false };
+  }
+
+  // Read existing content
+  let content = fs.readFileSync(claudeMdPath, 'utf-8');
+
+  // Check for marked section (from previous installer)
+  if (content.includes(CODEGRAPH_SECTION_START)) {
+    // Replace the marked section
+    const startIdx = content.indexOf(CODEGRAPH_SECTION_START);
+    const endIdx = content.indexOf(CODEGRAPH_SECTION_END);
+
+    if (endIdx > startIdx) {
+      // Replace existing marked section
+      const before = content.substring(0, startIdx);
+      const after = content.substring(endIdx + CODEGRAPH_SECTION_END.length);
+      content = before + CLAUDE_MD_TEMPLATE + after;
+      fs.writeFileSync(claudeMdPath, content);
+      return { created: false, updated: true };
+    }
+  }
+
+  // Check for unmarked "## CodeGraph" section (from manual setup)
+  const codegraphHeaderRegex = /\n## CodeGraph\n/;
+  const match = content.match(codegraphHeaderRegex);
+
+  if (match && match.index !== undefined) {
+    // Find the end of the CodeGraph section (next ## header or end of file)
+    const sectionStart = match.index;
+    const afterSection = content.substring(sectionStart + 1);
+    const nextHeaderMatch = afterSection.match(/\n## [^#]/);
+
+    let sectionEnd: number;
+    if (nextHeaderMatch && nextHeaderMatch.index !== undefined) {
+      sectionEnd = sectionStart + 1 + nextHeaderMatch.index;
+    } else {
+      sectionEnd = content.length;
+    }
+
+    // Replace the section
+    const before = content.substring(0, sectionStart);
+    const after = content.substring(sectionEnd);
+    content = before + '\n' + CLAUDE_MD_TEMPLATE + after;
+    fs.writeFileSync(claudeMdPath, content);
+    return { created: false, updated: true };
+  }
+
+  // No existing section, append to end
+  content = content.trimEnd() + '\n\n' + CLAUDE_MD_TEMPLATE + '\n';
+  fs.writeFileSync(claudeMdPath, content);
+  return { created: false, updated: false };
+}

+ 14 - 2
src/installer/index.ts

@@ -8,7 +8,7 @@
 import { execSync } from 'child_process';
 import { execSync } from 'child_process';
 import { showBanner, showNextSteps, success, error, info, chalk } from './banner';
 import { showBanner, showNextSteps, success, error, info, chalk } from './banner';
 import { promptInstallLocation, promptAutoAllow, InstallLocation } from './prompts';
 import { promptInstallLocation, promptAutoAllow, InstallLocation } from './prompts';
-import { writeMcpConfig, writePermissions, hasMcpConfig, hasPermissions } from './config-writer';
+import { writeMcpConfig, writePermissions, writeClaudeMd, hasMcpConfig, hasPermissions } from './config-writer';
 import CodeGraph from '../index';
 import CodeGraph from '../index';
 
 
 /**
 /**
@@ -66,7 +66,19 @@ export async function runInstaller(): Promise<void> {
       }
       }
     }
     }
 
 
-    // Step 5: For local install, initialize the project
+    // Step 5: Write CLAUDE.md instructions
+    const claudeMdResult = writeClaudeMd(location);
+    const claudeMdPath = location === 'global' ? '~/.claude/CLAUDE.md' : './.claude/CLAUDE.md';
+
+    if (claudeMdResult.created) {
+      success(`Created ${claudeMdPath} with CodeGraph instructions`);
+    } else if (claudeMdResult.updated) {
+      success(`Updated CodeGraph section in ${claudeMdPath}`);
+    } else {
+      success(`Added CodeGraph instructions to ${claudeMdPath}`);
+    }
+
+    // Step 6: For local install, initialize the project
     if (location === 'local') {
     if (location === 'local') {
       await initializeLocalProject();
       await initializeLocalProject();
     }
     }