#!/usr/bin/env node // 透過 codex app-server 的 JSON-RPC account/read 取得目前登入帳號的 email。 // // 這是 TUI `/status` Account 欄位的程式化來源,不解析本地 OAuth token, // 而是由 codex 自身回報登入帳號。將 email 印到 stdout(取不到時印空字串)。 const { spawn } = require("node:child_process"); const readline = require("node:readline"); const timeoutSeconds = Number(process.argv[2] ?? "25"); if (!Number.isFinite(timeoutSeconds) || timeoutSeconds < 0) { console.error("timeout_seconds must be a non-negative number."); process.exit(2); } function sendJson(processHandle, message) { try { processHandle.stdin.write(`${JSON.stringify(message)}\n`); } catch { return false; } return true; } async function readAccountEmail() { const processHandle = spawn("codex", ["app-server"], { stdio: ["pipe", "pipe", "ignore"], }); let settled = false; let timer; const cleanup = () => { if (!processHandle.killed) { processHandle.kill(); } }; process.once("exit", cleanup); process.once("SIGINT", () => { cleanup(); process.exit(130); }); process.once("SIGTERM", () => { cleanup(); process.exit(143); }); return await new Promise((resolve) => { const done = (email = "") => { if (settled) { return; } settled = true; clearTimeout(timer); cleanup(); resolve(email); }; timer = setTimeout(() => done(""), timeoutSeconds * 1000); processHandle.once("error", () => done("")); processHandle.once("exit", () => done("")); processHandle.stdin.once("error", () => done("")); const lines = readline.createInterface({ input: processHandle.stdout, crlfDelay: Infinity, }); lines.on("line", (line) => { let message; try { message = JSON.parse(line); } catch { return; } if (message.id !== 2) { return; } const email = message?.result?.account?.email; done(typeof email === "string" ? email : ""); }); const messages = [ { jsonrpc: "2.0", id: 1, method: "initialize", params: { clientInfo: { name: "ci", version: "1.0" } }, }, { jsonrpc: "2.0", method: "initialized", params: {}, }, { jsonrpc: "2.0", id: 2, method: "account/read", params: {}, }, ]; for (const message of messages) { if (!sendJson(processHandle, message)) { done(""); break; } } }); } readAccountEmail() .then((email) => { process.stdout.write(`${email}\n`); }) .catch(() => { process.stdout.write("\n"); });