import { spawn } from "node:child_process";
import { rm, writeFile } from "node:fs/promises";
import { tmpdir } from "node:os";
import { join } from "node:path";
import { killProcessTree, trackDetachedChildPid, untrackDetachedChildPid } from "../../utils/shell.js";
import { sleep } from "../../utils/sleep.js";
import { INTERACTIVE_ENGINE_MAX_FRAME_BYTES } from "../interactive-engine/protocol.js";
const guardianFiles = new WeakMap();
export function spawnRpcClientProcess(options) {
    const guardianFile = options.interactiveEngine
        ? join(tmpdir(), `atomic-engine-guardian-${process.pid}-${crypto.randomUUID()}`)
        : undefined;
    const child = spawn(options.runtimeExecutable ?? "bun", [...(options.runtimeArgs ?? []), ...(options.cliPath ? [options.cliPath] : []), ...options.cliArgs], {
        cwd: options.cwd,
        env: {
            ...process.env,
            ...options.env,
            ...(options.interactiveEngine ? {
                ATOMIC_INTERACTIVE_ENGINE_CHILD: "1",
                ATOMIC_INTERACTIVE_ENGINE_HOST_PID: String(process.pid),
                ATOMIC_INTERACTIVE_ENGINE_GUARD_FILE: guardianFile,
            } : {}),
        },
        detached: options.interactiveEngine && process.platform !== "win32",
        stdio: ["pipe", "pipe", "pipe"],
    });
    if (guardianFile)
        guardianFiles.set(child, guardianFile);
    if (options.interactiveEngine && child.pid) {
        trackDetachedChildPid(child.pid);
        child.once("exit", () => untrackDetachedChildPid(child.pid));
    }
    return child;
}
export async function terminateRpcClientProcess(child, processTree) {
    if (child.exitCode !== null || child.signalCode !== null)
        return;
    let resolveExit;
    const exited = new Promise((resolve) => { resolveExit = resolve; });
    child.once("exit", resolveExit);
    const guardianFile = guardianFiles.get(child);
    child.kill("SIGTERM");
    if (await Promise.race([exited.then(() => true), sleep(250).then(() => false)])) {
        if (guardianFile)
            await rm(guardianFile, { force: true });
        return;
    }
    if (processTree && guardianFile) {
        await writeFile(guardianFile, "stop");
        if (await Promise.race([exited.then(() => true), sleep(500).then(() => false)])) {
            await rm(guardianFile, { force: true });
            return;
        }
    }
    if (processTree && child.pid)
        killProcessTree(child.pid);
    else
        child.kill("SIGKILL");
    if (!(await Promise.race([exited.then(() => true), sleep(250).then(() => false)]))) {
        throw new Error(`Agent process ${child.pid ?? "unknown"} did not exit after SIGKILL`);
    }
    if (guardianFile)
        await rm(guardianFile, { force: true });
}
export function createInteractiveJsonlOptions(enabled, onDiagnostic) {
    if (!enabled)
        return {};
    return {
        maxBytesPerTurn: 256 * 1024,
        maxFrameBytes: INTERACTIVE_ENGINE_MAX_FRAME_BYTES,
        onOversizedLine: () => onDiagnostic?.({
            activity: undefined,
            elapsedMs: 0,
            level: "unresponsive",
            message: "Interactive engine violated the 1 MiB protocol frame limit; pending requests were cancelled",
        }),
    };
}
//# sourceMappingURL=rpc-client-process.js.map