// ensure-mcp-config.ts — register the imhub MCP sidecar into opencode's
// global config so the reminder tools are visible to opencode runs.
//
// Why modify global config:
//
//   opencode loads MCP servers from `~/.config/opencode/opencode.json` at
//   startup and inherits parent process env when spawning each server's
//   stdio. We can't just "pass --mcp-config" per spawn — opencode has no
//   such flag. The next-best knob is the global config file.
//
// We do an additive update: read the JSON if it exists, set
// `mcp.imhub.local.{command,enabled}`, write back. Other keys (provider,
// theme, etc.) are preserved unchanged. Idempotent — repeated calls are
// no-ops once the desired entry is in place.
//
// Per-spawn IM context (which thread / user is calling) flows through
// process.env: opencode-stdio-adapter sets IMHUB_APPROVAL_SOCK +
// IMHUB_RUN_ID on each spawn, opencode forwards them to the MCP server
// (per opencode/src/mcp/index.ts:384, env: { ...process.env, ... }).
import { homedir } from 'node:os';
import { join, dirname } from 'node:path';
import { readFile, writeFile, mkdir } from 'node:fs/promises';
import { fileURLToPath } from 'node:url';
import { logger as rootLogger } from '../../../core/logger.js';
const log = rootLogger.child({ component: 'opencode-mcp-config' });
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
// Sidecar lives next to claude-code's MCP entry — same JS, opencode just
// reaches it through a different MCP transport.
const SIDECAR_PATH = join(__dirname, '..', 'claude-code', 'mcp-approval-server.js');
/**
 * Idempotently register the imhub MCP server in opencode's global config.
 * Returns true when a write actually happened (config changed), false when
 * the config was already in the desired state.
 *
 * Failures (file unreadable, JSON malformed, write rejected) are logged
 * and swallowed — opencode users still keep working without reminder
 * tools, the same way they did before this feature.
 */
export async function ensureOpencodeMcpRegistered() {
    const configPath = process.env.OPENCODE_CONFIG_PATH
        ?? join(homedir(), '.config', 'opencode', 'opencode.json');
    let config = {};
    try {
        const buf = await readFile(configPath, 'utf8');
        config = JSON.parse(buf);
        if (typeof config !== 'object' || config === null || Array.isArray(config)) {
            log.warn({ event: 'opencode.mcp.bad_config', configPath }, 'opencode config is not a JSON object — skipping MCP registration');
            return false;
        }
    }
    catch (err) {
        const code = err.code;
        if (code !== 'ENOENT') {
            log.warn({
                event: 'opencode.mcp.read_failed', configPath,
                err: err instanceof Error ? err.message : String(err),
            }, 'opencode config read failed — skipping MCP registration');
            return false;
        }
        // No config yet — start fresh.
        config = {};
    }
    if (!config.mcp || typeof config.mcp !== 'object' || Array.isArray(config.mcp)) {
        config.mcp = {};
    }
    const mcp = config.mcp;
    const desired = {
        type: 'local',
        command: [process.execPath, SIDECAR_PATH],
        enabled: true,
    };
    // Compare existing entry; bail if already correct.
    const existing = mcp.imhub;
    if (existing
        && typeof existing === 'object'
        && !Array.isArray(existing)
        && JSON.stringify(existing) === JSON.stringify(desired)) {
        log.debug({ event: 'opencode.mcp.already_registered', configPath });
        return false;
    }
    mcp.imhub = desired;
    try {
        await mkdir(dirname(configPath), { recursive: true });
        await writeFile(configPath, `${JSON.stringify(config, null, 2)}\n`, 'utf8');
        log.info({
            event: 'opencode.mcp.registered',
            configPath, sidecar: SIDECAR_PATH,
        }, 'imhub MCP server registered in opencode global config');
        return true;
    }
    catch (err) {
        log.warn({
            event: 'opencode.mcp.write_failed', configPath,
            err: err instanceof Error ? err.message : String(err),
        }, 'opencode config write failed — opencode will not see imhub MCP tools');
        return false;
    }
}
//# sourceMappingURL=ensure-mcp-config.js.map