| 49 | } |
| 50 | |
| 51 | class CodexTarget implements AgentTarget { |
| 52 | readonly id = 'codex' as const; |
| 53 | readonly displayName = 'Codex CLI'; |
| 54 | readonly docsUrl = 'https://github.com/openai/codex'; |
| 55 | |
| 56 | supportsLocation(loc: Location): boolean { |
| 57 | return loc === 'global'; |
| 58 | } |
| 59 | |
| 60 | detect(loc: Location): DetectionResult { |
| 61 | if (loc !== 'global') { |
| 62 | return { installed: false, alreadyConfigured: false }; |
| 63 | } |
| 64 | const tomlPath = tomlConfigPath(); |
| 65 | let alreadyConfigured = false; |
| 66 | if (fs.existsSync(tomlPath)) { |
| 67 | try { |
| 68 | const content = fs.readFileSync(tomlPath, 'utf-8'); |
| 69 | alreadyConfigured = content.includes(`[${TOML_HEADER}]`); |
| 70 | } catch { /* ignore */ } |
| 71 | } |
| 72 | const installed = fs.existsSync(configDir()); |
| 73 | return { installed, alreadyConfigured, configPath: tomlPath }; |
| 74 | } |
| 75 | |
| 76 | install(loc: Location, _opts: InstallOptions): WriteResult { |
| 77 | if (loc !== 'global') { |
| 78 | return { |
| 79 | files: [], |
| 80 | notes: ['Codex CLI has no project-local config — re-run with --location=global to install.'], |
| 81 | }; |
| 82 | } |
| 83 | const files: WriteResult['files'] = []; |
| 84 | |
| 85 | files.push(writeMcpEntry()); |
| 86 | |
| 87 | // AGENTS.md gets the short marker-fenced CodeGraph block (#704): |
| 88 | // subagents and non-MCP harnesses read AGENTS.md but never the MCP |
| 89 | // initialize instructions. Upsert self-heals a stale pre-#529 block. |
| 90 | files.push(upsertInstructionsEntry(instructionsPath())); |
| 91 | |
| 92 | return { files }; |
| 93 | } |
| 94 | |
| 95 | uninstall(loc: Location): WriteResult { |
| 96 | if (loc !== 'global') return { files: [] }; |
| 97 | const files: WriteResult['files'] = []; |
| 98 | |
| 99 | const tomlPath = tomlConfigPath(); |
| 100 | if (fs.existsSync(tomlPath)) { |
| 101 | const content = fs.readFileSync(tomlPath, 'utf-8'); |
| 102 | const { content: nextContent, action } = removeTomlTable(content, TOML_HEADER); |
| 103 | if (action === 'removed') { |
| 104 | if (nextContent.trim() === '') { |
| 105 | try { fs.unlinkSync(tomlPath); } catch { /* ignore */ } |
| 106 | } else { |
| 107 | atomicWriteFileSync(tomlPath, nextContent.trimEnd() + '\n'); |
| 108 | } |
nothing calls this directly
no outgoing calls
no test coverage detected