openclaw
Version:
Multi-channel AI gateway with extensible messaging integrations
155 lines (154 loc) • 4.74 kB
JavaScript
import { c as isRecord } from "../../record-coerce-DItp3I4t.js";
import { l as normalizeOptionalString } from "../../string-coerce-CIXf7egm.js";
import { n as signalProcessTree } from "../../kill-tree-CR2oLt9D.js";
import { a as resolveWindowsSpawnProgram, r as materializeWindowsSpawnProgram } from "../../windows-spawn-oyE-2b7Z.js";
import "../../string-coerce-runtime-GQa0ehRA.js";
import "../../process-runtime-pcN9RjT8.js";
import { spawn } from "node:child_process";
//#region extensions/openai/package.json
var version = "2026.9.2";
//#endregion
//#region extensions/openai/cli-auth-api.ts
function projectCodexCliAccount(response) {
const account = response.account;
if (account === null && typeof response.requiresOpenaiAuth === "boolean") return {
type: "none",
requiresOpenaiAuth: response.requiresOpenaiAuth
};
if (!isRecord(account) || typeof account.type !== "string") return null;
if (account.type === "apiKey") return { type: "apiKey" };
if (account.type !== "chatgpt") return { type: "unknown" };
const email = normalizeOptionalString(account.email);
return {
type: "chatgpt",
...email && email.length <= 320 && !/[\r\n]/u.test(email) ? { email } : {}
};
}
/** Reads the native account before setup has installed a harness or configured an agent. */
async function readCodexCliAccount(params) {
const env = params.env ?? process.env;
if (env !== process.env && !env.CODEX_HOME?.trim() && (process.platform === "win32" || !env.HOME?.trim())) return null;
try {
const program = resolveWindowsSpawnProgram({
command: params.command,
env,
packageName: "@openai/codex"
});
const invocation = materializeWindowsSpawnProgram(program, [
"app-server",
"--listen",
"stdio://"
]);
const detached = process.platform !== "win32";
const child = spawn(invocation.command, invocation.argv, {
env,
detached,
stdio: [
"pipe",
"pipe",
"ignore"
],
shell: invocation.shell,
windowsHide: invocation.windowsHide ?? true
});
return await new Promise((resolve) => {
let phase = "initialize";
let result = null;
let output = "";
let outputBytes = 0;
let cleanupTimer;
const finish = () => {
if (phase === "closed") return;
phase = "closed";
clearTimeout(timer);
clearTimeout(cleanupTimer);
const complete = () => {
if (!detached && child.exitCode === null && child.signalCode === null) child.kill("SIGKILL");
child.stdin.destroy();
child.stdout.destroy();
child.unref();
resolve(result);
};
if (child.pid && (detached || child.exitCode === null && child.signalCode === null)) signalProcessTree(child.pid, "SIGKILL", {
detached,
onComplete: complete
});
else complete();
};
const stop = (account) => {
if (phase === "closing" || phase === "closed") return;
phase = "closing";
result = account;
output = "";
if (!detached || !child.pid) {
finish();
return;
}
signalProcessTree(child.pid, "SIGTERM", { detached });
cleanupTimer = setTimeout(finish, 200);
};
const timer = setTimeout(finish, 3e3);
const send = (messages) => {
try {
child.stdin.write(`${messages.map((message) => JSON.stringify(message)).join("\n")}\n`);
} catch {
stop(null);
}
};
child.once("error", () => stop(null));
child.once("close", finish);
child.stdin.on("error", () => stop(null));
child.stdout.on("error", () => stop(null));
child.stdout.setEncoding("utf8");
child.stdout.on("data", (chunk) => {
if (phase === "closing" || phase === "closed") return;
outputBytes += Buffer.byteLength(chunk);
if (outputBytes > 65536) {
stop(null);
return;
}
output += chunk;
let newline;
while ((newline = output.indexOf("\n")) !== -1) {
const line = output.slice(0, newline);
output = output.slice(newline + 1);
try {
const message = JSON.parse(line);
if (!isRecord(message) || "method" in message || message.id !== (phase === "initialize" ? 1 : 2)) continue;
if (message.error || !isRecord(message.result)) {
stop(null);
return;
}
if (phase === "initialize") {
phase = "account";
send([{ method: "initialized" }, {
id: 2,
method: "account/read",
params: { refreshToken: false }
}]);
} else {
stop(projectCodexCliAccount(message.result));
return;
}
} catch {
stop(null);
return;
}
}
});
send([{
id: 1,
method: "initialize",
params: { clientInfo: {
name: "openclaw",
title: "OpenClaw",
version
} }
}]);
});
} catch {
return null;
}
}
//#endregion
export { readCodexCliAccount };