| 126 | const FORMATTING = { tabSize: 2, insertSpaces: true, eol: '\n' }; |
| 127 | |
| 128 | class OpencodeTarget implements AgentTarget { |
| 129 | readonly id = 'opencode' as const; |
| 130 | readonly displayName = 'opencode'; |
| 131 | readonly docsUrl = 'https://opencode.ai/docs/config'; |
| 132 | |
| 133 | supportsLocation(_loc: Location): boolean { |
| 134 | return true; |
| 135 | } |
| 136 | |
| 137 | detect(loc: Location): DetectionResult { |
| 138 | const file = configPath(loc); |
| 139 | const config = parseConfig(readConfigText(file)); |
| 140 | const alreadyConfigured = !!config.mcp?.codegraph; |
| 141 | // Global: the XDG dir is what current opencode creates on first run; the |
| 142 | // legacy %APPDATA% dir still counts as "opencode present" so a re-install |
| 143 | // can sweep the stale pre-#535 entry out of it. |
| 144 | const legacy = legacyWindowsConfigDir(); |
| 145 | const installed = loc === 'global' |
| 146 | ? fs.existsSync(globalConfigDir()) || (!!legacy && fs.existsSync(legacy)) |
| 147 | : fs.existsSync(file); |
| 148 | return { installed, alreadyConfigured, configPath: file }; |
| 149 | } |
| 150 | |
| 151 | install(loc: Location, _opts: InstallOptions): WriteResult { |
| 152 | const files: WriteResult['files'] = []; |
| 153 | files.push(writeMcpEntry(loc)); |
| 154 | |
| 155 | // AGENTS.md gets the short marker-fenced CodeGraph block (#704): |
| 156 | // subagents and non-MCP harnesses read AGENTS.md but never the MCP |
| 157 | // initialize instructions. Upsert self-heals a stale pre-#529 block. |
| 158 | files.push(upsertInstructionsEntry(instructionsPath(loc))); |
| 159 | |
| 160 | // Self-heal a pre-#535 install that wrote to %APPDATA%/opencode — |
| 161 | // opencode never reads it, so anything of ours there is stale. |
| 162 | if (loc === 'global') files.push(...cleanupLegacyWindowsState()); |
| 163 | |
| 164 | return { files }; |
| 165 | } |
| 166 | |
| 167 | uninstall(loc: Location): WriteResult { |
| 168 | const files: WriteResult['files'] = []; |
| 169 | files.push(removeMcpEntryAt(configPath(loc))); |
| 170 | files.push(removeInstructionsEntry(loc)); |
| 171 | if (loc === 'global') files.push(...cleanupLegacyWindowsState()); |
| 172 | return { files }; |
| 173 | } |
| 174 | |
| 175 | printConfig(loc: Location): string { |
| 176 | const target = configPath(loc); |
| 177 | const snippet = JSON.stringify({ |
| 178 | $schema: 'https://opencode.ai/config.json', |
| 179 | mcp: { codegraph: getOpencodeServerEntry() }, |
| 180 | }, null, 2); |
| 181 | return `# Add to ${target}\n\n${snippet}\n`; |
| 182 | } |
| 183 | |
| 184 | describePaths(loc: Location): string[] { |
| 185 | return [configPath(loc), instructionsPath(loc)]; |
nothing calls this directly
no outgoing calls
no test coverage detected