diff --git a/src/bin/codegraph.ts b/src/bin/codegraph.ts index 75a78dd..810144d 100644 --- a/src/bin/codegraph.ts +++ b/src/bin/codegraph.ts @@ -1015,17 +1015,17 @@ program process.exit(0); } - // Spawn `codegraph sync` as a detached background process - // so this hook exits immediately and doesn't block Claude Code - const isWindows = process.platform === 'win32'; + // Spawn sync as a detached background process + // so this hook exits immediately and doesn't block Claude Code. + // Uses process.argv[0]/[1] (e.g. node /path/to/codegraph.js) so it + // works whether invoked via global install, npx, or directly. const child = spawn( - isWindows ? 'codegraph' : process.argv[0]!, - isWindows ? ['sync', '--quiet', projectRoot!] : [process.argv[1]!, 'sync', '--quiet', projectRoot!], + process.argv[0]!, + [process.argv[1]!, 'sync', '--quiet', projectRoot!], { detached: true, stdio: 'ignore', windowsHide: true, - shell: isWindows, } ); child.unref(); diff --git a/src/installer/banner.ts b/src/installer/banner.ts index 1f3f811..b0d6d8f 100644 --- a/src/installer/banner.ts +++ b/src/installer/banner.ts @@ -113,16 +113,18 @@ export function warn(message: string): void { /** * Show the "next steps" section after installation */ -export function showNextSteps(location: 'global' | 'local', useNpx?: boolean): void { +export function showNextSteps(location: 'global' | 'local'): void { console.log(); console.log(chalk.bold(' Done!') + ' Restart Claude Code to use CodeGraph.'); console.log(); if (location === 'global') { - const cmd = useNpx ? 'npx @colbymchenry/codegraph' : 'codegraph'; console.log(chalk.dim(' Quick start:')); console.log(chalk.dim(' cd your-project')); - console.log(chalk.cyan(` ${cmd} init -i`)); + console.log(chalk.cyan(' npx @colbymchenry/codegraph init -i')); + console.log(); + console.log(chalk.dim(' Tip: For a shorter command, install globally:')); + console.log(chalk.dim(' npm install -g @colbymchenry/codegraph')); } else { console.log(chalk.dim(' CodeGraph is ready to use in this project!')); } diff --git a/src/installer/config-writer.ts b/src/installer/config-writer.ts index d37edd1..edb2465 100644 --- a/src/installer/config-writer.ts +++ b/src/installer/config-writer.ts @@ -98,28 +98,9 @@ function writeJsonFile(filePath: string, data: Record): void { } /** - * When true, all configs use `npx @colbymchenry/codegraph` instead of the - * bare `codegraph` command. Set by the installer when global install fails. + * Get the MCP server configuration — always uses npx for reliability */ -let useNpxFallback = false; - -export function setUseNpxFallback(value: boolean): void { - useNpxFallback = value; -} - -/** - * Get the MCP server configuration for the given location - */ -function getMcpServerConfig(location: InstallLocation): Record { - if (location === 'global' && !useNpxFallback) { - // Global: use 'codegraph' command directly (globally installed and in PATH) - return { - type: 'stdio', - command: 'codegraph', - args: ['serve', '--mcp'], - }; - } - // Local or npx fallback: use npx to run the package +function getMcpServerConfig(): Record { return { type: 'stdio', command: 'npx', @@ -140,7 +121,7 @@ export function writeMcpConfig(location: InstallLocation): void { } // Add or update codegraph server - config.mcpServers.codegraph = getMcpServerConfig(location); + config.mcpServers.codegraph = getMcpServerConfig(); writeJsonFile(claudeJsonPath, config); } @@ -221,8 +202,8 @@ export function hasPermissions(location: InstallLocation): boolean { * PostToolUse(Edit|Write) → mark-dirty (async, non-blocking) * Stop → sync-if-dirty (sync, ensures fresh index before next user turn) */ -function getHooksConfig(location: InstallLocation): Record { - const command = (location === 'global' && !useNpxFallback) ? 'codegraph' : 'npx @colbymchenry/codegraph'; +function getHooksConfig(): Record { + const command = 'npx @colbymchenry/codegraph'; return { PostToolUse: [ @@ -277,7 +258,7 @@ export function writeHooks(location: InstallLocation): void { settings.hooks = {}; } - const newHooks = getHooksConfig(location); + const newHooks = getHooksConfig(); // For each hook event (PostToolUse, Stop), merge with existing entries for (const [event, newEntries] of Object.entries(newHooks)) { diff --git a/src/installer/index.ts b/src/installer/index.ts index 1cc6f9d..cb8781d 100644 --- a/src/installer/index.ts +++ b/src/installer/index.ts @@ -5,10 +5,9 @@ * with Claude Code. */ -import { execSync } from 'child_process'; import { showBanner, showNextSteps, success, error, info, chalk } from './banner'; import { promptInstallLocation, promptAutoAllow, InstallLocation } from './prompts'; -import { writeMcpConfig, writePermissions, writeClaudeMd, writeHooks, hasMcpConfig, hasPermissions, hasHooks, setUseNpxFallback } from './config-writer'; +import { writeMcpConfig, writePermissions, writeClaudeMd, writeHooks, hasMcpConfig, hasPermissions, hasHooks } from './config-writer'; /** * Format a number with commas @@ -25,40 +24,11 @@ export async function runInstaller(): Promise { showBanner(); try { - // Step 1: Check if codegraph is available (skip install if already there) - let codegraphAvailable = false; - try { - const checkCmd = process.platform === 'win32' ? 'where codegraph' : 'command -v codegraph'; - execSync(checkCmd, { stdio: 'pipe' }); - codegraphAvailable = true; - } catch { - // Not installed globally yet - } - - if (!codegraphAvailable) { - console.log(chalk.dim(' Installing codegraph globally...')); - try { - execSync('npm install -g @colbymchenry/codegraph', { stdio: 'pipe' }); - success('Installed codegraph command globally'); - codegraphAvailable = true; - } catch { - // May fail if no permissions, but that's ok - npx still works - info('Could not install globally — will use npx instead'); - info('(MCP server and hooks will use npx @colbymchenry/codegraph)'); - } - console.log(); - } - - // If codegraph binary isn't in PATH, tell config-writer to use npx for everything - if (!codegraphAvailable) { - setUseNpxFallback(true); - } - - // Step 2: Ask for installation location + // Step 1: Ask for installation location const location = await promptInstallLocation(); console.log(); - // Step 3: Write MCP configuration + // Step 2: Write MCP configuration const alreadyHasMcp = hasMcpConfig(location); writeMcpConfig(location); @@ -68,7 +38,7 @@ export async function runInstaller(): Promise { success(`Added MCP server to ${location === 'global' ? '~/.claude.json' : './.claude.json'}`); } - // Step 4: Ask about auto-allow permissions + // Step 3: Ask about auto-allow permissions const autoAllow = await promptAutoAllow(); console.log(); @@ -83,7 +53,7 @@ export async function runInstaller(): Promise { } } - // Step 5: Write auto-sync hooks + // Step 4: Write auto-sync hooks const alreadyHasHooks = hasHooks(location); writeHooks(location); @@ -93,7 +63,7 @@ export async function runInstaller(): Promise { success(`Added auto-sync hooks to ${location === 'global' ? '~/.claude/settings.json' : './.claude/settings.json'}`); } - // Step 6: Write CLAUDE.md instructions + // Step 5: Write CLAUDE.md instructions const claudeMdResult = writeClaudeMd(location); const claudeMdPath = location === 'global' ? '~/.claude/CLAUDE.md' : './.claude/CLAUDE.md'; @@ -105,13 +75,13 @@ export async function runInstaller(): Promise { success(`Added CodeGraph instructions to ${claudeMdPath}`); } - // Step 7: For local install, initialize the project + // Step 6: For local install, initialize the project if (location === 'local') { await initializeLocalProject(); } // Show next steps - showNextSteps(location, !codegraphAvailable); + showNextSteps(location); } catch (err) { console.log(); if (err instanceof Error && err.message.includes('readline was closed')) { @@ -137,7 +107,7 @@ async function initializeLocalProject(): Promise { } catch (err) { const msg = err instanceof Error ? err.message : String(err); error(`Could not load native modules: ${msg}`); - info('Skipping project initialization. You can run "codegraph init -i" later.'); + info('Skipping project initialization. You can run "npx @colbymchenry/codegraph init -i" later.'); info('If this persists, try a Node.js LTS version (20 or 22).'); return; }