From 88e1f2df7fbb2c7a0488bfe70de5cdb3d836f9c3 Mon Sep 17 00:00:00 2001 From: Colby McHenry Date: Thu, 19 Feb 2026 15:38:59 -0600 Subject: [PATCH] fix: Bring back global install attempt with loud failure messaging MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Global install is still attempted for bare `codegraph` convenience, but now verifies the command is actually in PATH after install. If it fails, users get clear actionable messages instead of silent swallowing. Configs (MCP server, hooks) always use npx regardless — those never break even if global install fails. --- src/installer/banner.ts | 13 +++++++----- src/installer/index.ts | 46 ++++++++++++++++++++++++++++++++++------- 2 files changed, 47 insertions(+), 12 deletions(-) diff --git a/src/installer/banner.ts b/src/installer/banner.ts index b0d6d8f..1d004fc 100644 --- a/src/installer/banner.ts +++ b/src/installer/banner.ts @@ -113,18 +113,21 @@ export function warn(message: string): void { /** * Show the "next steps" section after installation */ -export function showNextSteps(location: 'global' | 'local'): void { +export function showNextSteps(location: 'global' | 'local', codegraphAvailable?: boolean): void { console.log(); console.log(chalk.bold(' Done!') + ' Restart Claude Code to use CodeGraph.'); console.log(); if (location === 'global') { + const cmd = codegraphAvailable ? 'codegraph' : 'npx @colbymchenry/codegraph'; console.log(chalk.dim(' Quick start:')); console.log(chalk.dim(' cd your-project')); - 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')); + console.log(chalk.cyan(` ${cmd} init -i`)); + if (!codegraphAvailable) { + 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/index.ts b/src/installer/index.ts index cb8781d..ffab815 100644 --- a/src/installer/index.ts +++ b/src/installer/index.ts @@ -5,6 +5,7 @@ * 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 } from './config-writer'; @@ -24,11 +25,42 @@ export async function runInstaller(): Promise { showBanner(); try { - // Step 1: Ask for installation location + // Step 1: Try global install for bare `codegraph` command convenience. + // This is best-effort — configs always use npx regardless. + 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 — try to install + console.log(chalk.dim(' Installing codegraph globally...')); + try { + execSync('npm install -g @colbymchenry/codegraph', { stdio: 'pipe' }); + // Verify it actually worked (PATH may not include npm global bin) + try { + execSync(process.platform === 'win32' ? 'where codegraph' : 'command -v codegraph', { stdio: 'pipe' }); + codegraphAvailable = true; + success('Installed codegraph command globally'); + } catch { + // Install "succeeded" but command not in PATH — common with nvm/fnm + info('Global install succeeded but codegraph is not in your PATH'); + info('You may need to add npm\'s global bin to your PATH, or use:'); + info(' npx @colbymchenry/codegraph '); + } + } catch { + info('Could not install globally (permission denied)'); + info('You can install manually with: sudo npm install -g @colbymchenry/codegraph'); + info('Or use: npx @colbymchenry/codegraph '); + } + console.log(); + } + + // Step 2: Ask for installation location const location = await promptInstallLocation(); console.log(); - // Step 2: Write MCP configuration + // Step 3: Write MCP configuration (always uses npx for reliability) const alreadyHasMcp = hasMcpConfig(location); writeMcpConfig(location); @@ -38,7 +70,7 @@ export async function runInstaller(): Promise { success(`Added MCP server to ${location === 'global' ? '~/.claude.json' : './.claude.json'}`); } - // Step 3: Ask about auto-allow permissions + // Step 4: Ask about auto-allow permissions const autoAllow = await promptAutoAllow(); console.log(); @@ -53,7 +85,7 @@ export async function runInstaller(): Promise { } } - // Step 4: Write auto-sync hooks + // Step 5: Write auto-sync hooks const alreadyHasHooks = hasHooks(location); writeHooks(location); @@ -63,7 +95,7 @@ export async function runInstaller(): Promise { success(`Added auto-sync hooks to ${location === 'global' ? '~/.claude/settings.json' : './.claude/settings.json'}`); } - // Step 5: Write CLAUDE.md instructions + // Step 6: Write CLAUDE.md instructions const claudeMdResult = writeClaudeMd(location); const claudeMdPath = location === 'global' ? '~/.claude/CLAUDE.md' : './.claude/CLAUDE.md'; @@ -75,13 +107,13 @@ export async function runInstaller(): Promise { success(`Added CodeGraph instructions to ${claudeMdPath}`); } - // Step 6: For local install, initialize the project + // Step 7: For local install, initialize the project if (location === 'local') { await initializeLocalProject(); } // Show next steps - showNextSteps(location); + showNextSteps(location, codegraphAvailable); } catch (err) { console.log(); if (err instanceof Error && err.message.includes('readline was closed')) {