const DETACHED_CHILD_PROCESS = Symbol("d-pi.detachedChildProcess");
export const CHILD_PROCESS_TERMINATE_GRACE_MS = 2_000;
function isNodeErrnoException(error) {
    return typeof error === "object" && error !== null && "code" in error;
}
function isProcessStillRunning(child) {
    return child.exitCode == null && child.signalCode == null;
}
function isDetachedChildProcess(child) {
    return child[DETACHED_CHILD_PROCESS] === true;
}
export function markDetachedChildProcess(child) {
    Object.defineProperty(child, DETACHED_CHILD_PROCESS, {
        value: true,
        configurable: false,
        enumerable: false,
        writable: false,
    });
    return child;
}
export function signalChildProcessTree(child, signal) {
    if (process.platform !== "win32" && isDetachedChildProcess(child) && typeof child.pid === "number") {
        try {
            process.kill(-child.pid, signal);
            return;
        }
        catch (error) {
            if (!isNodeErrnoException(error) || error.code !== "ESRCH") {
                return;
            }
        }
    }
    try {
        child.kill(signal);
    }
    catch {
        // Best-effort process cleanup.
    }
}
export function terminateChildProcessTree(child, options = {}) {
    const signal = options.signal ?? "SIGTERM";
    const killSignal = options.killSignal ?? "SIGKILL";
    const graceMs = options.graceMs ?? CHILD_PROCESS_TERMINATE_GRACE_MS;
    signalChildProcessTree(child, signal);
    const timer = setTimeout(() => {
        if (isProcessStillRunning(child) || isDetachedChildProcess(child)) {
            signalChildProcessTree(child, killSignal);
        }
    }, graceMs);
    timer.unref?.();
}
//# sourceMappingURL=child-process-tree.js.map