better-opencode-openai-codex-auth 0.1.1 → 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.
Files changed (78) hide show
  1. package/README.md +24 -0
  2. package/config/README.md +19 -93
  3. package/config/opencode-modern.json +149 -42
  4. package/dist/index.d.ts +0 -12
  5. package/dist/index.d.ts.map +1 -1
  6. package/dist/index.js +215 -109
  7. package/dist/index.js.map +1 -1
  8. package/dist/lib/account-pool.d.ts +29 -3
  9. package/dist/lib/account-pool.d.ts.map +1 -1
  10. package/dist/lib/account-pool.js +211 -44
  11. package/dist/lib/account-pool.js.map +1 -1
  12. package/dist/lib/auth/auth.d.ts +55 -4
  13. package/dist/lib/auth/auth.d.ts.map +1 -1
  14. package/dist/lib/auth/auth.js +142 -13
  15. package/dist/lib/auth/auth.js.map +1 -1
  16. package/dist/lib/auth/server.d.ts.map +1 -1
  17. package/dist/lib/auth/server.js +12 -8
  18. package/dist/lib/auth/server.js.map +1 -1
  19. package/dist/lib/auth/ui/account-menu.d.ts +50 -0
  20. package/dist/lib/auth/ui/account-menu.d.ts.map +1 -0
  21. package/dist/lib/auth/ui/account-menu.js +258 -0
  22. package/dist/lib/auth/ui/account-menu.js.map +1 -0
  23. package/dist/lib/auth/ui/ansi.d.ts +23 -0
  24. package/dist/lib/auth/ui/ansi.d.ts.map +1 -0
  25. package/dist/lib/auth/ui/ansi.js +37 -0
  26. package/dist/lib/auth/ui/ansi.js.map +1 -0
  27. package/dist/lib/auth/ui/confirm.d.ts +2 -0
  28. package/dist/lib/auth/ui/confirm.d.ts.map +1 -0
  29. package/dist/lib/auth/ui/confirm.js +8 -0
  30. package/dist/lib/auth/ui/confirm.js.map +1 -0
  31. package/dist/lib/auth/ui/select.d.ts +21 -0
  32. package/dist/lib/auth/ui/select.d.ts.map +1 -0
  33. package/dist/lib/auth/ui/select.js +208 -0
  34. package/dist/lib/auth/ui/select.js.map +1 -0
  35. package/dist/lib/config.d.ts.map +1 -1
  36. package/dist/lib/config.js +13 -4
  37. package/dist/lib/config.js.map +1 -1
  38. package/dist/lib/constants.d.ts +76 -3
  39. package/dist/lib/constants.d.ts.map +1 -1
  40. package/dist/lib/constants.js +80 -3
  41. package/dist/lib/constants.js.map +1 -1
  42. package/dist/lib/logger.d.ts +6 -0
  43. package/dist/lib/logger.d.ts.map +1 -1
  44. package/dist/lib/logger.js +11 -2
  45. package/dist/lib/logger.js.map +1 -1
  46. package/dist/lib/prompts/codex.d.ts +1 -1
  47. package/dist/lib/prompts/codex.d.ts.map +1 -1
  48. package/dist/lib/prompts/codex.js +15 -2
  49. package/dist/lib/prompts/codex.js.map +1 -1
  50. package/dist/lib/refresh-queue.d.ts +56 -0
  51. package/dist/lib/refresh-queue.d.ts.map +1 -0
  52. package/dist/lib/refresh-queue.js +148 -0
  53. package/dist/lib/refresh-queue.js.map +1 -0
  54. package/dist/lib/request/fetch-helpers.d.ts +2 -1
  55. package/dist/lib/request/fetch-helpers.d.ts.map +1 -1
  56. package/dist/lib/request/fetch-helpers.js +25 -5
  57. package/dist/lib/request/fetch-helpers.js.map +1 -1
  58. package/dist/lib/request/helpers/input-utils.d.ts.map +1 -1
  59. package/dist/lib/request/helpers/input-utils.js +12 -10
  60. package/dist/lib/request/helpers/input-utils.js.map +1 -1
  61. package/dist/lib/request/helpers/model-map.d.ts.map +1 -1
  62. package/dist/lib/request/helpers/model-map.js +14 -1
  63. package/dist/lib/request/helpers/model-map.js.map +1 -1
  64. package/dist/lib/request/request-transformer.d.ts.map +1 -1
  65. package/dist/lib/request/request-transformer.js +33 -29
  66. package/dist/lib/request/request-transformer.js.map +1 -1
  67. package/dist/lib/request/response-handler.d.ts.map +1 -1
  68. package/dist/lib/request/response-handler.js +17 -13
  69. package/dist/lib/request/response-handler.js.map +1 -1
  70. package/dist/lib/schemas.d.ts +85 -0
  71. package/dist/lib/schemas.d.ts.map +1 -0
  72. package/dist/lib/schemas.js +93 -0
  73. package/dist/lib/schemas.js.map +1 -0
  74. package/dist/lib/types.d.ts +18 -2
  75. package/dist/lib/types.d.ts.map +1 -1
  76. package/package.json +6 -7
  77. package/scripts/install-opencode-codex-auth.js +7 -27
  78. package/config/opencode-legacy.json +0 -571
@@ -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, {
@@ -64,14 +69,14 @@ export async function exchangeAuthorizationCode(code, verifier, redirectUri = RE
64
69
  });
65
70
  if (!res.ok) {
66
71
  const text = await res.text().catch(() => "");
67
- console.error("[openai-codex-plugin] code->token failed:", res.status, text);
72
+ console.error(`[openai-codex-plugin] code->token failed: ${res.status}`, text);
68
73
  return { type: "failed" };
69
74
  }
70
75
  const json = (await res.json());
71
76
  if (!json?.access_token ||
72
77
  !json?.refresh_token ||
73
78
  typeof json?.expires_in !== "number") {
74
- console.error("[openai-codex-plugin] token response missing fields:", json);
79
+ console.error("[openai-codex-plugin] token response missing fields");
75
80
  return { type: "failed" };
76
81
  }
77
82
  return {
@@ -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,15 +98,71 @@ export function decodeJWT(token) {
92
98
  if (parts.length !== 3)
93
99
  return null;
94
100
  const payload = parts[1];
95
- const decoded = Buffer.from(payload, "base64").toString("utf-8");
96
- return JSON.parse(decoded);
101
+ if (!payload)
102
+ return null;
103
+ const decoded = Buffer.from(payload, "base64url").toString("utf-8");
104
+ const parsed = JSON.parse(decoded);
105
+ // Validate that the parsed payload is a non-null object
106
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
107
+ return null;
108
+ }
109
+ return parsed;
97
110
  }
98
111
  catch {
99
112
  return null;
100
113
  }
101
114
  }
102
115
  /**
103
- * Refresh access token using refresh token
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
+ *
104
166
  * @param refreshToken - Refresh token
105
167
  * @returns Token result
106
168
  */
@@ -117,13 +179,13 @@ export async function refreshAccessToken(refreshToken) {
117
179
  });
118
180
  if (!response.ok) {
119
181
  const text = await response.text().catch(() => "");
120
- console.error("[openai-codex-plugin] Token refresh failed:", response.status, text);
182
+ console.error(`[openai-codex-plugin] Token refresh failed: ${response.status}`, text);
121
183
  return { type: "failed" };
122
184
  }
123
185
  const json = (await response.json());
124
186
  if (!json?.access_token ||
125
187
  typeof json?.expires_in !== "number") {
126
- console.error("[openai-codex-plugin] Token refresh response missing fields:", json);
188
+ console.error("[openai-codex-plugin] Token refresh response missing fields");
127
189
  return { type: "failed" };
128
190
  }
129
191
  return {
@@ -131,16 +193,29 @@ export async function refreshAccessToken(refreshToken) {
131
193
  access: json.access_token,
132
194
  refresh: json.refresh_token || refreshToken,
133
195
  expires: Date.now() + json.expires_in * 1000,
196
+ id_token: json.id_token,
134
197
  };
135
198
  }
136
199
  catch (error) {
137
- const err = error;
138
- console.error("[openai-codex-plugin] Token refresh error:", err);
200
+ const err = error instanceof Error ? error : new Error(String(error));
201
+ console.error("[openai-codex-plugin] Token refresh error:", err.message);
139
202
  return { type: "failed" };
140
203
  }
141
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
+ }
142
217
  /**
143
- * Create OAuth authorization flow
218
+ * Create OAuth authorization flow (browser PKCE)
144
219
  * @returns Authorization flow details
145
220
  */
146
221
  export async function createAuthorizationFlow() {
@@ -156,7 +231,61 @@ export async function createAuthorizationFlow() {
156
231
  url.searchParams.set("state", state);
157
232
  url.searchParams.set("id_token_add_organizations", "true");
158
233
  url.searchParams.set("codex_cli_simplified_flow", "true");
159
- url.searchParams.set("originator", "codex_cli_rs");
234
+ // Use "opencode" — matching the first-party opencode CodexAuthPlugin (#2 fix)
235
+ url.searchParams.set("originator", "opencode");
160
236
  return { pkce, state, url: url.toString() };
161
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
+ }
162
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;AAG1C,sCAAsC;AACtC,MAAM,CAAC,MAAM,SAAS,GAAG,8BAA8B,CAAC;AACxD,MAAM,CAAC,MAAM,aAAa,GAAG,yCAAyC,CAAC;AACvE,MAAM,CAAC,MAAM,SAAS,GAAG,qCAAqC,CAAC;AAC/D,MAAM,CAAC,MAAM,YAAY,GAAG,qCAAqC,CAAC;AAClE,MAAM,CAAC,MAAM,KAAK,GAAG,qCAAqC,CAAC;AAE3D;;;GAGG;AACH,MAAM,UAAU,WAAW;IAC1B,OAAO,WAAW,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;AACxC,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,uBAAuB,CAAC,KAAa;IACpD,MAAM,KAAK,GAAG,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IACnC,IAAI,CAAC,KAAK;QAAE,OAAO,EAAE,CAAC;IAEtB,IAAI,CAAC;QACJ,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC;QAC3B,OAAO;YACN,IAAI,EAAE,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,SAAS;YAC/C,KAAK,EAAE,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,SAAS;SACjD,CAAC;IACH,CAAC;IAAC,MAAM,CAAC,CAAA,CAAC;IAEV,IAAI,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;QACzB,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;QAC1C,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;IACxB,CAAC;IACD,IAAI,KAAK,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;QAC7B,MAAM,MAAM,GAAG,IAAI,eAAe,CAAC,KAAK,CAAC,CAAC;QAC1C,OAAO;YACN,IAAI,EAAE,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,SAAS;YACrC,KAAK,EAAE,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,SAAS;SACvC,CAAC;IACH,CAAC;IACD,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;AACxB,CAAC;AAED;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,yBAAyB,CAC9C,IAAY,EACZ,QAAgB,EAChB,cAAsB,YAAY;IAElC,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,SAAS,EAAE;QAClC,MAAM,EAAE,MAAM;QACd,OAAO,EAAE,EAAE,cAAc,EAAE,mCAAmC,EAAE;QAChE,IAAI,EAAE,IAAI,eAAe,CAAC;YACzB,UAAU,EAAE,oBAAoB;YAChC,SAAS,EAAE,SAAS;YACpB,IAAI;YACJ,aAAa,EAAE,QAAQ;YACvB,YAAY,EAAE,WAAW;SACzB,CAAC;KACF,CAAC,CAAC;IACH,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;QACb,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC;QAC9C,OAAO,CAAC,KAAK,CAAC,2CAA2C,EAAE,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;QAC7E,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;IAC3B,CAAC;IACD,MAAM,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAI7B,CAAC;IACF,IACC,CAAC,IAAI,EAAE,YAAY;QACnB,CAAC,IAAI,EAAE,aAAa;QACpB,OAAO,IAAI,EAAE,UAAU,KAAK,QAAQ,EACnC,CAAC;QACF,OAAO,CAAC,KAAK,CAAC,sDAAsD,EAAE,IAAI,CAAC,CAAC;QAC5E,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;IAC3B,CAAC;IACD,OAAO;QACN,IAAI,EAAE,SAAS;QACf,MAAM,EAAE,IAAI,CAAC,YAAY;QACzB,OAAO,EAAE,IAAI,CAAC,aAAa;QAC3B,OAAO,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,UAAU,GAAG,IAAI;KAC5C,CAAC;AACH,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,SAAS,CAAC,KAAa;IACtC,IAAI,CAAC;QACJ,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAC/B,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,IAAI,CAAC;QACpC,MAAM,OAAO,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;QACzB,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;QACjE,OAAO,IAAI,CAAC,KAAK,CAAC,OAAO,CAAe,CAAC;IAC1C,CAAC;IAAC,MAAM,CAAC;QACR,OAAO,IAAI,CAAC;IACb,CAAC;AACF,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,YAAoB;IAC5D,IAAI,CAAC;QACJ,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,SAAS,EAAE;YACvC,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,EAAE,cAAc,EAAE,mCAAmC,EAAE;YAChE,IAAI,EAAE,IAAI,eAAe,CAAC;gBACzB,UAAU,EAAE,eAAe;gBAC3B,aAAa,EAAE,YAAY;gBAC3B,SAAS,EAAE,SAAS;aACpB,CAAC;SACF,CAAC,CAAC;QAEH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YAClB,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC;YACnD,OAAO,CAAC,KAAK,CACZ,6CAA6C,EAC7C,QAAQ,CAAC,MAAM,EACf,IAAI,CACJ,CAAC;YACF,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;QAC3B,CAAC;QAED,MAAM,IAAI,GAAG,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAIlC,CAAC;QACF,IACC,CAAC,IAAI,EAAE,YAAY;YACnB,OAAO,IAAI,EAAE,UAAU,KAAK,QAAQ,EACnC,CAAC;YACF,OAAO,CAAC,KAAK,CACZ,8DAA8D,EAC9D,IAAI,CACJ,CAAC;YACF,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;QAC3B,CAAC;QAED,OAAO;YACN,IAAI,EAAE,SAAS;YACf,MAAM,EAAE,IAAI,CAAC,YAAY;YACzB,OAAO,EAAE,IAAI,CAAC,aAAa,IAAI,YAAY;YAC3C,OAAO,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,UAAU,GAAG,IAAI;SAC5C,CAAC;IACH,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QAChB,MAAM,GAAG,GAAG,KAAc,CAAC;QAC3B,OAAO,CAAC,KAAK,CAAC,4CAA4C,EAAE,GAAG,CAAC,CAAC;QACjE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;IAC3B,CAAC;AACF,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,uBAAuB;IAC5C,MAAM,IAAI,GAAG,CAAC,MAAM,YAAY,EAAE,CAAa,CAAC;IAChD,MAAM,KAAK,GAAG,WAAW,EAAE,CAAC;IAE5B,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,aAAa,CAAC,CAAC;IACnC,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,eAAe,EAAE,MAAM,CAAC,CAAC;IAC9C,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,WAAW,EAAE,SAAS,CAAC,CAAC;IAC7C,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,cAAc,EAAE,YAAY,CAAC,CAAC;IACnD,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;IACrC,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,gBAAgB,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC;IACvD,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,uBAAuB,EAAE,MAAM,CAAC,CAAC;IACtD,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;IACrC,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,4BAA4B,EAAE,MAAM,CAAC,CAAC;IAC3D,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,2BAA2B,EAAE,MAAM,CAAC,CAAC;IAC1D,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,YAAY,EAAE,cAAc,CAAC,CAAC;IAEnD,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,EAAE,GAAG,CAAC,QAAQ,EAAE,EAAE,CAAC;AAC7C,CAAC"}
1
+ {"version":3,"file":"auth.js","sourceRoot":"","sources":["../../../lib/auth/auth.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../../lib/auth/server.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAMnD;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,EAAE,KAAK,EAAE,EAAE;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAAC,eAAe,CAAC,CAkE5F"}
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../../lib/auth/server.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAOnD;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,EAAE,KAAK,EAAE,EAAE;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAAC,eAAe,CAAC,CAqE5F"}
@@ -2,6 +2,7 @@ import http from "node:http";
2
2
  import fs from "node:fs";
3
3
  import path from "node:path";
4
4
  import { fileURLToPath } from "node:url";
5
+ import { OAUTH_SERVER, PLUGIN_NAME } from "../constants.js";
5
6
  // Resolve path to oauth-success.html (one level up from auth/ subfolder)
6
7
  const __dirname = path.dirname(fileURLToPath(import.meta.url));
7
8
  const successHtml = fs.readFileSync(path.join(__dirname, "..", "oauth-success.html"), "utf-8");
@@ -35,21 +36,22 @@ export function startLocalOAuthServer({ state }) {
35
36
  res.end(successHtml);
36
37
  server._lastCode = code;
37
38
  }
38
- catch {
39
+ catch (error) {
40
+ console.error(`[${PLUGIN_NAME}] OAuth callback handler error:`, error);
39
41
  res.statusCode = 500;
40
42
  res.end("Internal error");
41
43
  }
42
44
  });
43
45
  return new Promise((resolve) => {
44
46
  server
45
- .listen(1455, "127.0.0.1", () => {
47
+ .listen(OAUTH_SERVER.PORT, "127.0.0.1", () => {
46
48
  resolve({
47
- port: 1455,
49
+ port: OAUTH_SERVER.PORT,
48
50
  ready: true,
49
51
  close: () => server.close(),
50
52
  waitForCode: async () => {
51
- const poll = () => new Promise((r) => setTimeout(r, 100));
52
- for (let i = 0; i < 600; i++) {
53
+ const poll = () => new Promise((r) => setTimeout(r, OAUTH_SERVER.POLL_INTERVAL_MS));
54
+ for (let i = 0; i < OAUTH_SERVER.MAX_POLL_ITERATIONS; i++) {
53
55
  const lastCode = server._lastCode;
54
56
  if (lastCode)
55
57
  return { code: lastCode };
@@ -60,15 +62,17 @@ export function startLocalOAuthServer({ state }) {
60
62
  });
61
63
  })
62
64
  .on("error", (err) => {
63
- console.error("[openai-codex-plugin] Failed to bind http://127.0.0.1:1455 (", err?.code, ") Falling back to manual paste.");
65
+ console.error(`[${PLUGIN_NAME}] Failed to bind http://127.0.0.1:${OAUTH_SERVER.PORT} (`, err?.code, ") Falling back to manual paste.");
64
66
  resolve({
65
- port: 1455,
67
+ port: OAUTH_SERVER.PORT,
66
68
  ready: false,
67
69
  close: () => {
68
70
  try {
69
71
  server.close();
70
72
  }
71
- catch { }
73
+ catch (closeErr) {
74
+ console.error(`[${PLUGIN_NAME}] Error closing server:`, closeErr);
75
+ }
72
76
  },
73
77
  waitForCode: async () => null,
74
78
  });
@@ -1 +1 @@
1
- {"version":3,"file":"server.js","sourceRoot":"","sources":["../../../lib/auth/server.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../../../lib/auth/server.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