| 3 | import type { Runner, RunnerResult, AgentStep } from './runner' |
| 4 | |
| 5 | export class CodexRunner implements Runner { |
| 6 | private cwd: string |
| 7 | private env: Record<string, string> |
| 8 | |
| 9 | constructor(cwd: string, env: Record<string, string> = {}) { |
| 10 | this.cwd = cwd |
| 11 | this.env = env |
| 12 | } |
| 13 | |
| 14 | async run(prompt: string): Promise<RunnerResult> { |
| 15 | const steps: AgentStep[] = [] |
| 16 | let totalCostUsd = 0 |
| 17 | |
| 18 | return new Promise((resolve, reject) => { |
| 19 | // Codex CLI uses the prompt as a positional argument |
| 20 | // Use exec subcommand with --full-auto for automatic execution |
| 21 | // --full-auto enables -a on-failure and --sandbox workspace-write |
| 22 | // Use --json for structured output that we can parse |
| 23 | const args = [ |
| 24 | 'exec', |
| 25 | '--full-auto', |
| 26 | '--json', |
| 27 | '-m', |
| 28 | 'gpt-5.1-codex', |
| 29 | prompt, |
| 30 | ] |
| 31 | |
| 32 | console.log(`[CodexRunner] Running: codex ${args.join(' ')}`) |
| 33 | |
| 34 | const child = spawn('codex', args, { |
| 35 | cwd: this.cwd, |
| 36 | env: { |
| 37 | ...process.env, |
| 38 | ...this.env, |
| 39 | CODEX_API_KEY: process.env.OPENAI_API_KEY || this.env.OPENAI_API_KEY, |
| 40 | }, |
| 41 | // Use 'ignore' for stdin to prevent the CLI from waiting for input |
| 42 | stdio: ['ignore', 'pipe', 'pipe'], |
| 43 | }) |
| 44 | |
| 45 | let _stdout = '' |
| 46 | let stderr = '' |
| 47 | |
| 48 | child.stdout.on('data', (data: Buffer) => { |
| 49 | const chunk = data.toString() |
| 50 | _stdout += chunk |
| 51 | process.stdout.write(chunk) |
| 52 | |
| 53 | // Codex outputs events as JSON lines in some modes |
| 54 | const lines = chunk.split('\n').filter((line) => line.trim()) |
| 55 | for (const line of lines) { |
| 56 | try { |
| 57 | const event = JSON.parse(line) |
| 58 | if (event.type === 'message') { |
| 59 | steps.push({ |
| 60 | type: 'text', |
| 61 | text: event.content || event.message || '', |
| 62 | }) |
nothing calls this directly
no outgoing calls
no test coverage detected