Files
openclaw/extensions/codex/src/app-server/transport.ts
2026-04-10 23:29:58 +01:00

73 lines
2.0 KiB
TypeScript

export type CodexAppServerTransport = {
stdin: {
write: (data: string) => unknown;
end?: () => unknown;
destroy?: () => unknown;
unref?: () => unknown;
};
stdout: NodeJS.ReadableStream & {
destroy?: () => unknown;
unref?: () => unknown;
};
stderr: NodeJS.ReadableStream & {
destroy?: () => unknown;
unref?: () => unknown;
};
pid?: number;
exitCode?: number | null;
signalCode?: string | null;
killed?: boolean;
kill?: (signal?: NodeJS.Signals) => unknown;
unref?: () => unknown;
once: (event: string, listener: (...args: unknown[]) => void) => unknown;
};
export function closeCodexAppServerTransport(
child: CodexAppServerTransport,
options: { forceKillDelayMs?: number } = {},
): void {
child.stdout.destroy?.();
child.stderr.destroy?.();
child.stdin.end?.();
child.stdin.destroy?.();
signalCodexAppServerTransport(child, "SIGTERM");
const forceKillDelayMs = options.forceKillDelayMs ?? 1_000;
const forceKill = setTimeout(
() => {
if (hasCodexAppServerTransportExited(child)) {
return;
}
signalCodexAppServerTransport(child, "SIGKILL");
},
Math.max(1, forceKillDelayMs),
);
forceKill.unref?.();
child.once("exit", () => clearTimeout(forceKill));
child.unref?.();
child.stdout.unref?.();
child.stderr.unref?.();
child.stdin.unref?.();
}
function hasCodexAppServerTransportExited(child: CodexAppServerTransport): boolean {
return child.exitCode !== null && child.exitCode !== undefined
? true
: child.signalCode !== null && child.signalCode !== undefined;
}
function signalCodexAppServerTransport(
child: CodexAppServerTransport,
signal: NodeJS.Signals,
): void {
if (child.pid && process.platform !== "win32") {
try {
process.kill(-child.pid, signal);
return;
} catch {
// Fall back to the child handle. The process may already be gone or not
// be a process-group leader on older call sites.
}
}
child.kill?.(signal);
}