/**
 * olam memory bridge serve --local — embedded Miniflare bridge.
 *
 * `wrangler dev` is a dev iteration loop, not a production-style host
 * for a long-lived service. This subcommand spawns
 * `packages/memory-service/scripts/local-bridge-server.mjs` as a
 * foreground Node process: operators wire it into launchd / systemd
 * (Type=simple) and get the agent-memory bridge running on their
 * laptop without a Cloudflare account.
 *
 * Flow:
 *   1. Resolve packages/memory-service/ via the shared candidates list
 *      (handles workspace / bundled-CLI / cwd-checkout layouts).
 *   2. Locate scripts/local-bridge-server.mjs inside it.
 *   3. Ensure ~/.olam/memory-secret (0600) exists; pass it via
 *      AGENTMEMORY_SECRET env so the bridge can authenticate
 *      /bridge/stats callers without leaking the secret on argv.
 *   4. Spawn the .mjs in foreground; stdin/stdout/stderr propagate so
 *      the service-manager journal captures the bridge's logs.
 *   5. Forward SIGTERM/SIGINT to the child + exit with its code.
 *
 * Mirrors `start.ts`'s service-resolution + secret-handling pattern;
 * differs in that the spawned process stays in foreground (start.ts
 * detaches because the agentmemory engine is a separate long-lived
 * service).
 *
 * Plan reference: architecture conversation in PR #612.
 */
import { spawn } from 'node:child_process';
import { existsSync } from 'node:fs';
import { join } from 'node:path';
import { printError, printHeader, printInfo } from '../../output.js';
import { ensureMemorySecret } from '../../lib/memory-secret.js';
import { MEMORY_SERVICE_CANDIDATES } from './_paths.js';
const DEFAULT_PORT = 8788;
export function resolveMemoryServiceDir() {
    for (const c of MEMORY_SERVICE_CANDIDATES) {
        if (existsSync(c))
            return c;
    }
    throw new Error(`Could not find packages/memory-service/. Searched: ${MEMORY_SERVICE_CANDIDATES.join(', ')}. ` +
        `If running from a published @pleri/olam-cli tarball, this is a packaging bug — please file an issue.`);
}
export function resolveLocalBridgeScript(serviceDir) {
    const path = join(serviceDir, 'scripts', 'local-bridge-server.mjs');
    if (!existsSync(path)) {
        throw new Error(`Could not find local-bridge-server.mjs at ${path}. ` +
            `Verify packages/memory-service ships the scripts/ directory.`);
    }
    return path;
}
export function validateBridgeOpts(opts) {
    const local = opts.local ?? false;
    if (!local) {
        throw new Error(`'olam memory bridge serve' currently requires --local. ` +
            `Remote-bridge orchestration is reserved for future flags.`);
    }
    const port = opts.port ?? DEFAULT_PORT;
    if (!Number.isInteger(port) || port < 0 || port > 65535) {
        throw new Error(`--port must be an integer 0..65535 (got: ${opts.port})`);
    }
    const result = {
        port,
        local,
    };
    if (typeof opts.persistTo === 'string' && opts.persistTo.length > 0) {
        result.persistTo = opts.persistTo;
    }
    return result;
}
export async function runBridgeServe(opts, deps = {}) {
    printHeader('olam memory bridge serve --local');
    const validated = validateBridgeOpts(opts);
    printInfo('port', String(validated.port));
    if (validated.persistTo) {
        printInfo('persist-to', validated.persistTo);
    }
    else {
        printInfo('persist-to', '(in-memory — DO state lost on restart)');
    }
    const serviceDir = (deps.resolveServiceDir ?? resolveMemoryServiceDir)();
    const scriptPath = resolveLocalBridgeScript(serviceDir);
    printInfo('entry', scriptPath);
    const secret = (deps.ensureSecret ?? ensureMemorySecret)();
    const args = ['--port', String(validated.port)];
    if (validated.persistTo) {
        args.push('--persist-to', validated.persistTo);
    }
    const env = {
        ...process.env,
        AGENTMEMORY_SECRET: secret,
    };
    const spawner = deps.spawnChild ??
        ((command, spawnArgs, spawnEnv) => spawn(command, [...spawnArgs], {
            env: spawnEnv,
            stdio: 'inherit',
        }));
    const child = spawner(process.execPath, [scriptPath, ...args], env);
    return new Promise((resolve) => {
        let resolved = false;
        const finish = (code) => {
            if (resolved)
                return;
            resolved = true;
            resolve(code);
        };
        const forward = (signal) => () => {
            if (!child.killed) {
                try {
                    child.kill(signal);
                }
                catch {
                    // Best-effort signal forwarding; child may already be exiting.
                }
            }
        };
        process.on('SIGTERM', forward('SIGTERM'));
        process.on('SIGINT', forward('SIGINT'));
        child.on('error', (err) => {
            printError(`failed to spawn local-bridge-server.mjs: ${err.message}`);
            finish(1);
        });
        child.on('exit', (code, signal) => {
            if (signal) {
                // Treat signal-driven exit as success (operator stopped service).
                finish(0);
            }
            else {
                finish(code ?? 1);
            }
        });
    });
}
export function registerMemoryBridge(cmd) {
    const bridge = cmd
        .command('bridge')
        .description('Local bridge service (Miniflare-embedded) for the agent-memory engine');
    bridge
        .command('serve')
        .description('Run the agent-memory bridge as a foreground Node process (suitable for systemd/launchd)')
        .option('--local', 'Use the embedded Miniflare runtime (currently required)')
        .option('--port <n>', 'TCP port to bind on', (v) => parseInt(v, 10), DEFAULT_PORT)
        .option('--persist-to <path>', 'DO SQLite persistence directory')
        .action(async (opts) => {
        try {
            const rc = await runBridgeServe(opts);
            if (rc !== 0)
                process.exitCode = rc;
        }
        catch (err) {
            printError(err instanceof Error ? err.message : String(err));
            process.exitCode = 1;
        }
    });
}
//# sourceMappingURL=bridge.js.map