/**
 * Antigravity / agy MCP injector.
 *
 * `agy` auto-loads MCP servers declared in `~/.gemini/config/mcp_config.json`
 * — the same shape Claude Code, Gemini CLI, and many other MCP hosts use:
 *
 *   {
 *     "mcpServers": {
 *       "<name>": { "command": "...", "args": [...], "env": {...} }
 *     }
 *   }
 *
 * On adapter init we read-modify-write this file so the `imhub` entry
 * is always pointed at the current approval-bus socket (which rotates
 * every agim restart — see core/approval-bus.ts:defaultSocketPath).
 * Other entries the operator already had stay untouched.
 *
 * Why a single shared config file (vs claude-code's per-spawn tmpdir):
 * agy has no `--mcp-config <path>` flag; the only way to wire MCP is
 * the global file. Concurrency-wise that's fine because the file just
 * tells agy which sidecar to launch — the sidecar itself is stateless
 * across runs (each run gets its own IMHUB_RUN_ID via process env).
 */
import { mkdir, readFile, writeFile } from 'node:fs/promises';
import { homedir } from 'node:os';
import { dirname, join } from 'node:path';
import { logger as rootLogger } from '../../../core/logger.js';
const log = rootLogger.child({ component: 'agent.antigravity.mcp' });
/** Resolves to `${HOME}/.gemini/config/mcp_config.json`. Exported for tests
 *  that want to point this at a tmp dir instead of the real home. */
export function defaultMcpConfigPath() {
    return join(homedir(), '.gemini', 'config', 'mcp_config.json');
}
/**
 * Ensure `~/.gemini/config/mcp_config.json` has the imhub MCP entry
 * pointing at the current approval-bus socket. Preserves any other
 * keys / mcpServers entries the operator already configured.
 *
 * Idempotent: safe to call on every adapter init or before every spawn.
 */
export async function ensureImhubMcp(spec, opts = {}) {
    const filePath = opts.path ?? defaultMcpConfigPath();
    let current = {};
    try {
        const raw = await readFile(filePath, 'utf8');
        if (raw.trim()) {
            try {
                current = JSON.parse(raw);
            }
            catch {
                // Empty / corrupt file — agy itself logs `unexpected end of JSON
                // input` and proceeds without MCP, so rewriting from scratch is
                // safer than refusing to update.
                log.warn({ event: 'antigravity.mcp.parse_failed', filePath }, 'replacing unparseable mcp_config.json');
                current = {};
            }
        }
    }
    catch (err) {
        const e = err;
        if (e.code !== 'ENOENT')
            throw err;
        // First-time setup: create directory + start from empty
    }
    if (!current.mcpServers || typeof current.mcpServers !== 'object') {
        current.mcpServers = {};
    }
    const existing = current.mcpServers.imhub;
    // Skip write if nothing changed — avoids touching mtime on every send.
    if (existing
        && existing.command === spec.command
        && JSON.stringify(existing.args ?? []) === JSON.stringify(spec.args ?? [])
        && JSON.stringify(existing.env ?? {}) === JSON.stringify(spec.env ?? {})) {
        return;
    }
    current.mcpServers.imhub = spec;
    try {
        await mkdir(dirname(filePath), { recursive: true });
        await writeFile(filePath, JSON.stringify(current, null, 2), 'utf8');
        log.info({ event: 'antigravity.mcp.config_written', filePath }, 'wrote imhub MCP entry to agy global config');
    }
    catch (err) {
        log.warn({ event: 'antigravity.mcp.write_failed', filePath, err: String(err) }, 'could not write mcp_config.json — agy will run without imhub MCP');
        throw err;
    }
}
/**
 * Remove the imhub MCP entry. Used by tests / uninstall flows; the
 * normal adapter path just overwrites with a fresh socket.
 */
export async function removeImhubMcp(opts = {}) {
    const filePath = opts.path ?? defaultMcpConfigPath();
    let current = {};
    try {
        const raw = await readFile(filePath, 'utf8');
        if (raw.trim())
            current = JSON.parse(raw);
    }
    catch (err) {
        const e = err;
        if (e.code === 'ENOENT')
            return;
        throw err;
    }
    if (current.mcpServers && current.mcpServers.imhub) {
        delete current.mcpServers.imhub;
        await writeFile(filePath, JSON.stringify(current, null, 2), 'utf8');
    }
}
//# sourceMappingURL=ensure-mcp-config.js.map