/**
 * RPC mode: Headless operation with JSON stdin/stdout protocol.
 *
 * Used for embedding the agent in other applications.
 * Receives commands as JSON on stdin, outputs events and responses as JSON on stdout.
 *
 * Protocol:
 * - Commands: JSON objects with `type` field, optional `id` for correlation
 * - Responses: JSON objects with `type: "response"`, `command`, `success`, and optional `data`/`error`
 * - Events: AgentSessionEvent objects streamed as they occur
 * - Extension UI: Extension UI requests are emitted, client responds with extension_ui_response
 */
import { flushRawStdout, takeOverStdout, writeRawStdout } from "../../core/output-guard.js";
import { killTrackedDetachedChildren } from "../../utils/shell.js";
import { attachJsonlLineReader, serializeJsonLine } from "./jsonl.js";
import { createRpcCommandHandler } from "./rpc-command-handler.js";
import { createRpcInputLineHandler } from "./rpc-input.js";
import { RpcSessionBinding } from "./rpc-session-binding.js";
/**
 * Run in RPC mode.
 * Listens for JSON commands on stdin, outputs events and responses on stdout.
 */
export async function runRpcMode(runtimeHost) {
    takeOverStdout();
    const output = (obj) => {
        writeRawStdout(serializeJsonLine(obj));
    };
    const pendingExtensionRequests = new Map();
    const signalCleanupHandlers = [];
    let shutdownRequested = false;
    let shuttingDown = false;
    let detachInput = () => { };
    const requestShutdown = () => {
        shutdownRequested = true;
    };
    const sessionBinding = new RpcSessionBinding({
        runtimeHost,
        output,
        pendingExtensionRequests,
        requestShutdown,
    });
    runtimeHost.setRebindSession(async () => {
        await sessionBinding.rebindSession();
    });
    const handleCommand = createRpcCommandHandler({
        runtimeHost,
        getSession: () => sessionBinding.currentSession,
        rebindSession: () => sessionBinding.rebindSession(),
        output,
    });
    async function shutdown(exitCode = 0, signal) {
        if (shuttingDown) {
            process.exit(exitCode);
        }
        shuttingDown = true;
        for (const cleanup of signalCleanupHandlers) {
            cleanup();
        }
        sessionBinding.disposeSubscriptions();
        await runtimeHost.dispose();
        detachInput();
        process.stdin.pause();
        if (signal !== "SIGTERM") {
            await flushRawStdout();
        }
        process.exit(exitCode);
    }
    const checkShutdownRequested = async () => {
        if (!shutdownRequested)
            return;
        await shutdown();
    };
    const registerSignalHandlers = () => {
        const signals = ["SIGTERM"];
        if (process.platform !== "win32") {
            signals.push("SIGHUP");
        }
        for (const signal of signals) {
            const handler = () => {
                killTrackedDetachedChildren();
                void shutdown(signal === "SIGHUP" ? 129 : 143, signal);
            };
            process.on(signal, handler);
            signalCleanupHandlers.push(() => process.off(signal, handler));
        }
    };
    await sessionBinding.rebindSession();
    registerSignalHandlers();
    const handleInputLine = createRpcInputLineHandler({
        output,
        pendingExtensionRequests,
        handleCommand,
        checkShutdownRequested,
    });
    const onInputEnd = () => {
        void shutdown();
    };
    process.stdin.on("end", onInputEnd);
    detachInput = (() => {
        const detachJsonl = attachJsonlLineReader(process.stdin, (line) => {
            void handleInputLine(line);
        });
        return () => {
            detachJsonl();
            process.stdin.off("end", onInputEnd);
        };
    })();
    // Keep process alive forever
    return new Promise(() => { });
}
//# sourceMappingURL=rpc-mode.js.map