diff --git a/packages/happy-cli/src/codex/codexMcpClient.ts b/packages/happy-cli/src/codex/codexMcpClient.ts index 25f2e6854d..0872e273b0 100644 --- a/packages/happy-cli/src/codex/codexMcpClient.ts +++ b/packages/happy-cli/src/codex/codexMcpClient.ts @@ -98,12 +98,17 @@ export class CodexMcpClient { if (mcpCommand === null) { throw new Error( - 'Codex CLI not found or not executable.\n' + + 'Codex CLI is not installed\n' + '\n' + - 'To install codex:\n' + + 'Please install Codex CLI using one of these methods:\n' + + '\n' + + 'Option 1 - npm (recommended):\n' + ' npm install -g @openai/codex\n' + '\n' + - 'Alternatively, use Claude:\n' + + 'Option 2 - Homebrew (macOS):\n' + + ' brew install --cask codex\n' + + '\n' + + 'Alternatively, use Claude Code:\n' + ' happy claude' ); } diff --git a/packages/happy-cli/src/codex/runCodex.ts b/packages/happy-cli/src/codex/runCodex.ts index 0d51a7b974..37aeedfb44 100644 --- a/packages/happy-cli/src/codex/runCodex.ts +++ b/packages/happy-cli/src/codex/runCodex.ts @@ -6,6 +6,7 @@ import { CodexPermissionHandler } from './utils/permissionHandler'; import { ReasoningProcessor } from './utils/reasoningProcessor'; import { DiffProcessor } from './utils/diffProcessor'; import { randomUUID } from 'node:crypto'; +import { execSync } from 'node:child_process'; import { logger } from '@/ui/logger'; import { Credentials, readSettings } from '@/persistence'; import { initialMachineMetadata } from '@/daemon/run'; @@ -70,6 +71,21 @@ export async function runCodex(opts: { startedBy?: 'daemon' | 'terminal'; noSandbox?: boolean; }): Promise { + // Early check: ensure Codex CLI is installed before proceeding + try { + execSync('codex --version', { encoding: 'utf8', stdio: 'pipe' }); + } catch { + console.error('\n\x1b[1m\x1b[33mCodex CLI is not installed\x1b[0m\n'); + console.error('Please install Codex CLI using one of these methods:\n'); + console.error('\x1b[1mOption 1 - npm (recommended):\x1b[0m'); + console.error(' \x1b[36mnpm install -g @openai/codex\x1b[0m\n'); + console.error('\x1b[1mOption 2 - Homebrew (macOS):\x1b[0m'); + console.error(' \x1b[36mbrew install --cask codex\x1b[0m\n'); + console.error('Alternatively, use Claude Code:'); + console.error(' \x1b[36mhappy claude\x1b[0m\n'); + process.exit(1); + } + // Use shared PermissionMode type for cross-agent compatibility type PermissionMode = import('@/api/types').PermissionMode; interface EnhancedMode {