refactor(codex_account): 改用 Node.js 實作帳號查詢
This commit is contained in:
Executable
+122
@@ -0,0 +1,122 @@
|
||||
#!/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");
|
||||
});
|
||||
Reference in New Issue
Block a user