/**
 * olam memory install — Register `agentmemory` as an MCP server with the
 * operator's host claude.
 *
 * Shells to:
 *   claude mcp add agentmemory --scope <s>
 *     --env AGENTMEMORY_URL=http://localhost:3111
 *     --env AGENTMEMORY_SECRET=<from-file>
 *     -- npx -y @agentmemory/mcp
 *
 * The secret is read from ~/.olam/memory-secret (generated by A2 start or
 * A3 secret rotate). Missing secret → exit 1 with remedy.
 *
 * Rotation note: claude stores the env value at install-time. After
 * `olam memory secret rotate`, re-run `olam memory install` so claude
 * picks up the new value (the rotate command surfaces this as a warning).
 *
 * Security note (CP3 audit, 2026-05-13): the bearer secret transits as
 * an argv element of the spawned `claude` invocation. On Linux + macOS,
 * argv is briefly readable via `/proc/<pid>/cmdline` (Linux) or `ps -E`
 * (macOS) by any local user during the few ms claude runs. Blast radius:
 * operator's own machine (single-user dev laptop = effectively nil;
 * shared dev VM / interactive tmux = full secret disclosure to anyone
 * on the box). Same shape as every other `--env KEY=VAL` CLI. Operator
 * docs (A6) call this out + name the mitigation: don't run install on
 * boxes with untrusted local users. If/when `claude mcp add` grows a
 * `--env-stdin` form upstream, switch to it.
 *
 * Plan reference: docs/plans/olam-agent-memory-distributed/phase-a-tasks.md A4
 */
import { printError, printSuccess } from '../../output.js';
import { DEFAULT_CLAUDE_SHELL_DEPS, REMEDY_CLAUDE_MISSING, isOnPath, normaliseScope, } from '../mcp/install-shared.js';
import { MEMORY_REST_PORT } from './_paths.js';
import { MEMORY_SECRET_PATH, readMemorySecretOrNull, } from '../../lib/memory-secret.js';
const MCP_NAME = 'agentmemory';
const NPM_PACKAGE_NAME = '@agentmemory/mcp';
export const DEFAULT_SECRET_READER = () => readMemorySecretOrNull();
export function buildClaudeMcpAddArgs(scope, agentmemoryUrl, secret) {
    return {
        command: 'claude',
        args: [
            'mcp',
            'add',
            MCP_NAME,
            '--scope',
            scope,
            '--env',
            `AGENTMEMORY_URL=${agentmemoryUrl}`,
            '--env',
            `AGENTMEMORY_SECRET=${secret}`,
            '--',
            'npx',
            '-y',
            NPM_PACKAGE_NAME,
        ],
    };
}
const REMEDY_SECRET_MISSING = `No memory-secret found at ${MEMORY_SECRET_PATH}. ` +
    `Run 'olam memory start' first — it generates the secret on first launch.`;
/**
 * Defensive redaction for any stderr/stdout we echo back. If `claude`
 * (or an upstream bug) ever prints the env values on parse failure, we
 * don't want the secret hitting the operator's terminal scrollback.
 */
function redactSecretInText(text) {
    return text.replace(/AGENTMEMORY_SECRET=\S+/g, 'AGENTMEMORY_SECRET=<redacted>');
}
export async function runInstall(opts, deps = DEFAULT_CLAUDE_SHELL_DEPS) {
    if (!isOnPath(deps, 'claude')) {
        printError(REMEDY_CLAUDE_MISSING);
        return 1;
    }
    const readSecret = opts.readSecret ?? DEFAULT_SECRET_READER;
    const secret = opts.secret ?? readSecret();
    if (!secret) {
        printError(REMEDY_SECRET_MISSING);
        return 1;
    }
    const agentmemoryUrl = `http://localhost:${MEMORY_REST_PORT}`;
    const { command, args } = buildClaudeMcpAddArgs(opts.scope, agentmemoryUrl, secret);
    // Log without leaking the secret. Replace the AGENTMEMORY_SECRET arg with a redacted shape.
    const redacted = args.map((a) => a.startsWith('AGENTMEMORY_SECRET=') ? 'AGENTMEMORY_SECRET=<redacted>' : a);
    deps.log(`Wiring: ${command} ${redacted.join(' ')}`);
    const result = deps.spawn(command, args, {
        encoding: 'utf8',
        stdio: ['ignore', 'pipe', 'pipe'],
    });
    if (result.status !== 0) {
        const detail = redactSecretInText(result.stderr?.trim() || result.stdout?.trim() || '(no output)');
        printError(`claude mcp add failed (rc=${result.status ?? 'unknown'}): ${detail}`);
        return result.status ?? 1;
    }
    printSuccess(`agentmemory MCP registered with claude (--scope ${opts.scope}; url ${agentmemoryUrl}).`);
    return 0;
}
export function registerMemoryInstall(cmd) {
    cmd
        .command('install')
        .description('Register agentmemory as an MCP server with the operator\'s host claude (shells to `claude mcp add`)')
        .option('--scope <scope>', 'claude mcp scope: user | project | local', 'user')
        .action(async (rawOpts) => {
        const scope = normaliseScope(rawOpts.scope);
        if (scope === null) {
            printError(`--scope must be one of: user, project, local (got: ${rawOpts.scope})`);
            process.exitCode = 1;
            return;
        }
        const rc = await runInstall({ scope });
        if (rc !== 0) {
            process.exitCode = rc;
        }
    });
}
//# sourceMappingURL=install.js.map