better-opencode-openai-codex-auth 0.1.2 → 0.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/config/README.md +19 -93
- package/config/opencode-modern.json +149 -42
- package/dist/index.d.ts +0 -12
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +195 -94
- package/dist/index.js.map +1 -1
- package/dist/lib/account-pool.d.ts +29 -3
- package/dist/lib/account-pool.d.ts.map +1 -1
- package/dist/lib/account-pool.js +210 -47
- package/dist/lib/account-pool.js.map +1 -1
- package/dist/lib/auth/auth.d.ts +55 -4
- package/dist/lib/auth/auth.d.ts.map +1 -1
- package/dist/lib/auth/auth.js +130 -6
- package/dist/lib/auth/auth.js.map +1 -1
- package/dist/lib/auth/ui/account-menu.d.ts +50 -0
- package/dist/lib/auth/ui/account-menu.d.ts.map +1 -0
- package/dist/lib/auth/ui/account-menu.js +258 -0
- package/dist/lib/auth/ui/account-menu.js.map +1 -0
- package/dist/lib/auth/ui/ansi.d.ts +23 -0
- package/dist/lib/auth/ui/ansi.d.ts.map +1 -0
- package/dist/lib/auth/ui/ansi.js +37 -0
- package/dist/lib/auth/ui/ansi.js.map +1 -0
- package/dist/lib/auth/ui/confirm.d.ts +2 -0
- package/dist/lib/auth/ui/confirm.d.ts.map +1 -0
- package/dist/lib/auth/ui/confirm.js +8 -0
- package/dist/lib/auth/ui/confirm.js.map +1 -0
- package/dist/lib/auth/ui/select.d.ts +21 -0
- package/dist/lib/auth/ui/select.d.ts.map +1 -0
- package/dist/lib/auth/ui/select.js +208 -0
- package/dist/lib/auth/ui/select.js.map +1 -0
- package/dist/lib/constants.d.ts +51 -3
- package/dist/lib/constants.d.ts.map +1 -1
- package/dist/lib/constants.js +55 -3
- package/dist/lib/constants.js.map +1 -1
- package/dist/lib/refresh-queue.d.ts +56 -0
- package/dist/lib/refresh-queue.d.ts.map +1 -0
- package/dist/lib/refresh-queue.js +148 -0
- package/dist/lib/refresh-queue.js.map +1 -0
- package/dist/lib/request/fetch-helpers.d.ts +2 -1
- package/dist/lib/request/fetch-helpers.d.ts.map +1 -1
- package/dist/lib/request/fetch-helpers.js +23 -3
- package/dist/lib/request/fetch-helpers.js.map +1 -1
- package/dist/lib/types.d.ts +18 -2
- package/dist/lib/types.d.ts.map +1 -1
- package/package.json +1 -2
- package/scripts/install-opencode-codex-auth.js +7 -27
- package/config/opencode-legacy.json +0 -571
package/dist/lib/auth/auth.js
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import { generatePKCE } from "@openauthjs/openauth/pkce";
|
|
2
2
|
import { randomBytes } from "node:crypto";
|
|
3
|
+
import { DEVICE_AUTH } from "../constants.js";
|
|
3
4
|
// OAuth constants (from openai/codex)
|
|
4
5
|
export const CLIENT_ID = "app_EMoamEEZ73f0CkXaXp7hrann";
|
|
5
6
|
export const AUTHORIZE_URL = "https://auth.openai.com/oauth/authorize";
|
|
6
7
|
export const TOKEN_URL = "https://auth.openai.com/oauth/token";
|
|
7
8
|
export const REDIRECT_URI = "http://localhost:1455/auth/callback";
|
|
8
9
|
export const SCOPE = "openid profile email offline_access";
|
|
10
|
+
const refreshInFlight = new Map();
|
|
9
11
|
/**
|
|
10
12
|
* Generate a random state value for OAuth flow
|
|
11
13
|
* @returns Random hex string
|
|
@@ -44,11 +46,14 @@ export function parseAuthorizationInput(input) {
|
|
|
44
46
|
return { code: value };
|
|
45
47
|
}
|
|
46
48
|
/**
|
|
47
|
-
* Exchange authorization code for access and refresh tokens
|
|
49
|
+
* Exchange authorization code for access and refresh tokens.
|
|
50
|
+
* Captures id_token when returned — it contains chatgpt_account_id as a
|
|
51
|
+
* dedicated JWT claim, making account-ID extraction more reliable.
|
|
52
|
+
*
|
|
48
53
|
* @param code - Authorization code from OAuth flow
|
|
49
54
|
* @param verifier - PKCE verifier
|
|
50
55
|
* @param redirectUri - OAuth redirect URI
|
|
51
|
-
* @returns Token result
|
|
56
|
+
* @returns Token result (includes id_token when available)
|
|
52
57
|
*/
|
|
53
58
|
export async function exchangeAuthorizationCode(code, verifier, redirectUri = REDIRECT_URI) {
|
|
54
59
|
const res = await fetch(TOKEN_URL, {
|
|
@@ -79,6 +84,7 @@ export async function exchangeAuthorizationCode(code, verifier, redirectUri = RE
|
|
|
79
84
|
access: json.access_token,
|
|
80
85
|
refresh: json.refresh_token,
|
|
81
86
|
expires: Date.now() + json.expires_in * 1000,
|
|
87
|
+
id_token: json.id_token,
|
|
82
88
|
};
|
|
83
89
|
}
|
|
84
90
|
/**
|
|
@@ -92,7 +98,9 @@ export function decodeJWT(token) {
|
|
|
92
98
|
if (parts.length !== 3)
|
|
93
99
|
return null;
|
|
94
100
|
const payload = parts[1];
|
|
95
|
-
|
|
101
|
+
if (!payload)
|
|
102
|
+
return null;
|
|
103
|
+
const decoded = Buffer.from(payload, "base64url").toString("utf-8");
|
|
96
104
|
const parsed = JSON.parse(decoded);
|
|
97
105
|
// Validate that the parsed payload is a non-null object
|
|
98
106
|
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
@@ -105,7 +113,56 @@ export function decodeJWT(token) {
|
|
|
105
113
|
}
|
|
106
114
|
}
|
|
107
115
|
/**
|
|
108
|
-
*
|
|
116
|
+
* Extract the ChatGPT account ID from a JWT token string.
|
|
117
|
+
* Checks (in priority order, matching first-party opencode CodexAuthPlugin):
|
|
118
|
+
* 1. Root-level chatgpt_account_id claim
|
|
119
|
+
* 2. Nested https://api.openai.com/auth.chatgpt_account_id claim
|
|
120
|
+
* 3. organizations[0].id fallback
|
|
121
|
+
*
|
|
122
|
+
* @param token - JWT string (id_token or access_token)
|
|
123
|
+
* @returns Account ID or undefined if not found
|
|
124
|
+
*/
|
|
125
|
+
export function extractAccountIdFromToken(token) {
|
|
126
|
+
if (!token)
|
|
127
|
+
return undefined;
|
|
128
|
+
const claims = decodeJWT(token);
|
|
129
|
+
if (!claims)
|
|
130
|
+
return undefined;
|
|
131
|
+
// 1. Root-level claim (most authoritative)
|
|
132
|
+
if (typeof claims.chatgpt_account_id === "string" && claims.chatgpt_account_id) {
|
|
133
|
+
return claims.chatgpt_account_id;
|
|
134
|
+
}
|
|
135
|
+
// 2. Nested claim
|
|
136
|
+
const nested = claims["https://api.openai.com/auth"];
|
|
137
|
+
if (nested?.chatgpt_account_id) {
|
|
138
|
+
return nested.chatgpt_account_id;
|
|
139
|
+
}
|
|
140
|
+
// 3. Organizations fallback
|
|
141
|
+
const orgs = claims.organizations;
|
|
142
|
+
if (Array.isArray(orgs) && orgs[0]?.id) {
|
|
143
|
+
return orgs[0].id;
|
|
144
|
+
}
|
|
145
|
+
return undefined;
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Extract account ID from a token-response object.
|
|
149
|
+
* Tries id_token first (more authoritative), then access_token.
|
|
150
|
+
*
|
|
151
|
+
* @param tokens - Object with access_token and optional id_token
|
|
152
|
+
* @returns Account ID or undefined
|
|
153
|
+
*/
|
|
154
|
+
export function extractAccountId(tokens) {
|
|
155
|
+
if (tokens.id_token) {
|
|
156
|
+
const fromIdToken = extractAccountIdFromToken(tokens.id_token);
|
|
157
|
+
if (fromIdToken)
|
|
158
|
+
return fromIdToken;
|
|
159
|
+
}
|
|
160
|
+
return extractAccountIdFromToken(tokens.access_token);
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Refresh access token using refresh token.
|
|
164
|
+
* Captures id_token when returned by the server.
|
|
165
|
+
*
|
|
109
166
|
* @param refreshToken - Refresh token
|
|
110
167
|
* @returns Token result
|
|
111
168
|
*/
|
|
@@ -136,6 +193,7 @@ export async function refreshAccessToken(refreshToken) {
|
|
|
136
193
|
access: json.access_token,
|
|
137
194
|
refresh: json.refresh_token || refreshToken,
|
|
138
195
|
expires: Date.now() + json.expires_in * 1000,
|
|
196
|
+
id_token: json.id_token,
|
|
139
197
|
};
|
|
140
198
|
}
|
|
141
199
|
catch (error) {
|
|
@@ -144,8 +202,20 @@ export async function refreshAccessToken(refreshToken) {
|
|
|
144
202
|
return { type: "failed" };
|
|
145
203
|
}
|
|
146
204
|
}
|
|
205
|
+
export function refreshAccessTokenShared(accountKey, refreshToken) {
|
|
206
|
+
const key = `${accountKey}:${refreshToken}`;
|
|
207
|
+
const existing = refreshInFlight.get(key);
|
|
208
|
+
if (existing) {
|
|
209
|
+
return existing;
|
|
210
|
+
}
|
|
211
|
+
const promise = refreshAccessToken(refreshToken).finally(() => {
|
|
212
|
+
refreshInFlight.delete(key);
|
|
213
|
+
});
|
|
214
|
+
refreshInFlight.set(key, promise);
|
|
215
|
+
return promise;
|
|
216
|
+
}
|
|
147
217
|
/**
|
|
148
|
-
* Create OAuth authorization flow
|
|
218
|
+
* Create OAuth authorization flow (browser PKCE)
|
|
149
219
|
* @returns Authorization flow details
|
|
150
220
|
*/
|
|
151
221
|
export async function createAuthorizationFlow() {
|
|
@@ -161,7 +231,61 @@ export async function createAuthorizationFlow() {
|
|
|
161
231
|
url.searchParams.set("state", state);
|
|
162
232
|
url.searchParams.set("id_token_add_organizations", "true");
|
|
163
233
|
url.searchParams.set("codex_cli_simplified_flow", "true");
|
|
164
|
-
|
|
234
|
+
// Use "opencode" — matching the first-party opencode CodexAuthPlugin (#2 fix)
|
|
235
|
+
url.searchParams.set("originator", "opencode");
|
|
165
236
|
return { pkce, state, url: url.toString() };
|
|
166
237
|
}
|
|
238
|
+
/**
|
|
239
|
+
* Create a headless/device-code authorization flow.
|
|
240
|
+
*
|
|
241
|
+
* This flow requires no browser on the machine running opencode. The user
|
|
242
|
+
* visits a URL on any device and enters a short code to authenticate.
|
|
243
|
+
* Matches the "headless" method in the first-party opencode CodexAuthPlugin.
|
|
244
|
+
*
|
|
245
|
+
* @returns Device authorization flow details
|
|
246
|
+
*/
|
|
247
|
+
export async function createDeviceAuthorizationFlow() {
|
|
248
|
+
const response = await fetch(DEVICE_AUTH.USERCODE_URL, {
|
|
249
|
+
method: "POST",
|
|
250
|
+
headers: { "Content-Type": "application/json" },
|
|
251
|
+
body: JSON.stringify({ client_id: CLIENT_ID }),
|
|
252
|
+
});
|
|
253
|
+
if (!response.ok) {
|
|
254
|
+
throw new Error(`[openai-codex-plugin] Device auth usercode request failed: ${response.status}`);
|
|
255
|
+
}
|
|
256
|
+
const data = (await response.json());
|
|
257
|
+
const serverIntervalMs = Math.max(parseInt(data.interval) || 5, 1) * 1000;
|
|
258
|
+
const pollIntervalMs = serverIntervalMs + DEVICE_AUTH.POLL_SAFETY_MARGIN_MS;
|
|
259
|
+
const poll = async () => {
|
|
260
|
+
// eslint-disable-next-line no-constant-condition
|
|
261
|
+
while (true) {
|
|
262
|
+
const tokenResponse = await fetch(DEVICE_AUTH.TOKEN_URL, {
|
|
263
|
+
method: "POST",
|
|
264
|
+
headers: { "Content-Type": "application/json" },
|
|
265
|
+
body: JSON.stringify({
|
|
266
|
+
device_auth_id: data.device_auth_id,
|
|
267
|
+
user_code: data.user_code,
|
|
268
|
+
}),
|
|
269
|
+
});
|
|
270
|
+
if (tokenResponse.ok) {
|
|
271
|
+
const tokenData = (await tokenResponse.json());
|
|
272
|
+
// Exchange the authorization_code for final tokens
|
|
273
|
+
return exchangeAuthorizationCode(tokenData.authorization_code, tokenData.code_verifier, DEVICE_AUTH.REDIRECT_URI);
|
|
274
|
+
}
|
|
275
|
+
// 403 / 404 = still waiting for user to complete auth
|
|
276
|
+
if (tokenResponse.status !== 403 && tokenResponse.status !== 404) {
|
|
277
|
+
console.error(`[openai-codex-plugin] Device token poll failed: ${tokenResponse.status}`);
|
|
278
|
+
return { type: "failed" };
|
|
279
|
+
}
|
|
280
|
+
// Wait before next poll
|
|
281
|
+
await new Promise((r) => setTimeout(r, pollIntervalMs));
|
|
282
|
+
}
|
|
283
|
+
};
|
|
284
|
+
return {
|
|
285
|
+
activateUrl: DEVICE_AUTH.ACTIVATE_URL,
|
|
286
|
+
userCode: data.user_code,
|
|
287
|
+
pollIntervalMs,
|
|
288
|
+
poll,
|
|
289
|
+
};
|
|
290
|
+
}
|
|
167
291
|
//# sourceMappingURL=auth.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../../../lib/auth/auth.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AACzD,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../../../lib/auth/auth.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Account pool management UI for the Codex OAuth plugin.
|
|
3
|
+
*
|
|
4
|
+
* Shown when the user runs `opencode auth login` and existing accounts
|
|
5
|
+
* are already in the pool. Provides TTY-interactive menu on terminals;
|
|
6
|
+
* falls back to a plain readline prompt on headless/non-TTY environments.
|
|
7
|
+
*
|
|
8
|
+
* Inspired by NoeFabris/opencode-antigravity-auth ui/auth-menu.ts.
|
|
9
|
+
*/
|
|
10
|
+
import type { AccountPoolEntry } from "../../types.js";
|
|
11
|
+
import { AccountPool } from "../../account-pool.js";
|
|
12
|
+
export type AccountStatus = "active" | "rate-limited" | "cooling-down" | "expired" | "unknown";
|
|
13
|
+
export interface DisplayAccount {
|
|
14
|
+
entry: AccountPoolEntry;
|
|
15
|
+
index: number;
|
|
16
|
+
status: AccountStatus;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Derive a human-readable status from pool entry timestamps.
|
|
20
|
+
*/
|
|
21
|
+
export declare function getAccountStatus(entry: AccountPoolEntry): AccountStatus;
|
|
22
|
+
export type ManageResult = {
|
|
23
|
+
action: "add";
|
|
24
|
+
} | {
|
|
25
|
+
action: "delete-one";
|
|
26
|
+
index: number;
|
|
27
|
+
} | {
|
|
28
|
+
action: "delete-all";
|
|
29
|
+
} | {
|
|
30
|
+
action: "refresh-token";
|
|
31
|
+
index: number;
|
|
32
|
+
} | {
|
|
33
|
+
action: "done";
|
|
34
|
+
};
|
|
35
|
+
/**
|
|
36
|
+
* Show the account management menu.
|
|
37
|
+
*
|
|
38
|
+
* Loads the current pool, displays it with live status, and applies the
|
|
39
|
+
* user's chosen action (delete, refresh-token, delete-all, or add).
|
|
40
|
+
*
|
|
41
|
+
* Returns the final `ManageResult` after the user is done. Callers should
|
|
42
|
+
* loop as long as `action !== "done"` && `action !== "add"`.
|
|
43
|
+
*/
|
|
44
|
+
export declare function showAccountManager(): Promise<ManageResult>;
|
|
45
|
+
/**
|
|
46
|
+
* Apply a ManageResult to the pool and persist.
|
|
47
|
+
* Returns true if the caller should proceed to add a new account.
|
|
48
|
+
*/
|
|
49
|
+
export declare function applyManageResult(result: ManageResult, pool: AccountPool): boolean;
|
|
50
|
+
//# sourceMappingURL=account-menu.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"account-menu.d.ts","sourceRoot":"","sources":["../../../../lib/auth/ui/account-menu.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAMH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AACvD,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAEpD,MAAM,MAAM,aAAa,GAAG,QAAQ,GAAG,cAAc,GAAG,cAAc,GAAG,SAAS,GAAG,SAAS,CAAC;AAE/F,MAAM,WAAW,cAAc;IAC9B,KAAK,EAAE,gBAAgB,CAAC;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,aAAa,CAAC;CACtB;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,gBAAgB,GAAG,aAAa,CAMvE;AAgLD,MAAM,MAAM,YAAY,GACrB;IAAE,MAAM,EAAE,KAAK,CAAA;CAAE,GACjB;IAAE,MAAM,EAAE,YAAY,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GACvC;IAAE,MAAM,EAAE,YAAY,CAAA;CAAE,GACxB;IAAE,MAAM,EAAE,eAAe,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAC1C;IAAE,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAEtB;;;;;;;;GAQG;AACH,wBAAsB,kBAAkB,IAAI,OAAO,CAAC,YAAY,CAAC,CAkDhE;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,YAAY,EAAE,IAAI,EAAE,WAAW,GAAG,OAAO,CAuBlF"}
|
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Account pool management UI for the Codex OAuth plugin.
|
|
3
|
+
*
|
|
4
|
+
* Shown when the user runs `opencode auth login` and existing accounts
|
|
5
|
+
* are already in the pool. Provides TTY-interactive menu on terminals;
|
|
6
|
+
* falls back to a plain readline prompt on headless/non-TTY environments.
|
|
7
|
+
*
|
|
8
|
+
* Inspired by NoeFabris/opencode-antigravity-auth ui/auth-menu.ts.
|
|
9
|
+
*/
|
|
10
|
+
import { createInterface } from "node:readline/promises";
|
|
11
|
+
import { ANSI, isTTY } from "./ansi.js";
|
|
12
|
+
import { select } from "./select.js";
|
|
13
|
+
import { confirm } from "./confirm.js";
|
|
14
|
+
import { AccountPool } from "../../account-pool.js";
|
|
15
|
+
/**
|
|
16
|
+
* Derive a human-readable status from pool entry timestamps.
|
|
17
|
+
*/
|
|
18
|
+
export function getAccountStatus(entry) {
|
|
19
|
+
const now = Date.now();
|
|
20
|
+
if (entry.rateLimitedUntil && entry.rateLimitedUntil > now)
|
|
21
|
+
return "rate-limited";
|
|
22
|
+
if (entry.coolingDownUntil && entry.coolingDownUntil > now)
|
|
23
|
+
return "cooling-down";
|
|
24
|
+
if (entry.expires < now)
|
|
25
|
+
return "expired";
|
|
26
|
+
return "active";
|
|
27
|
+
}
|
|
28
|
+
function statusBadge(status) {
|
|
29
|
+
switch (status) {
|
|
30
|
+
case "active": return `${ANSI.green}[active]${ANSI.reset}`;
|
|
31
|
+
case "rate-limited": return `${ANSI.yellow}[rate-limited]${ANSI.reset}`;
|
|
32
|
+
case "cooling-down": return `${ANSI.yellow}[cooling-down]${ANSI.reset}`;
|
|
33
|
+
case "expired": return `${ANSI.red}[expired]${ANSI.reset}`;
|
|
34
|
+
default: return `${ANSI.dim}[unknown]${ANSI.reset}`;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
function relativeTime(ts) {
|
|
38
|
+
if (!ts)
|
|
39
|
+
return "never";
|
|
40
|
+
const diff = Date.now() - ts;
|
|
41
|
+
const mins = Math.floor(diff / 60_000);
|
|
42
|
+
if (mins < 1)
|
|
43
|
+
return "just now";
|
|
44
|
+
if (mins < 60)
|
|
45
|
+
return `${mins}m ago`;
|
|
46
|
+
const hrs = Math.floor(mins / 60);
|
|
47
|
+
if (hrs < 24)
|
|
48
|
+
return `${hrs}h ago`;
|
|
49
|
+
const days = Math.floor(hrs / 24);
|
|
50
|
+
if (days < 7)
|
|
51
|
+
return `${days}d ago`;
|
|
52
|
+
return new Date(ts).toLocaleDateString();
|
|
53
|
+
}
|
|
54
|
+
function countdownTime(until) {
|
|
55
|
+
if (!until)
|
|
56
|
+
return "";
|
|
57
|
+
const ms = until - Date.now();
|
|
58
|
+
if (ms <= 0)
|
|
59
|
+
return "";
|
|
60
|
+
const secs = Math.ceil(ms / 1000);
|
|
61
|
+
if (secs < 60)
|
|
62
|
+
return ` (${secs}s)`;
|
|
63
|
+
return ` (${Math.ceil(secs / 60)}m)`;
|
|
64
|
+
}
|
|
65
|
+
async function showMainMenu(accounts) {
|
|
66
|
+
const items = [
|
|
67
|
+
{ label: "Actions", value: { type: "cancel" }, kind: "heading" },
|
|
68
|
+
{ label: "Add another account", value: { type: "add" }, color: "cyan" },
|
|
69
|
+
{ label: "", value: { type: "cancel" }, separator: true },
|
|
70
|
+
{ label: `Accounts (${accounts.length})`, value: { type: "cancel" }, kind: "heading" },
|
|
71
|
+
...accounts.map((acc) => {
|
|
72
|
+
const label = acc.entry.email || `Account ${acc.index + 1}`;
|
|
73
|
+
const badge = statusBadge(acc.status);
|
|
74
|
+
const countdown = acc.status !== "active" ? countdownTime(acc.entry.rateLimitedUntil ?? acc.entry.coolingDownUntil) : "";
|
|
75
|
+
return {
|
|
76
|
+
label: `${acc.index + 1}. ${label} ${badge}${countdown}`,
|
|
77
|
+
hint: acc.entry.lastUsed ? relativeTime(acc.entry.lastUsed) : "",
|
|
78
|
+
value: { type: "select", account: acc },
|
|
79
|
+
};
|
|
80
|
+
}),
|
|
81
|
+
{ label: "", value: { type: "cancel" }, separator: true },
|
|
82
|
+
{ label: "Danger zone", value: { type: "cancel" }, kind: "heading" },
|
|
83
|
+
{ label: "Delete all accounts", value: { type: "delete-all" }, color: "red" },
|
|
84
|
+
];
|
|
85
|
+
while (true) {
|
|
86
|
+
const result = await select(items, {
|
|
87
|
+
message: "OpenAI Codex accounts",
|
|
88
|
+
subtitle: "Select an action or account",
|
|
89
|
+
clearScreen: true,
|
|
90
|
+
});
|
|
91
|
+
if (!result)
|
|
92
|
+
return { type: "cancel" };
|
|
93
|
+
if (result.type === "delete-all") {
|
|
94
|
+
const confirmed = await confirm("Delete ALL accounts? This cannot be undone.");
|
|
95
|
+
if (!confirmed)
|
|
96
|
+
continue;
|
|
97
|
+
}
|
|
98
|
+
return result;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
async function showAccountDetail(acc) {
|
|
102
|
+
const label = acc.entry.email || `Account ${acc.index + 1}`;
|
|
103
|
+
const badge = statusBadge(acc.status);
|
|
104
|
+
while (true) {
|
|
105
|
+
const result = await select([
|
|
106
|
+
{ label: "Back", value: "back" },
|
|
107
|
+
{ label: "Refresh token (re-authenticate)", value: "refresh-token", color: "cyan" },
|
|
108
|
+
{ label: "Delete this account", value: "delete", color: "red" },
|
|
109
|
+
], {
|
|
110
|
+
message: `${label} ${badge}`,
|
|
111
|
+
subtitle: [
|
|
112
|
+
`ID: ${acc.entry.accountId}`,
|
|
113
|
+
`Last used: ${relativeTime(acc.entry.lastUsed)}`,
|
|
114
|
+
`Expires: ${new Date(acc.entry.expires).toLocaleString()}`,
|
|
115
|
+
].join(" | "),
|
|
116
|
+
clearScreen: true,
|
|
117
|
+
});
|
|
118
|
+
if (result === "delete") {
|
|
119
|
+
const confirmed = await confirm(`Delete ${label}?`);
|
|
120
|
+
if (!confirmed)
|
|
121
|
+
continue;
|
|
122
|
+
}
|
|
123
|
+
if (result === "refresh-token") {
|
|
124
|
+
const confirmed = await confirm(`Re-authenticate ${label}? You will be redirected to log in again.`);
|
|
125
|
+
if (!confirmed)
|
|
126
|
+
continue;
|
|
127
|
+
}
|
|
128
|
+
return result ?? "cancel";
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
// ---------------------------------------------------------------------------
|
|
132
|
+
// Fallback for non-TTY (headless server)
|
|
133
|
+
// ---------------------------------------------------------------------------
|
|
134
|
+
async function showMenuFallback(accounts) {
|
|
135
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
136
|
+
try {
|
|
137
|
+
process.stdout.write("\n");
|
|
138
|
+
process.stdout.write(` OpenAI Codex accounts (${accounts.length})\n`);
|
|
139
|
+
process.stdout.write(" ─────────────────────────────\n");
|
|
140
|
+
for (const acc of accounts) {
|
|
141
|
+
const label = acc.entry.email || `Account ${acc.index + 1}`;
|
|
142
|
+
const status = acc.status;
|
|
143
|
+
process.stdout.write(` ${acc.index + 1}. ${label} [${status}] last used: ${relativeTime(acc.entry.lastUsed)}\n`);
|
|
144
|
+
}
|
|
145
|
+
process.stdout.write("\n");
|
|
146
|
+
while (true) {
|
|
147
|
+
const answer = await rl.question(" (a)dd account (d)elete <n> (da) delete all (q)uit: ");
|
|
148
|
+
const parts = answer.trim().toLowerCase().split(/\s+/);
|
|
149
|
+
const cmd = parts[0] ?? "";
|
|
150
|
+
if (cmd === "a" || cmd === "add")
|
|
151
|
+
return { action: "add" };
|
|
152
|
+
if (cmd === "q" || cmd === "quit" || cmd === "")
|
|
153
|
+
return { action: "done" };
|
|
154
|
+
if ((cmd === "da" || cmd === "delete-all")) {
|
|
155
|
+
const confirm = await rl.question(" Delete ALL accounts? (yes/no): ");
|
|
156
|
+
if (confirm.trim().toLowerCase() === "yes")
|
|
157
|
+
return { action: "delete-all" };
|
|
158
|
+
continue;
|
|
159
|
+
}
|
|
160
|
+
if (cmd === "d" || cmd === "delete") {
|
|
161
|
+
const idxStr = parts[1];
|
|
162
|
+
const idx = idxStr ? parseInt(idxStr, 10) - 1 : NaN;
|
|
163
|
+
if (Number.isNaN(idx) || idx < 0 || idx >= accounts.length) {
|
|
164
|
+
process.stdout.write(" Usage: d <account number>\n");
|
|
165
|
+
continue;
|
|
166
|
+
}
|
|
167
|
+
const label = accounts[idx].entry.email || `Account ${idx + 1}`;
|
|
168
|
+
const confirmStr = await rl.question(` Delete ${label}? (yes/no): `);
|
|
169
|
+
if (confirmStr.trim().toLowerCase() === "yes") {
|
|
170
|
+
return { action: "delete-one", index: idx };
|
|
171
|
+
}
|
|
172
|
+
continue;
|
|
173
|
+
}
|
|
174
|
+
process.stdout.write(" Unknown command. Try: a | d <n> | da | q\n");
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
finally {
|
|
178
|
+
rl.close();
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* Show the account management menu.
|
|
183
|
+
*
|
|
184
|
+
* Loads the current pool, displays it with live status, and applies the
|
|
185
|
+
* user's chosen action (delete, refresh-token, delete-all, or add).
|
|
186
|
+
*
|
|
187
|
+
* Returns the final `ManageResult` after the user is done. Callers should
|
|
188
|
+
* loop as long as `action !== "done"` && `action !== "add"`.
|
|
189
|
+
*/
|
|
190
|
+
export async function showAccountManager() {
|
|
191
|
+
const pool = AccountPool.load();
|
|
192
|
+
const accounts = pool.getAccounts();
|
|
193
|
+
if (accounts.length === 0) {
|
|
194
|
+
process.stdout.write("\n No accounts in pool — proceeding to add one.\n\n");
|
|
195
|
+
return { action: "add" };
|
|
196
|
+
}
|
|
197
|
+
const displayAccounts = accounts.map((entry, index) => ({
|
|
198
|
+
entry,
|
|
199
|
+
index,
|
|
200
|
+
status: getAccountStatus(entry),
|
|
201
|
+
}));
|
|
202
|
+
if (!isTTY()) {
|
|
203
|
+
return showMenuFallback(displayAccounts);
|
|
204
|
+
}
|
|
205
|
+
// TTY interactive loop
|
|
206
|
+
while (true) {
|
|
207
|
+
const mainAction = await showMainMenu(displayAccounts);
|
|
208
|
+
if (mainAction.type === "cancel")
|
|
209
|
+
return { action: "done" };
|
|
210
|
+
if (mainAction.type === "add")
|
|
211
|
+
return { action: "add" };
|
|
212
|
+
if (mainAction.type === "delete-all") {
|
|
213
|
+
// Remove all accounts from pool and save
|
|
214
|
+
for (let i = accounts.length - 1; i >= 0; i--) {
|
|
215
|
+
accounts.splice(i, 1);
|
|
216
|
+
}
|
|
217
|
+
pool.save();
|
|
218
|
+
process.stdout.write("\n All accounts removed.\n\n");
|
|
219
|
+
return { action: "add" };
|
|
220
|
+
}
|
|
221
|
+
if (mainAction.type === "select") {
|
|
222
|
+
const detail = await showAccountDetail(mainAction.account);
|
|
223
|
+
if (detail === "back")
|
|
224
|
+
continue;
|
|
225
|
+
if (detail === "delete") {
|
|
226
|
+
return { action: "delete-one", index: mainAction.account.index };
|
|
227
|
+
}
|
|
228
|
+
if (detail === "refresh-token") {
|
|
229
|
+
return { action: "refresh-token", index: mainAction.account.index };
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
/**
|
|
235
|
+
* Apply a ManageResult to the pool and persist.
|
|
236
|
+
* Returns true if the caller should proceed to add a new account.
|
|
237
|
+
*/
|
|
238
|
+
export function applyManageResult(result, pool) {
|
|
239
|
+
const accounts = pool.getAccounts();
|
|
240
|
+
if (result.action === "delete-one") {
|
|
241
|
+
accounts.splice(result.index, 1);
|
|
242
|
+
pool.save();
|
|
243
|
+
const label = accounts[result.index]?.email || `Account ${result.index + 1}`;
|
|
244
|
+
process.stdout.write(`\n Account removed.\n\n`);
|
|
245
|
+
return false;
|
|
246
|
+
}
|
|
247
|
+
if (result.action === "delete-all") {
|
|
248
|
+
accounts.splice(0, accounts.length);
|
|
249
|
+
pool.save();
|
|
250
|
+
process.stdout.write("\n All accounts removed.\n\n");
|
|
251
|
+
return true; // proceed to add
|
|
252
|
+
}
|
|
253
|
+
if (result.action === "add" || result.action === "refresh-token") {
|
|
254
|
+
return true;
|
|
255
|
+
}
|
|
256
|
+
return false;
|
|
257
|
+
}
|
|
258
|
+
//# sourceMappingURL=account-menu.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"account-menu.js","sourceRoot":"","sources":["../../../../lib/auth/ui/account-menu.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ANSI escape codes and key parsing for interactive CLI menus.
|
|
3
|
+
* Ported from NoeFabris/opencode-antigravity-auth with minor adaptations.
|
|
4
|
+
*/
|
|
5
|
+
export declare const ANSI: {
|
|
6
|
+
readonly hide: "\u001B[?25l";
|
|
7
|
+
readonly show: "\u001B[?25h";
|
|
8
|
+
readonly up: (n?: number) => string;
|
|
9
|
+
readonly clearLine: "\u001B[2K";
|
|
10
|
+
readonly clearScreen: "\u001B[2J";
|
|
11
|
+
readonly moveTo: (row: number, col: number) => string;
|
|
12
|
+
readonly cyan: "\u001B[36m";
|
|
13
|
+
readonly green: "\u001B[32m";
|
|
14
|
+
readonly red: "\u001B[31m";
|
|
15
|
+
readonly yellow: "\u001B[33m";
|
|
16
|
+
readonly dim: "\u001B[2m";
|
|
17
|
+
readonly bold: "\u001B[1m";
|
|
18
|
+
readonly reset: "\u001B[0m";
|
|
19
|
+
};
|
|
20
|
+
export type KeyAction = "up" | "down" | "enter" | "escape" | "escape-start" | null;
|
|
21
|
+
export declare function parseKey(data: Buffer): KeyAction;
|
|
22
|
+
export declare function isTTY(): boolean;
|
|
23
|
+
//# sourceMappingURL=ansi.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ansi.d.ts","sourceRoot":"","sources":["../../../../lib/auth/ui/ansi.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,eAAO,MAAM,IAAI;;;;;;2BAMF,MAAM,OAAO,MAAM;;;;;;;;CAQxB,CAAC;AAEX,MAAM,MAAM,SAAS,GAAG,IAAI,GAAG,MAAM,GAAG,OAAO,GAAG,QAAQ,GAAG,cAAc,GAAG,IAAI,CAAC;AAEnF,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,CAQhD;AAED,wBAAgB,KAAK,IAAI,OAAO,CAE/B"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ANSI escape codes and key parsing for interactive CLI menus.
|
|
3
|
+
* Ported from NoeFabris/opencode-antigravity-auth with minor adaptations.
|
|
4
|
+
*/
|
|
5
|
+
export const ANSI = {
|
|
6
|
+
hide: "\x1b[?25l",
|
|
7
|
+
show: "\x1b[?25h",
|
|
8
|
+
up: (n = 1) => `\x1b[${n}A`,
|
|
9
|
+
clearLine: "\x1b[2K",
|
|
10
|
+
clearScreen: "\x1b[2J",
|
|
11
|
+
moveTo: (row, col) => `\x1b[${row};${col}H`,
|
|
12
|
+
cyan: "\x1b[36m",
|
|
13
|
+
green: "\x1b[32m",
|
|
14
|
+
red: "\x1b[31m",
|
|
15
|
+
yellow: "\x1b[33m",
|
|
16
|
+
dim: "\x1b[2m",
|
|
17
|
+
bold: "\x1b[1m",
|
|
18
|
+
reset: "\x1b[0m",
|
|
19
|
+
};
|
|
20
|
+
export function parseKey(data) {
|
|
21
|
+
const s = data.toString();
|
|
22
|
+
if (s === "\x1b[A" || s === "\x1bOA")
|
|
23
|
+
return "up";
|
|
24
|
+
if (s === "\x1b[B" || s === "\x1bOB")
|
|
25
|
+
return "down";
|
|
26
|
+
if (s === "\r" || s === "\n")
|
|
27
|
+
return "enter";
|
|
28
|
+
if (s === "\x03")
|
|
29
|
+
return "escape";
|
|
30
|
+
if (s === "\x1b")
|
|
31
|
+
return "escape-start";
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
export function isTTY() {
|
|
35
|
+
return Boolean(process.stdin.isTTY);
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=ansi.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ansi.js","sourceRoot":"","sources":["../../../../lib/auth/ui/ansi.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,CAAC,MAAM,IAAI,GAAG;IACnB,IAAI,EAAE,WAAW;IACjB,IAAI,EAAE,WAAW;IACjB,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,QAAQ,CAAC,GAAG;IAC3B,SAAS,EAAE,SAAS;IACpB,WAAW,EAAE,SAAS;IACtB,MAAM,EAAE,CAAC,GAAW,EAAE,GAAW,EAAE,EAAE,CAAC,QAAQ,GAAG,IAAI,GAAG,GAAG;IAC3D,IAAI,EAAE,UAAU;IAChB,KAAK,EAAE,UAAU;IACjB,GAAG,EAAE,UAAU;IACf,MAAM,EAAE,UAAU;IAClB,GAAG,EAAE,SAAS;IACd,IAAI,EAAE,SAAS;IACf,KAAK,EAAE,SAAS;CACP,CAAC;AAIX,MAAM,UAAU,QAAQ,CAAC,IAAY;IACpC,MAAM,CAAC,GAAG,IAAI,CAAC,QAAQ,EAAE,CAAC;IAC1B,IAAI,CAAC,KAAK,QAAQ,IAAI,CAAC,KAAK,QAAQ;QAAE,OAAO,IAAI,CAAC;IAClD,IAAI,CAAC,KAAK,QAAQ,IAAI,CAAC,KAAK,QAAQ;QAAE,OAAO,MAAM,CAAC;IACpD,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,IAAI;QAAE,OAAO,OAAO,CAAC;IAC7C,IAAI,CAAC,KAAK,MAAM;QAAE,OAAO,QAAQ,CAAC;IAClC,IAAI,CAAC,KAAK,MAAM;QAAE,OAAO,cAAc,CAAC;IACxC,OAAO,IAAI,CAAC;AACb,CAAC;AAED,MAAM,UAAU,KAAK;IACpB,OAAO,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;AACrC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"confirm.d.ts","sourceRoot":"","sources":["../../../../lib/auth/ui/confirm.ts"],"names":[],"mappings":"AAEA,wBAAsB,OAAO,CAAC,OAAO,EAAE,MAAM,EAAE,UAAU,UAAQ,GAAG,OAAO,CAAC,OAAO,CAAC,CAKnF"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { select } from "./select.js";
|
|
2
|
+
export async function confirm(message, defaultYes = false) {
|
|
3
|
+
const items = defaultYes
|
|
4
|
+
? [{ label: "Yes", value: true }, { label: "No", value: false }]
|
|
5
|
+
: [{ label: "No", value: false }, { label: "Yes", value: true }];
|
|
6
|
+
return (await select(items, { message })) ?? false;
|
|
7
|
+
}
|
|
8
|
+
//# sourceMappingURL=confirm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"confirm.js","sourceRoot":"","sources":["../../../../lib/auth/ui/confirm.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAErC,MAAM,CAAC,KAAK,UAAU,OAAO,CAAC,OAAe,EAAE,UAAU,GAAG,KAAK;IAChE,MAAM,KAAK,GAAG,UAAU;QACvB,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC;QAChE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IAClE,OAAO,CAAC,MAAM,MAAM,CAAC,KAAK,EAAE,EAAE,OAAO,EAAE,CAAC,CAAC,IAAI,KAAK,CAAC;AACpD,CAAC"}
|