/**
 * In-world MCP registration helper.
 *
 * After `olam create` spawns a fresh world container, we register the
 * agentmemory MCP server inside that world's claude config so the
 * in-world claude session reaches the host-side agent-memory service
 * without manual `claude mcp add` from the operator.
 *
 * Architecture:
 *
 *   host           docker exec               world container
 *   ----           ----------               ---------------
 *   olam create  ─►   docker exec     ─►    claude mcp add agentmemory
 *                                               --scope user
 *                                               --env AGENTMEMORY_URL=...
 *                                               --env AGENTMEMORY_SECRET=...
 *                                               -- agentmemory-mcp
 *
 * The `agentmemory-mcp` bin is pre-baked into the devbox image (B2), so
 * there's no `npx -y` cold-start at first claude invocation (T6).
 *
 * Idempotency: re-running against an already-registered world is a noop.
 * We detect via `claude mcp list` exit code + stderr signature (same
 * "No <scope> MCP server found" pattern reused from the host-side
 * `olam memory uninstall` helper).
 *
 * Graceful skip: when the world wasn't spawned with AGENTMEMORY_* env
 * (because the host memory service was absent at spawn time per B1),
 * we skip registration with an informative log. The world keeps working
 * — the @agentmemory/mcp shim falls back to local InMemoryKV.
 *
 * Plan reference: docs/plans/olam-agent-memory-distributed/phase-b-tasks.md B3
 */
import { spawnSync } from 'node:child_process';
export const DEFAULT_DOCKER_EXEC_DEPS = {
    spawn: spawnSync,
    log: (msg) => console.log(msg),
};
const MCP_NAME = 'agentmemory';
const MCP_BIN = 'agentmemory-mcp';
/**
 * Probe whether `agentmemory` is already registered inside the world's
 * claude. Uses `claude mcp list` which prints a structured list; we
 * just look for the name in the output. Returns:
 *   - `'present'`   — already registered (idempotent skip path)
 *   - `'absent'`    — not registered yet (proceed to add)
 *   - `'unknown'`   — `claude mcp list` failed for any reason; we don't
 *                     pretend to know the state, caller decides.
 */
export function probeMcpListed(containerName, deps) {
    const result = deps.spawn('docker', ['exec', containerName, 'claude', 'mcp', 'list'], { encoding: 'utf8', stdio: ['ignore', 'pipe', 'pipe'] });
    if (result.status !== 0)
        return 'unknown';
    const combined = `${result.stdout ?? ''}\n${result.stderr ?? ''}`;
    // `claude mcp list` prints one row per registered server. Match on
    // the name at the start of a line to avoid false positives from
    // descriptive prose.
    return new RegExp(`^\\s*${MCP_NAME}\\b`, 'm').test(combined) ? 'present' : 'absent';
}
/**
 * Register the agentmemory MCP server inside a world container.
 *
 * - Skips silently when `agentmemorySecret` is empty (the world was
 *   spawned without B1's env injection because the host memory service
 *   was absent at spawn time).
 * - Skips idempotently when `claude mcp list` already shows the server.
 * - Otherwise shells to `docker exec <world> claude mcp add agentmemory
 *   --scope user --env ... -- agentmemory-mcp`.
 *
 * The bearer secret transits as an argv element of the spawned `claude`
 * process inside the container (same shape as the host-side
 * `olam memory install`). Documented in the operator-facing
 * docs/architecture/agent-memory.md security model.
 */
export function registerAgentMemoryMcp(opts, deps = DEFAULT_DOCKER_EXEC_DEPS) {
    if (!opts.agentmemorySecret || opts.agentmemorySecret.length === 0) {
        return {
            outcome: 'skipped-no-env',
            reason: 'world has no AGENTMEMORY_SECRET (memory service was absent or --skip-memory active at spawn time)',
        };
    }
    const probe = probeMcpListed(opts.containerName, deps);
    if (probe === 'present') {
        return { outcome: 'already-registered', scope: 'user' };
    }
    const args = [
        'exec',
        opts.containerName,
        'claude',
        'mcp',
        'add',
        MCP_NAME,
        '--scope',
        'user',
        '--env',
        `AGENTMEMORY_URL=${opts.agentmemoryUrl}`,
        '--env',
        `AGENTMEMORY_SECRET=${opts.agentmemorySecret}`,
        '--',
        MCP_BIN,
    ];
    // Log without leaking the secret. Same redaction pattern as
    // packages/cli/src/commands/memory/install.ts.
    const redacted = args.map((a) => a.startsWith('AGENTMEMORY_SECRET=') ? 'AGENTMEMORY_SECRET=<redacted>' : a);
    deps.log?.(`Wiring agent-memory MCP in ${opts.containerName}: docker ${redacted.join(' ')}`);
    const result = deps.spawn('docker', args, {
        encoding: 'utf8',
        stdio: ['ignore', 'pipe', 'pipe'],
    });
    if (result.status === 0) {
        return { outcome: 'registered', scope: 'user' };
    }
    // Defensive redaction of any echo-back of the env value.
    const detail = (result.stderr?.trim() || result.stdout?.trim() || '(no output)').replace(/AGENTMEMORY_SECRET=\S+/g, 'AGENTMEMORY_SECRET=<redacted>');
    return { outcome: 'failed', rc: result.status ?? 1, detail };
}
//# sourceMappingURL=world-mcp-register.js.map