diff --git a/package.json b/package.json index 771f071..52ac6f7 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "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", "main": "dist/index.js", "types": "dist/index.d.ts", diff --git a/src/installer/claude-md-template.ts b/src/installer/claude-md-template.ts new file mode 100644 index 0000000..6b73c03 --- /dev/null +++ b/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 = ''; +export const CODEGRAPH_SECTION_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}`; diff --git a/src/installer/config-writer.ts b/src/installer/config-writer.ts index 0506239..f33f325 100644 --- a/src/installer/config-writer.ts +++ b/src/installer/config-writer.ts @@ -1,12 +1,17 @@ /** * 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 path from 'path'; import * as os from 'os'; 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 @@ -169,3 +174,101 @@ export function hasPermissions(location: InstallLocation): boolean { // Check if at least one CodeGraph permission exists 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 }; +} diff --git a/src/installer/index.ts b/src/installer/index.ts index c70edc5..6965075 100644 --- a/src/installer/index.ts +++ b/src/installer/index.ts @@ -8,7 +8,7 @@ import { execSync } from 'child_process'; import { showBanner, showNextSteps, success, error, info, chalk } from './banner'; 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'; /** @@ -66,7 +66,19 @@ export async function runInstaller(): Promise { } } - // 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') { await initializeLocalProject(); }