opencode-codex-multi-account 0.2.6 → 0.2.9

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.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/account-manager.ts","../src/constants.ts","../src/oauth.ts","../src/types.ts","../src/token.ts","../src/executor.ts","../src/rate-limit.ts","../src/config.ts","../src/utils.ts","../src/usage.ts","../src/auth-handler.ts","../src/ui/ansi.ts","../src/ui/select.ts","../src/ui/confirm.ts","../src/ui/auth-menu.ts","../src/account-store.ts","../src/proactive-refresh.ts","../src/request-transform.ts","../src/runtime-factory.ts"],"sourcesContent":["import { tool } from \"@opencode-ai/plugin\";\nimport { migrateFromAuthJson } from \"opencode-multi-account-core\";\nimport { AccountManager } from \"./account-manager\";\nimport { executeWithAccountRotation } from \"./executor\";\nimport { getUsageSummary } from \"./usage\";\nimport { handleAuthorize } from \"./auth-handler\";\nimport { loadConfig } from \"./config\";\nimport { ProactiveRefreshQueue } from \"./proactive-refresh\";\nimport { AccountStore } from \"./account-store\";\nimport { AccountRuntimeFactory } from \"./runtime-factory\";\nimport { formatWaitTime, getAccountLabel, showToast } from \"./utils\";\nimport { OPENAI_OAUTH_ADAPTER } from \"./constants\";\nimport type { OAuthCredentials, PluginClient } from \"./types\";\n\nfunction formatResetTime(resetAt: string): string {\n return formatWaitTime(new Date(resetAt).getTime() - Date.now());\n}\n\nexport const CodexMultiAuthPlugin = async (ctx: unknown) => {\n const { client } = ctx as unknown as { client: PluginClient } & Record<string, unknown>;\n\n await loadConfig();\n\n const store = new AccountStore();\n let manager: AccountManager | null = null;\n let runtimeFactory: AccountRuntimeFactory | null = null;\n let refreshQueue: ProactiveRefreshQueue | null = null;\n\n return {\n tool: {\n [OPENAI_OAUTH_ADAPTER.statusToolName]: tool({\n description:\n \"Show status of all multi-auth accounts including rate limits and usage.\",\n args: {},\n async execute(_args, _context) {\n if (!manager) {\n return \"Multi-auth not initialized. No OAuth accounts detected.\";\n }\n\n const accounts = manager.getAccounts();\n if (accounts.length === 0) {\n return \"No accounts configured. Run `opencode auth login` to add an account.\";\n }\n\n const lines: string[] = [\n `## Codex Multi-Auth Status (${accounts.length} accounts)\\n`,\n ];\n\n for (const account of accounts) {\n const isActive = account.uuid === manager.getActiveAccount()?.uuid;\n const marker = isActive ? \" **[ACTIVE]**\" : \"\";\n const label = getAccountLabel(account);\n const usage = getUsageSummary(account);\n\n const statusParts: string[] = [];\n if (account.isAuthDisabled) statusParts.push(`AUTH DISABLED: ${account.authDisabledReason}`);\n else if (!account.enabled) statusParts.push(\"disabled\");\n else statusParts.push(\"enabled\");\n\n if (account.rateLimitResetAt && account.rateLimitResetAt > Date.now()) {\n const remaining = formatWaitTime(account.rateLimitResetAt - Date.now());\n statusParts.push(`RATE LIMITED (resets in ${remaining})`);\n }\n\n if (account.cachedUsage) {\n const usage = account.cachedUsage;\n const exhaustedTiers = [\n { name: \"5-hour\", tier: usage.five_hour },\n { name: \"7-day\", tier: usage.seven_day },\n ].filter(({ tier }) => tier && tier.utilization >= 100);\n\n exhaustedTiers.forEach(({ name, tier }) => {\n if (tier && tier.resets_at) {\n const resetTime = formatResetTime(tier.resets_at);\n statusParts.push(`USAGE EXHAUSTED (${name}, resets ${resetTime})`);\n }\n });\n }\n\n lines.push(\n `- **${label}**${marker}: ${statusParts.join(\" | \")} | ${usage}`,\n );\n }\n\n return lines.join(\"\\n\");\n },\n }),\n },\n\n auth: {\n provider: OPENAI_OAUTH_ADAPTER.authProviderId,\n methods: [\n {\n label: OPENAI_OAUTH_ADAPTER.authMethodLabel,\n type: \"oauth\" as const,\n async authorize() {\n const inputs = arguments.length > 0 ? (arguments[0] as Record<string, string>) : undefined;\n return handleAuthorize(manager, inputs, client);\n },\n },\n { type: \"api\" as const, label: \"Manually enter API Key\" },\n ],\n\n async loader(\n getAuth: () => Promise<unknown>,\n provider: Record<string, unknown>,\n ) {\n const auth = await getAuth() as Record<string, unknown>;\n if (auth.type !== \"oauth\") {\n return { apiKey: \"\", fetch };\n }\n\n for (const model of Object.values((provider as Record<string, unknown>).models ?? {}) as Record<string, unknown>[]) {\n if (model) {\n model.cost = { input: 0, output: 0, cache: { read: 0, write: 0 } };\n }\n }\n\n const credentials = auth as OAuthCredentials;\n await migrateFromAuthJson(\"openai\", store);\n manager = await AccountManager.create(store, credentials, client);\n runtimeFactory = new AccountRuntimeFactory(store, client);\n manager.setRuntimeFactory(runtimeFactory);\n\n if (manager.getAccountCount() > 0) {\n const activeAccount = manager.getActiveAccount();\n const activeLabel = activeAccount ? getAccountLabel(activeAccount) : \"none\";\n void showToast(\n client,\n `Multi-Auth: ${manager.getAccountCount()} account(s) loaded. Active: ${activeLabel}`,\n \"info\",\n );\n await manager.validateNonActiveTokens(client);\n\n const disabledCount = manager.getAccounts().filter((a) => a.isAuthDisabled).length;\n if (disabledCount > 0) {\n void showToast(\n client,\n `${disabledCount} account(s) have auth failures.`,\n \"warning\",\n );\n }\n\n if (refreshQueue) {\n await refreshQueue.stop();\n }\n refreshQueue = new ProactiveRefreshQueue(\n client,\n store,\n (uuid) => runtimeFactory?.invalidate(uuid),\n );\n refreshQueue.start();\n }\n\n return {\n apiKey: \"CODEX_OAUTH\",\n async fetch(input: RequestInfo | URL, init?: RequestInit) {\n if (!manager || !runtimeFactory) {\n return fetch(input, init);\n }\n\n if (manager.getAccountCount() === 0) {\n throw new Error(\n \"No Codex accounts configured. Run `opencode auth login` to add an account.\",\n );\n }\n\n return executeWithAccountRotation(manager, runtimeFactory, client, input, init);\n },\n };\n },\n },\n };\n};\n","import { createAccountManagerForProvider } from \"opencode-multi-account-core\";\nimport { isTokenExpired, refreshToken } from \"./token\";\n\nexport const AccountManager = createAccountManagerForProvider({\n providerAuthId: \"openai\",\n isTokenExpired,\n refreshToken,\n});\n\nexport type AccountManager = InstanceType<typeof AccountManager>;\n","import { openAIOAuthAdapter } from \"opencode-multi-account-core\";\n\n/** OpenAI OAuth adapter config */\nexport const OPENAI_OAUTH_ADAPTER = openAIOAuthAdapter;\n\n/** OpenAI OAuth Client ID */\nexport const OPENAI_CLIENT_ID = OPENAI_OAUTH_ADAPTER.oauthClientId;\n\n/** Token exchange / refresh endpoint */\nexport const OPENAI_TOKEN_ENDPOINT = OPENAI_OAUTH_ADAPTER.tokenEndpoint;\n\n/** OAuth usage stats endpoint */\nexport const OPENAI_USAGE_ENDPOINT = OPENAI_OAUTH_ADAPTER.usageEndpoint;\n\n/** OAuth profile endpoint */\nexport const OPENAI_PROFILE_ENDPOINT = OPENAI_OAUTH_ADAPTER.profileEndpoint;\n\n/** Codex upstream endpoint used by OpenCode */\nexport const CODEX_API_ENDPOINT = \"https://chatgpt.com/backend-api/codex/responses\";\n\n/** Codex usage/quota endpoint (WHAM API) */\nexport const CODEX_USAGE_ENDPOINT = \"https://chatgpt.com/backend-api/wham/usage\";\n\n/** OpenAI OAuth issuer */\nexport const OAUTH_ISSUER = \"https://auth.openai.com\";\n\n/** Local callback port for browser OAuth */\nexport const OAUTH_PORT = 1455;\n\n/** Required beta header for OAuth requests */\nexport const OPENAI_BETA_HEADER = OPENAI_OAUTH_ADAPTER.requestBetaHeader;\n\n/** User-Agent header */\nexport const OPENAI_CLI_USER_AGENT = OPENAI_OAUTH_ADAPTER.cliUserAgent;\n\n/** Tool name prefix */\nexport const TOOL_PREFIX = OPENAI_OAUTH_ADAPTER.toolPrefix;\n\n/** Account storage filename */\nexport const ACCOUNTS_FILENAME = OPENAI_OAUTH_ADAPTER.accountStorageFilename;\n\n/** Plan display labels derived from adapter */\nexport const PLAN_LABELS = OPENAI_OAUTH_ADAPTER.planLabels;\n\n/** Access token expiry buffer (refresh 60s before expiry) */\nexport const TOKEN_EXPIRY_BUFFER_MS = 60_000;\n\n/** Maximum time to wait for a token refresh HTTP request */\nexport const TOKEN_REFRESH_TIMEOUT_MS = 30_000;\n","import * as v from \"valibot\";\nimport {\n OPENAI_CLIENT_ID,\n OAUTH_ISSUER,\n OAUTH_PORT,\n} from \"./constants\";\nimport { TokenResponseSchema } from \"./types\";\nimport type { TokenResponse } from \"./types\";\n\nconst OAUTH_CALLBACK_TIMEOUT_MS = 5 * 60 * 1000;\n\ntype PKCE = { verifier: string; challenge: string };\n\ntype OAuthCallbackQuery = {\n code?: string;\n state?: string;\n error?: string;\n errorDescription?: string;\n};\n\ninterface BunServerLike {\n stop(closeActiveConnections?: boolean): void;\n}\n\ninterface BunRuntimeLike {\n serve(options: {\n port: number;\n fetch(request: Request): Response | Promise<Response>;\n }): BunServerLike;\n}\n\nlet oauthServer: BunServerLike | null = null;\nlet resolveOAuthQuery: ((value: OAuthCallbackQuery) => void) | null = null;\nlet rejectOAuthQuery: ((reason?: unknown) => void) | null = null;\n\nfunction getBunRuntime(): BunRuntimeLike {\n const maybeBun = (globalThis as unknown as { Bun?: BunRuntimeLike }).Bun;\n if (!maybeBun || typeof maybeBun.serve !== \"function\") {\n throw new Error(\"Browser OAuth requires Bun runtime\");\n }\n return maybeBun;\n}\n\nfunction getRedirectUri(port: number = OAUTH_PORT): string {\n return `http://localhost:${port}/auth/callback`;\n}\n\nfunction renderHtml(title: string, body: string): string {\n return `<!doctype html>\n<html>\n <head>\n <meta charset=\"utf-8\" />\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n <title>${title}</title>\n <style>\n :root { color-scheme: dark; }\n body {\n margin: 0;\n min-height: 100vh;\n display: grid;\n place-items: center;\n background: #0f1115;\n color: #f5f7ff;\n font: 16px/1.45 -apple-system, BlinkMacSystemFont, \"Segoe UI\", sans-serif;\n }\n main {\n width: min(520px, calc(100vw - 32px));\n border: 1px solid #2a3040;\n border-radius: 12px;\n padding: 24px;\n background: #171b25;\n }\n h1 { margin: 0 0 8px 0; font-size: 22px; }\n p { margin: 0; color: #c4cadb; }\n </style>\n </head>\n <body>\n <main>\n <h1>${title}</h1>\n <p>${body}</p>\n </main>\n </body>\n</html>`;\n}\n\nfunction renderSuccessHtml(): string {\n return renderHtml(\"Authentication Complete\", \"You can close this tab and return to OpenCode.\");\n}\n\nfunction renderErrorHtml(message: string): string {\n return renderHtml(\"Authentication Failed\", message);\n}\n\nfunction completeOAuthQuery(query: OAuthCallbackQuery): void {\n if (resolveOAuthQuery) {\n resolveOAuthQuery(query);\n }\n resolveOAuthQuery = null;\n rejectOAuthQuery = null;\n}\n\nfunction failOAuthQuery(reason: unknown): void {\n if (rejectOAuthQuery) {\n rejectOAuthQuery(reason);\n }\n resolveOAuthQuery = null;\n rejectOAuthQuery = null;\n}\n\nfunction tokenEndpoint(): string {\n return `${OAUTH_ISSUER}/oauth/token`;\n}\n\nfunction parseTokenResponse(json: unknown): TokenResponse {\n return v.parse(TokenResponseSchema, json);\n}\n\nasync function postTokenForm(body: URLSearchParams): Promise<TokenResponse> {\n const response = await fetch(tokenEndpoint(), {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/x-www-form-urlencoded\",\n },\n body,\n });\n\n const payload = await response.json().catch(() => ({} as Record<string, unknown>));\n\n if (!response.ok) {\n throw new Error(`Token request failed: ${response.status}`);\n }\n\n return parseTokenResponse(payload);\n}\n\nexport async function generatePKCE(): Promise<{ verifier: string; challenge: string }> {\n const verifier = generateRandomString(64);\n const digest = await crypto.subtle.digest(\"SHA-256\", new TextEncoder().encode(verifier));\n const challenge = base64UrlEncode(digest);\n return { verifier, challenge };\n}\n\nfunction generateRandomBytes(length: number): Uint8Array {\n const bytes = new Uint8Array(length);\n crypto.getRandomValues(bytes);\n return bytes;\n}\n\nfunction generateRandomString(length: number): string {\n const charset = \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~\";\n const bytes = generateRandomBytes(length);\n let out = \"\";\n\n for (const value of bytes) {\n out += charset[value % charset.length];\n }\n\n return out;\n}\n\nfunction base64UrlEncode(buffer: ArrayBuffer): string {\n const bytes = new Uint8Array(buffer);\n let binary = \"\";\n\n for (const byte of bytes) {\n binary += String.fromCharCode(byte);\n }\n\n return btoa(binary)\n .replace(/\\+/g, \"-\")\n .replace(/\\//g, \"_\")\n .replace(/=+$/g, \"\");\n}\n\nexport function generateState(): string {\n const bytes = generateRandomBytes(32);\n const buffer = new ArrayBuffer(bytes.byteLength);\n new Uint8Array(buffer).set(bytes);\n return base64UrlEncode(buffer);\n}\n\nexport async function exchangeCodeForTokens(\n code: string,\n redirectUri: string,\n pkce: PKCE,\n): Promise<TokenResponse> {\n return postTokenForm(new URLSearchParams({\n grant_type: \"authorization_code\",\n code,\n redirect_uri: redirectUri,\n client_id: OPENAI_CLIENT_ID,\n code_verifier: pkce.verifier,\n }));\n}\n\nexport async function refreshAccessToken(refreshToken: string): Promise<TokenResponse> {\n return postTokenForm(new URLSearchParams({\n grant_type: \"refresh_token\",\n refresh_token: refreshToken,\n client_id: OPENAI_CLIENT_ID,\n }));\n}\n\nexport interface IdTokenClaims {\n chatgpt_account_id?: string;\n organizations?: Array<{ id: string }>;\n email?: string;\n \"https://api.openai.com/auth\"?: { chatgpt_account_id?: string };\n}\n\nfunction base64UrlDecode(value: string): string {\n const normalized = value.replace(/-/g, \"+\").replace(/_/g, \"/\");\n const padded = normalized + \"=\".repeat((4 - (normalized.length % 4 || 4)) % 4);\n return atob(padded);\n}\n\nexport function parseJwtClaims(token: string): IdTokenClaims | undefined {\n try {\n const parts = token.split(\".\");\n if (parts.length < 2 || !parts[1]) return undefined;\n const json = base64UrlDecode(parts[1]);\n return JSON.parse(json) as IdTokenClaims;\n } catch {\n return undefined;\n }\n}\n\nfunction findAccountId(claims: IdTokenClaims | undefined): string | undefined {\n if (!claims) return undefined;\n if (claims.chatgpt_account_id) return claims.chatgpt_account_id;\n if (claims[\"https://api.openai.com/auth\"]?.chatgpt_account_id) {\n return claims[\"https://api.openai.com/auth\"]?.chatgpt_account_id;\n }\n if (Array.isArray(claims.organizations) && claims.organizations[0]?.id) {\n return claims.organizations[0].id;\n }\n return undefined;\n}\n\nexport function extractAccountId(tokens: { id_token?: string; access_token: string }): string | undefined {\n const fromIdToken = findAccountId(parseJwtClaims(tokens.id_token ?? \"\"));\n if (fromIdToken) return fromIdToken;\n return findAccountId(parseJwtClaims(tokens.access_token));\n}\n\nexport async function startOAuthServer(): Promise<{ port: number; redirectUri: string }> {\n if (oauthServer) {\n return { port: OAUTH_PORT, redirectUri: getRedirectUri() };\n }\n\n const bun = getBunRuntime();\n oauthServer = bun.serve({\n port: OAUTH_PORT,\n fetch(request) {\n const url = new URL(request.url);\n\n if (url.pathname === \"/cancel\") {\n failOAuthQuery(new Error(\"Authentication cancelled by user\"));\n return new Response(renderErrorHtml(\"Authentication was cancelled.\"), {\n status: 200,\n headers: { \"Content-Type\": \"text/html; charset=utf-8\" },\n });\n }\n\n if (url.pathname !== \"/auth/callback\") {\n return new Response(\"Not Found\", { status: 404 });\n }\n\n const error = url.searchParams.get(\"error\") ?? undefined;\n const errorDescription = url.searchParams.get(\"error_description\") ?? undefined;\n const code = url.searchParams.get(\"code\") ?? undefined;\n const state = url.searchParams.get(\"state\") ?? undefined;\n\n if (error) {\n failOAuthQuery(new Error(errorDescription ?? error));\n return new Response(renderErrorHtml(errorDescription ?? error), {\n status: 400,\n headers: { \"Content-Type\": \"text/html; charset=utf-8\" },\n });\n }\n\n if (!code) {\n failOAuthQuery(new Error(\"Missing authorization code\"));\n return new Response(renderErrorHtml(\"Missing authorization code.\"), {\n status: 400,\n headers: { \"Content-Type\": \"text/html; charset=utf-8\" },\n });\n }\n\n completeOAuthQuery({ code, state });\n return new Response(renderSuccessHtml(), {\n status: 200,\n headers: { \"Content-Type\": \"text/html; charset=utf-8\" },\n });\n },\n });\n\n return { port: OAUTH_PORT, redirectUri: getRedirectUri() };\n}\n\nexport function stopOAuthServer(): void {\n if (oauthServer) {\n oauthServer.stop(true);\n }\n oauthServer = null;\n failOAuthQuery(new Error(\"OAuth server stopped\"));\n}\n\nexport function waitForOAuthCallback(pkce: PKCE, state: string): Promise<TokenResponse> {\n return new Promise<TokenResponse>(async (resolve, reject) => {\n try {\n const { redirectUri } = await startOAuthServer();\n\n if (resolveOAuthQuery || rejectOAuthQuery) {\n reject(new Error(\"OAuth callback wait already active\"));\n return;\n }\n\n const timeout = setTimeout(() => {\n failOAuthQuery(new Error(\"OAuth callback timed out\"));\n }, OAUTH_CALLBACK_TIMEOUT_MS);\n\n resolveOAuthQuery = async (query) => {\n clearTimeout(timeout);\n\n try {\n if (!query.code) {\n reject(new Error(\"Missing OAuth authorization code\"));\n return;\n }\n\n if (!query.state || query.state !== state) {\n reject(new Error(\"OAuth state mismatch\"));\n return;\n }\n\n const tokens = await exchangeCodeForTokens(query.code, redirectUri, pkce);\n resolve(tokens);\n } catch (error) {\n reject(error);\n } finally {\n resolveOAuthQuery = null;\n rejectOAuthQuery = null;\n }\n };\n\n rejectOAuthQuery = (reason) => {\n clearTimeout(timeout);\n reject(reason);\n };\n } catch (error) {\n reject(error);\n }\n });\n}\n\nexport function buildAuthorizeUrl(\n redirectUri: string,\n pkce: { challenge: string },\n state: string,\n): string {\n const url = new URL(`${OAUTH_ISSUER}/oauth/authorize`);\n url.searchParams.set(\"response_type\", \"code\");\n url.searchParams.set(\"client_id\", OPENAI_CLIENT_ID);\n url.searchParams.set(\"redirect_uri\", redirectUri);\n url.searchParams.set(\"scope\", \"openid profile email offline_access\");\n url.searchParams.set(\"code_challenge\", pkce.challenge);\n url.searchParams.set(\"code_challenge_method\", \"S256\");\n url.searchParams.set(\"id_token_add_organizations\", \"true\");\n url.searchParams.set(\"codex_cli_simplified_flow\", \"true\");\n url.searchParams.set(\"state\", state);\n url.searchParams.set(\"originator\", \"opencode\");\n return url.toString();\n}\n","import * as v from \"valibot\";\n\n// ─── Schemas (Single Source of Truth) ───────────────────────────\n\nexport const OAuthCredentialsSchema = v.object({\n type: v.literal(\"oauth\"),\n refresh: v.string(),\n access: v.string(),\n expires: v.number(),\n});\n\nexport const UsageLimitEntrySchema = v.object({\n utilization: v.number(),\n resets_at: v.nullable(v.string()),\n});\n\nexport const UsageLimitsSchema = v.object({\n five_hour: v.optional(v.nullable(UsageLimitEntrySchema), null),\n seven_day: v.optional(v.nullable(UsageLimitEntrySchema), null),\n seven_day_sonnet: v.optional(v.nullable(UsageLimitEntrySchema), null),\n});\n\nexport const CredentialRefreshPatchSchema = v.object({\n accessToken: v.string(),\n expiresAt: v.number(),\n refreshToken: v.optional(v.string()),\n uuid: v.optional(v.string()),\n accountId: v.optional(v.string()),\n email: v.optional(v.string()),\n});\n\nexport const StoredAccountSchema = v.object({\n uuid: v.optional(v.string()),\n accountId: v.optional(v.string()),\n label: v.optional(v.string()),\n email: v.optional(v.string()),\n planTier: v.optional(v.string(), \"\"),\n refreshToken: v.string(),\n accessToken: v.optional(v.string()),\n expiresAt: v.optional(v.number()),\n addedAt: v.number(),\n lastUsed: v.number(),\n enabled: v.optional(v.boolean(), true),\n rateLimitResetAt: v.optional(v.number()),\n cachedUsage: v.optional(UsageLimitsSchema),\n cachedUsageAt: v.optional(v.number()),\n consecutiveAuthFailures: v.optional(v.number(), 0),\n isAuthDisabled: v.optional(v.boolean(), false),\n authDisabledReason: v.optional(v.string()),\n});\n\nexport const AccountStorageSchema = v.object({\n version: v.literal(1),\n accounts: v.optional(v.array(StoredAccountSchema), []),\n activeAccountUuid: v.optional(v.string()),\n});\n\n/** OpenAI /oauth/token response */\nexport const TokenResponseSchema = v.object({\n id_token: v.optional(v.string()),\n access_token: v.string(),\n refresh_token: v.optional(v.string()),\n expires_in: v.number(),\n});\n\n// ─── Types (derived from schemas) ───────────────────────────────\n\nexport type OAuthCredentials = v.InferOutput<typeof OAuthCredentialsSchema>;\nexport type UsageLimitEntry = v.InferOutput<typeof UsageLimitEntrySchema>;\nexport type UsageLimits = v.InferOutput<typeof UsageLimitsSchema>;\nexport type CredentialRefreshPatch = v.InferOutput<typeof CredentialRefreshPatchSchema>;\nexport type StoredAccount = v.InferOutput<typeof StoredAccountSchema>;\nexport type AccountStorage = v.InferOutput<typeof AccountStorageSchema>;\nexport type TokenResponse = v.InferOutput<typeof TokenResponseSchema>;\n\n// ─── Plugin Config Schema ────────────────────────────────────────\n\nexport const AccountSelectionStrategySchema = v.picklist([\"sticky\", \"round-robin\", \"hybrid\"]);\nexport type AccountSelectionStrategy = v.InferOutput<typeof AccountSelectionStrategySchema>;\n\nexport const PluginConfigSchema = v.object({\n /** sticky: same account until failure, round-robin: rotate every request, hybrid: health+usage scoring */\n account_selection_strategy: v.optional(AccountSelectionStrategySchema, \"sticky\"),\n\n /** Use cross-process claim file to distribute parallel sessions across accounts */\n cross_process_claims: v.optional(v.boolean(), true),\n /** Skip account when any usage tier utilization >= this % (100 = disabled) */\n soft_quota_threshold_percent: v.optional(v.pipe(v.number(), v.minValue(0), v.maxValue(100)), 100),\n /** Minimum backoff after rate limit (ms) */\n rate_limit_min_backoff_ms: v.optional(v.pipe(v.number(), v.minValue(0)), 30_000),\n /** Default retry-after when header is missing (ms) */\n default_retry_after_ms: v.optional(v.pipe(v.number(), v.minValue(0)), 60_000),\n /** Consecutive auth failures before disabling account */\n max_consecutive_auth_failures: v.optional(v.pipe(v.number(), v.integer(), v.minValue(1)), 3),\n /** Backoff after token refresh failure (ms) */\n token_failure_backoff_ms: v.optional(v.pipe(v.number(), v.minValue(0)), 30_000),\n /** Enable proactive background token refresh */\n proactive_refresh: v.optional(v.boolean(), true),\n /** Seconds before expiry to trigger proactive refresh (default 30 min) */\n proactive_refresh_buffer_seconds: v.optional(v.pipe(v.number(), v.minValue(60)), 1800),\n /** Interval between background refresh checks in seconds (default 5 min) */\n proactive_refresh_interval_seconds: v.optional(v.pipe(v.number(), v.minValue(30)), 300),\n /** Suppress toast notifications */\n quiet_mode: v.optional(v.boolean(), false),\n /** Enable debug logging */\n debug: v.optional(v.boolean(), false),\n});\n\nexport type PluginConfig = v.InferOutput<typeof PluginConfigSchema>;\n\n// ─── External Plugin Auth Hook ───────────────────────────────────\n\nexport interface OriginalAuthHook {\n methods?: Array<{\n authorize?: (inputs?: Record<string, string>) => Promise<unknown>;\n }>;\n loader: (\n getAuth: () => Promise<unknown>,\n provider: unknown,\n ) => Promise<{ apiKey: string; fetch: (input: RequestInfo | URL, init?: RequestInit) => Promise<Response> }>;\n}\n\n// ─── Types (manual — not from external data) ────────────────────\n\nexport type TokenRefreshResult =\n | { ok: true; patch: CredentialRefreshPatch }\n | { ok: false; permanent: boolean; status?: number };\n\nexport interface ManagedAccount {\n index: number;\n uuid?: string;\n accountId?: string;\n label?: string;\n email?: string;\n planTier?: string;\n refreshToken: string;\n accessToken?: string;\n expiresAt?: number;\n addedAt: number;\n lastUsed: number;\n enabled: boolean;\n rateLimitResetAt?: number;\n last429At?: number;\n cachedUsage?: UsageLimits;\n cachedUsageAt?: number;\n consecutiveAuthFailures: number;\n isAuthDisabled: boolean;\n authDisabledReason?: string;\n}\n\nexport interface PluginClient {\n auth: {\n set: (params: {\n path: { id: string };\n body: {\n type: string;\n refresh: string;\n access: string;\n expires: number;\n };\n }) => Promise<void>;\n };\n tui: {\n showToast: (params: {\n body: {\n title?: string;\n message: string;\n variant: \"info\" | \"warning\" | \"success\" | \"error\";\n };\n }) => Promise<void>;\n };\n app: {\n log: (params: {\n body: {\n service: string;\n level: \"debug\" | \"info\" | \"warn\" | \"error\";\n message: string;\n extra?: Record<string, unknown>;\n };\n }) => Promise<void>;\n };\n}\n","import {\n OPENAI_OAUTH_ADAPTER,\n OPENAI_CLIENT_ID,\n OPENAI_TOKEN_ENDPOINT,\n TOKEN_EXPIRY_BUFFER_MS,\n TOKEN_REFRESH_TIMEOUT_MS,\n} from \"./constants\";\nimport { extractAccountId } from \"./oauth\";\nimport * as v from \"valibot\";\nimport {\n TokenResponseSchema,\n type ManagedAccount,\n type PluginClient,\n type CredentialRefreshPatch,\n type TokenRefreshResult,\n} from \"./types\";\n\nconst PERMANENT_FAILURE_STATUSES = new Set([400, 401, 403]);\nconst refreshMutexByAccountId = new Map<string, Promise<TokenRefreshResult>>();\n\nexport function isTokenExpired(account: Pick<ManagedAccount, \"accessToken\" | \"expiresAt\">): boolean {\n if (!account.accessToken || !account.expiresAt) return true;\n return account.expiresAt <= Date.now() + TOKEN_EXPIRY_BUFFER_MS;\n}\n\nexport async function refreshToken(\n currentRefreshToken: string,\n accountId: string,\n client: PluginClient,\n): Promise<TokenRefreshResult> {\n if (!currentRefreshToken) return { ok: false, permanent: true };\n\n const inFlightRefresh = refreshMutexByAccountId.get(accountId);\n if (inFlightRefresh) return inFlightRefresh;\n\n const refreshPromise = (async (): Promise<TokenRefreshResult> => {\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), TOKEN_REFRESH_TIMEOUT_MS);\n\n try {\n const startTime = Date.now();\n const response = await fetch(OPENAI_TOKEN_ENDPOINT, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/x-www-form-urlencoded\" },\n body: new URLSearchParams({\n grant_type: \"refresh_token\",\n refresh_token: currentRefreshToken,\n client_id: OPENAI_CLIENT_ID,\n }),\n signal: controller.signal,\n });\n\n if (!response.ok) {\n const isPermanent = PERMANENT_FAILURE_STATUSES.has(response.status);\n await client.app\n .log({\n body: {\n service: OPENAI_OAUTH_ADAPTER.serviceLogName,\n level: isPermanent ? \"error\" : \"warn\",\n message: `Token refresh failed: ${response.status}${isPermanent ? \" (permanent)\" : \"\"}`,\n extra: { accountId },\n },\n })\n .catch(() => {});\n\n return { ok: false, permanent: isPermanent, status: response.status };\n }\n\n const json = v.parse(TokenResponseSchema, await response.json());\n\n const patch: CredentialRefreshPatch = {\n accessToken: json.access_token,\n expiresAt: startTime + json.expires_in * 1000,\n refreshToken: json.refresh_token,\n accountId: extractAccountId(json),\n };\n\n return { ok: true, patch };\n } catch (error) {\n await client.app\n .log({\n body: {\n service: OPENAI_OAUTH_ADAPTER.serviceLogName,\n level: \"warn\",\n message: `Token refresh network error: ${error instanceof Error ? error.message : String(error)}`,\n extra: { accountId },\n },\n })\n .catch(() => {});\n return { ok: false, permanent: false };\n } finally {\n clearTimeout(timeout);\n refreshMutexByAccountId.delete(accountId);\n }\n })();\n\n refreshMutexByAccountId.set(accountId, refreshPromise);\n return refreshPromise;\n}\n\nexport function clearRefreshMutex(accountId?: string): void {\n if (accountId) {\n refreshMutexByAccountId.delete(accountId);\n return;\n }\n\n refreshMutexByAccountId.clear();\n}\n","import { createExecutorForProvider } from \"opencode-multi-account-core\";\nimport { handleRateLimitResponse as handleRateLimitResponseForProvider } from \"./rate-limit\";\nimport { formatWaitTime, getAccountLabel, showToast, sleep } from \"./utils\";\n\nconst { executeWithAccountRotation } = createExecutorForProvider(\"Codex\", {\n handleRateLimitResponse: async (manager, client, account, response) =>\n handleRateLimitResponseForProvider(\n manager as Parameters<typeof handleRateLimitResponseForProvider>[0],\n client,\n account,\n response,\n ),\n formatWaitTime,\n sleep,\n showToast,\n getAccountLabel,\n});\n\nexport { executeWithAccountRotation };\n","import { createRateLimitHandlers } from \"opencode-multi-account-core\";\nimport { getConfig } from \"./config\";\nimport { fetchUsage } from \"./usage\";\nimport { formatWaitTime, getAccountLabel, showToast } from \"./utils\";\n\nconst {\n fetchUsageLimits,\n getResetMsFromUsage,\n handleRateLimitResponse,\n retryAfterMsFromResponse,\n} = createRateLimitHandlers({\n fetchUsage,\n getConfig,\n formatWaitTime,\n getAccountLabel,\n showToast,\n});\n\nexport {\n fetchUsageLimits,\n getResetMsFromUsage,\n handleRateLimitResponse,\n retryAfterMsFromResponse,\n};\n","import {\n getConfig,\n initCoreConfig,\n loadConfig,\n resetConfigCache,\n updateConfigField,\n} from \"opencode-multi-account-core\";\n\ninitCoreConfig(\"codex-multiauth.json\");\n\nexport {\n getConfig,\n loadConfig,\n resetConfigCache,\n updateConfigField,\n};\n","import { setConfigGetter } from \"opencode-multi-account-core\";\nimport { getConfig } from \"./config\";\n\nsetConfigGetter(getConfig);\n\nexport {\n createMinimalClient,\n debugLog,\n formatWaitTime,\n getAccountLabel,\n getConfigDir,\n getErrorCode,\n showToast,\n sleep,\n} from \"opencode-multi-account-core\";\n","import { formatWaitTime } from \"./utils\";\nimport * as v from \"valibot\";\nimport { UsageLimitsSchema } from \"./types\";\nimport { parseJwtClaims } from \"./oauth\";\nimport { CODEX_USAGE_ENDPOINT, OPENAI_CLI_USER_AGENT, PLAN_LABELS } from \"./constants\";\nimport type { ManagedAccount, UsageLimits } from \"./types\";\n\n/** OpenAI JWT namespaced claim keys */\nconst OPENAI_AUTH_CLAIM = \"https://api.openai.com/auth\";\nconst OPENAI_PROFILE_CLAIM = \"https://api.openai.com/profile\";\n\n/** Schema for the OpenAI namespaced auth claim in JWT */\nconst OpenAIAuthClaimSchema = v.object({\n chatgpt_plan_type: v.optional(v.string()),\n chatgpt_account_id: v.optional(v.string()),\n chatgpt_user_id: v.optional(v.string()),\n});\n\n/** Schema for the OpenAI namespaced profile claim in JWT */\nconst OpenAIProfileClaimSchema = v.object({\n email: v.optional(v.string()),\n});\n\n/** Schema for the WHAM usage API response from chatgpt.com */\nconst WhamRateLimitWindowSchema = v.object({\n used_percent: v.number(),\n reset_after_seconds: v.number(),\n});\n\nconst WhamUsageResponseSchema = v.object({\n plan_type: v.optional(v.nullable(v.string())),\n rate_limit: v.optional(v.nullable(v.object({\n primary_window: v.optional(v.nullable(WhamRateLimitWindowSchema)),\n secondary_window: v.optional(v.nullable(WhamRateLimitWindowSchema)),\n }))),\n credits: v.optional(v.nullable(v.object({\n balance: v.optional(v.nullable(v.string())),\n unlimited: v.optional(v.nullable(v.boolean())),\n }))),\n});\n\nexport type ProfileData = {\n email?: string;\n planTier: string;\n};\n\nexport type FetchUsageResult =\n | { ok: true; data: UsageLimits; planType?: string }\n | { ok: false; reason: string };\n\nexport type FetchProfileResult =\n | { ok: true; data: ProfileData }\n | { ok: false; reason: string };\n\nfunction secondsToISOResetTime(resetAfterSeconds: number): string {\n return new Date(Date.now() + resetAfterSeconds * 1000).toISOString();\n}\n\nexport async function fetchUsage(accessToken: string, accountId?: string): Promise<FetchUsageResult> {\n try {\n const headers: Record<string, string> = {\n Authorization: `Bearer ${accessToken}`,\n \"User-Agent\": OPENAI_CLI_USER_AGENT,\n };\n\n if (accountId) {\n headers[\"ChatGPT-Account-Id\"] = accountId;\n }\n\n const response = await fetch(CODEX_USAGE_ENDPOINT, {\n method: \"GET\",\n headers,\n });\n\n if (!response.ok) {\n return { ok: false, reason: `HTTP ${response.status} ${response.statusText}` };\n }\n\n const parsed = v.safeParse(WhamUsageResponseSchema, await response.json());\n if (!parsed.success) {\n return { ok: false, reason: `Invalid response: ${parsed.issues[0]?.message ?? \"unknown\"}` };\n }\n\n const wham = parsed.output;\n const primaryWindow = wham.rate_limit?.primary_window;\n const secondaryWindow = wham.rate_limit?.secondary_window;\n\n const usage: UsageLimits = {\n five_hour: primaryWindow\n ? {\n utilization: primaryWindow.used_percent,\n resets_at: secondsToISOResetTime(primaryWindow.reset_after_seconds),\n }\n : null,\n seven_day: secondaryWindow\n ? {\n utilization: secondaryWindow.used_percent,\n resets_at: secondsToISOResetTime(secondaryWindow.reset_after_seconds),\n }\n : null,\n seven_day_sonnet: null,\n };\n\n const validated = v.safeParse(UsageLimitsSchema, usage);\n if (!validated.success) {\n return { ok: false, reason: `Mapping error: ${validated.issues[0]?.message ?? \"unknown\"}` };\n }\n\n return { ok: true, data: validated.output, planType: wham.plan_type ?? undefined };\n } catch (error) {\n const message = error instanceof Error ? error.message : \"Unknown error\";\n return { ok: false, reason: message };\n }\n}\n\nexport function derivePlanTier(planType: string): string {\n const normalized = planType.toLowerCase().trim();\n return normalized || \"free\";\n}\n\nexport function fetchProfile(accessToken: string): FetchProfileResult {\n try {\n const claims = parseJwtClaims(accessToken);\n if (!claims || typeof claims !== \"object\") {\n return { ok: true, data: { planTier: \"free\" } };\n }\n\n const record = claims as Record<string, unknown>;\n\n // Extract email from namespaced profile claim\n const profileClaim = record[OPENAI_PROFILE_CLAIM];\n const profileParsed = v.safeParse(OpenAIProfileClaimSchema, profileClaim ?? {});\n const email = profileParsed.success ? profileParsed.output.email : undefined;\n\n // Extract plan_type from namespaced auth claim\n const authClaim = record[OPENAI_AUTH_CLAIM];\n const authParsed = v.safeParse(OpenAIAuthClaimSchema, authClaim ?? {});\n const planType = authParsed.success ? (authParsed.output.chatgpt_plan_type ?? \"\") : \"\";\n const planTier = derivePlanTier(planType);\n\n return {\n ok: true,\n data: { email, planTier },\n };\n } catch (error) {\n const message = error instanceof Error ? error.message : \"Unknown error\";\n return { ok: false, reason: message };\n }\n}\n\nfunction formatTimeRemaining(resetAt: string | null): string {\n if (!resetAt) return \"unknown\";\n const diffMs = new Date(resetAt).getTime() - Date.now();\n if (diffMs <= 0) return \"0m\";\n return formatWaitTime(diffMs);\n}\n\nexport function getUsageSummary(account: ManagedAccount): string {\n if (!account.cachedUsage) return \"no usage data\";\n\n const parsed = v.safeParse(UsageLimitsSchema, account.cachedUsage);\n if (!parsed.success) return \"no usage data\";\n\n const parts: string[] = [];\n const { five_hour, seven_day } = parsed.output;\n\n if (five_hour) {\n const reset = five_hour.resets_at\n ? ` (resets ${formatTimeRemaining(five_hour.resets_at)})`\n : \"\";\n parts.push(`5h: ${five_hour.utilization.toFixed(0)}%${reset}`);\n }\n if (seven_day) {\n const reset = seven_day.resets_at\n ? ` (resets ${formatTimeRemaining(seven_day.resets_at)})`\n : \"\";\n parts.push(`7d: ${seven_day.utilization.toFixed(0)}%${reset}`);\n }\n\n return parts.length > 0 ? parts.join(\", \") : \"no usage data\";\n}\n\nexport function getPlanLabel(account: ManagedAccount): string {\n if (!account.planTier || account.planTier === \"free\") return \"\";\n return PLAN_LABELS[account.planTier]\n ?? account.planTier.charAt(0).toUpperCase() + account.planTier.slice(1);\n}\n","import * as v from \"valibot\";\nimport { AccountManager } from \"./account-manager\";\nimport { isTokenExpired } from \"./token\";\nimport { getConfig, updateConfigField } from \"./config\";\nimport { isTTY } from \"./ui/ansi\";\nimport { showAuthMenu, showManageAccounts, showMethodSelect, showStrategySelect, printQuotaError, printQuotaReport } from \"./ui/auth-menu\";\nimport { createMinimalClient, getAccountLabel } from \"./utils\";\nimport { fetchUsage, fetchProfile, derivePlanTier } from \"./usage\";\nimport { AccountStore } from \"./account-store\";\nimport { randomUUID } from \"node:crypto\";\nimport { createInterface } from \"node:readline\";\nimport { exec } from \"node:child_process\";\nimport {\n startOAuthServer,\n stopOAuthServer,\n waitForOAuthCallback,\n generatePKCE,\n generateState,\n buildAuthorizeUrl,\n extractAccountId,\n} from \"./oauth\";\nimport { OAUTH_ISSUER, OPENAI_CLIENT_ID } from \"./constants\";\nimport type { ManagedAccount, OAuthCredentials, PluginClient, StoredAccount, TokenResponse } from \"./types\";\nimport { TokenResponseSchema } from \"./types\";\n\ntype OAuthCallbackResponse =\n | ({ type: \"success\" } & { refresh: string; access: string; expires: number; accountId?: string })\n | { type: \"failed\" };\n\nexport interface OAuthFlowResult {\n url: string;\n instructions: string;\n method: \"auto\";\n callback(): Promise<OAuthCallbackResponse>;\n}\n\nconst DeviceUserCodeResponseSchema = v.object({\n device_code: v.string(),\n user_code: v.string(),\n expires_in: v.number(),\n interval: v.optional(v.number()),\n});\n\ntype DeviceUserCodeResponse = v.InferOutput<typeof DeviceUserCodeResponseSchema>;\n\nfunction makeFailedFlowResult(message: string): OAuthFlowResult {\n return {\n url: \"\",\n instructions: message,\n method: \"auto\",\n callback: async () => ({ type: \"failed\" }),\n };\n}\n\nfunction normalizeMethod(method?: \"browser\" | \"headless\"): \"browser\" | \"headless\" {\n return method === \"headless\" ? \"headless\" : \"browser\";\n}\n\nfunction toCallbackResponse(tokens: TokenResponse): OAuthCallbackResponse {\n if (!tokens.refresh_token) {\n return { type: \"failed\" };\n }\n\n return {\n type: \"success\",\n refresh: tokens.refresh_token,\n access: tokens.access_token,\n expires: Date.now() + (tokens.expires_in ?? 3600) * 1000,\n accountId: extractAccountId(tokens),\n };\n}\n\nasync function pollDeviceAuthToken(startResult: DeviceUserCodeResponse): Promise<TokenResponse> {\n const expiresAt = Date.now() + startResult.expires_in * 1000;\n let intervalMs = Math.max(1, startResult.interval ?? 5) * 1000;\n\n while (Date.now() < expiresAt) {\n const response = await fetch(`${OAUTH_ISSUER}/api/accounts/deviceauth/token`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({\n client_id: OPENAI_CLIENT_ID,\n device_code: startResult.device_code,\n }),\n });\n\n if (response.ok) {\n return v.parse(TokenResponseSchema, await response.json());\n }\n\n const payload = await response.json().catch(() => ({} as Record<string, unknown>));\n const error = typeof payload.error === \"string\" ? payload.error : \"\";\n\n if (error === \"authorization_pending\") {\n await new Promise((resolve) => setTimeout(resolve, intervalMs));\n continue;\n }\n\n if (error === \"slow_down\") {\n intervalMs += 5000;\n await new Promise((resolve) => setTimeout(resolve, intervalMs));\n continue;\n }\n\n if (error === \"expired_token\") {\n throw new Error(\"Device code expired. Start authentication again.\");\n }\n\n if (error === \"access_denied\") {\n throw new Error(\"Device authorization denied by user.\");\n }\n\n throw new Error(`Device token polling failed: ${response.status}`);\n }\n\n throw new Error(\"Device authorization timed out\");\n}\n\nasync function startBrowserAuth(): Promise<OAuthFlowResult> {\n const { redirectUri } = await startOAuthServer();\n const pkce = await generatePKCE();\n const state = generateState();\n const authUrl = buildAuthorizeUrl(redirectUri, pkce, state);\n\n return {\n url: authUrl,\n instructions: \"Complete authorization in your browser.\",\n method: \"auto\",\n callback: async () => {\n try {\n const tokens = await waitForOAuthCallback(pkce, state);\n return toCallbackResponse(tokens);\n } finally {\n stopOAuthServer();\n }\n },\n };\n}\n\nasync function startDeviceAuth(): Promise<OAuthFlowResult> {\n const response = await fetch(`${OAUTH_ISSUER}/api/accounts/deviceauth/usercode`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({ client_id: OPENAI_CLIENT_ID }),\n });\n\n if (!response.ok) {\n throw new Error(`Failed to start device authorization: ${response.status}`);\n }\n\n const startResult = v.parse(DeviceUserCodeResponseSchema, await response.json());\n\n return {\n url: `${OAUTH_ISSUER}/codex/device`,\n instructions: `Enter code: ${startResult.user_code}`,\n method: \"auto\",\n callback: async () => {\n const tokens = await pollDeviceAuthToken(startResult);\n return toCallbackResponse(tokens);\n },\n };\n}\n\nasync function startFlow(method?: \"browser\" | \"headless\"): Promise<OAuthFlowResult> {\n if (normalizeMethod(method) === \"headless\") {\n return startDeviceAuth();\n }\n return startBrowserAuth();\n}\n\nfunction wrapCallbackWithAccountReplace(\n result: OAuthFlowResult,\n manager: AccountManager,\n targetAccount: ManagedAccount,\n): OAuthFlowResult {\n const originalCallback = result.callback;\n return {\n ...result,\n callback: async function () {\n const code = arguments.length > 0 ? (arguments[0] as string) : undefined;\n const callbackResult = await (originalCallback as (code?: string) => Promise<OAuthCallbackResponse>)(code);\n\n if (callbackResult?.type === \"success\" && callbackResult.refresh) {\n const auth: OAuthCredentials = {\n type: \"oauth\",\n refresh: callbackResult.refresh,\n access: callbackResult.access,\n expires: callbackResult.expires,\n };\n\n if (targetAccount.uuid) {\n await manager.replaceAccountCredentials(targetAccount.uuid, auth);\n }\n\n const label = getAccountLabel(targetAccount);\n console.log(`\\n✅ ${label} re-authenticated successfully.\\n`);\n }\n\n return callbackResult;\n },\n };\n}\n\nfunction wrapCallbackWithManagerSync(\n result: OAuthFlowResult,\n manager: AccountManager | null,\n): OAuthFlowResult {\n const originalCallback = result.callback;\n return {\n ...result,\n callback: async function () {\n const code = arguments.length > 0 ? (arguments[0] as string) : undefined;\n const callbackResult = await (originalCallback as (code?: string) => Promise<OAuthCallbackResponse>)(code);\n\n if (callbackResult?.type === \"success\" && callbackResult.refresh) {\n const auth: OAuthCredentials = {\n type: \"oauth\",\n refresh: callbackResult.refresh,\n access: callbackResult.access,\n expires: callbackResult.expires,\n };\n\n if (manager) {\n const countBefore = manager.getAccounts().length;\n await manager.addAccount(auth);\n const countAfter = manager.getAccounts().length;\n\n if (countAfter > countBefore) {\n console.log(`\\n✅ Account added to multi-auth pool (${countAfter} total).\\n`);\n } else {\n console.log(`\\nℹ️ Account already exists in multi-auth pool (${countAfter} total).\\n`);\n }\n } else {\n await persistFallback(auth, callbackResult.accountId);\n console.log(\"\\n✅ Account saved.\\n\");\n }\n }\n\n return callbackResult;\n },\n };\n}\n\nfunction promptYesNo(message: string): Promise<boolean> {\n if (!isTTY()) return Promise.resolve(false);\n const rl = createInterface({ input: process.stdin, output: process.stdout });\n return new Promise((resolve) => {\n rl.question(message, (answer) => {\n rl.close();\n resolve(answer.trim().toLowerCase() === \"y\");\n });\n });\n}\n\nfunction openBrowser(url: string): void {\n const cmd = process.platform === \"darwin\" ? \"open\"\n : process.platform === \"win32\" ? \"start\"\n : \"xdg-open\";\n exec(`${cmd} ${JSON.stringify(url)}`);\n}\n\nasync function addMoreAccountsLoop(\n manager: AccountManager,\n): Promise<void> {\n while (true) {\n const currentCount = manager.getAccounts().length;\n const shouldAdd = await promptYesNo(`Add another account? (${currentCount} added) (y/n): `);\n if (!shouldAdd) break;\n\n const methodResult = await selectMethodAndStartFlow();\n if (!methodResult) break;\n\n let flow: OAuthFlowResult;\n try {\n flow = methodResult.flow;\n } catch {\n console.log(\"\\n❌ Failed to start OAuth flow.\\n\");\n break;\n }\n\n if (flow.url) {\n openBrowser(flow.url);\n }\n if (flow.instructions) {\n console.log(`\\n${flow.instructions}\\n`);\n }\n\n let callbackResult: OAuthCallbackResponse;\n try {\n callbackResult = await flow.callback();\n } catch {\n console.log(\"\\n❌ Authentication failed.\\n\");\n break;\n }\n\n if (callbackResult?.type !== \"success\" || !(\"refresh\" in callbackResult)) {\n console.log(\"\\n❌ Authentication failed.\\n\");\n break;\n }\n\n const auth: OAuthCredentials = {\n type: \"oauth\",\n refresh: callbackResult.refresh,\n access: callbackResult.access,\n expires: callbackResult.expires,\n };\n\n const countBefore = manager.getAccounts().length;\n await manager.addAccount(auth);\n const countAfter = manager.getAccounts().length;\n\n if (countAfter > countBefore) {\n console.log(`\\n✅ Account added to multi-auth pool (${countAfter} total).\\n`);\n } else {\n console.log(`\\nℹ️ Account already exists in multi-auth pool (${countAfter} total).\\n`);\n }\n }\n}\n\nasync function persistFallback(auth: OAuthCredentials, accountId?: string): Promise<void> {\n try {\n const store = new AccountStore();\n const now = Date.now();\n const account: StoredAccount = {\n uuid: randomUUID(),\n accountId,\n refreshToken: auth.refresh,\n accessToken: auth.access,\n expiresAt: auth.expires,\n addedAt: now,\n lastUsed: now,\n enabled: true,\n planTier: \"\",\n consecutiveAuthFailures: 0,\n isAuthDisabled: false,\n };\n await store.addAccount(account);\n await store.setActiveUuid(account.uuid);\n } catch {\n // best-effort\n }\n}\n\nasync function selectMethodAndStartFlow(): Promise<{ flow: OAuthFlowResult; method: \"browser\" | \"headless\" } | null> {\n if (!isTTY()) {\n const flow = await startFlow(\"browser\");\n return { flow, method: \"browser\" };\n }\n\n const selected = await showMethodSelect();\n if (!selected) return null;\n\n const flow = await startFlow(selected);\n return { flow, method: selected };\n}\n\nexport async function handleAuthorize(\n manager: AccountManager | null,\n inputs?: Record<string, string>,\n client?: PluginClient,\n): Promise<OAuthFlowResult> {\n if (!inputs || !isTTY()) {\n return wrapCallbackWithManagerSync(await startFlow(\"browser\"), manager);\n }\n\n const effectiveManager = manager ?? await loadManagerFromDisk(client);\n if (!effectiveManager || effectiveManager.getAccounts().length === 0) {\n const result = await selectMethodAndStartFlow();\n if (!result) return makeFailedFlowResult(\"Authentication cancelled\");\n return wrapCallbackWithManagerSync(result.flow, manager);\n }\n\n return runAccountManagementMenu(effectiveManager, client);\n}\n\nasync function loadManagerFromDisk(client?: PluginClient): Promise<AccountManager | null> {\n const store = new AccountStore();\n const stored = await store.load();\n if (stored.accounts.length === 0) return null;\n const emptyAuth: OAuthCredentials = { type: \"oauth\", refresh: \"\", access: \"\", expires: 0 };\n const mgr = await AccountManager.create(store, emptyAuth, client);\n return mgr;\n}\n\nasync function runAccountManagementMenu(\n manager: AccountManager,\n client?: PluginClient,\n): Promise<OAuthFlowResult> {\n while (true) {\n const allAccounts = manager.getAccounts();\n const menuAction = await showAuthMenu(allAccounts);\n\n switch (menuAction.type) {\n case \"add\": {\n const result = await selectMethodAndStartFlow();\n if (!result) continue;\n return wrapCallbackWithManagerSync(result.flow, manager);\n }\n\n case \"check-quotas\":\n await handleCheckQuotas(manager, client);\n continue;\n\n case \"manage\": {\n const result = await showManageAccounts(allAccounts);\n if (result.action === \"back\" || result.action === \"cancel\") continue;\n const manageResult = await handleManageAction(manager, result.action, result.account, client);\n if (manageResult.triggerOAuth) {\n const methodResult = await selectMethodAndStartFlow();\n if (!methodResult) continue;\n return wrapCallbackWithAccountReplace(methodResult.flow, manager, manageResult.account);\n }\n continue;\n }\n\n case \"load-balancing\":\n await handleLoadBalancing();\n continue;\n\n case \"delete-all\": {\n await manager.clearAllAccounts();\n console.log(\"\\nAll accounts deleted.\\n\");\n const result = await selectMethodAndStartFlow();\n if (!result) return makeFailedFlowResult(\"Authentication cancelled\");\n return wrapCallbackWithManagerSync(result.flow, manager);\n }\n\n case \"cancel\":\n return makeFailedFlowResult(\"Authentication cancelled\");\n }\n }\n}\n\nasync function handleCheckQuotas(manager: AccountManager, client?: PluginClient): Promise<void> {\n await manager.refresh();\n const accounts = manager.getAccounts();\n const effectiveClient = client ?? createMinimalClient();\n if (client) manager.setClient(client);\n console.log(`\\n📊 Checking quotas for ${accounts.length} account(s)...\\n`);\n\n for (const account of accounts) {\n if (account.isAuthDisabled || !account.accessToken || isTokenExpired(account)) {\n if (!account.uuid) {\n printQuotaError(account, \"Missing account UUID\");\n continue;\n }\n\n const result = await manager.ensureValidToken(account.uuid, effectiveClient);\n if (!result.ok) {\n printQuotaError(account, account.isAuthDisabled\n ? `${account.authDisabledReason ?? \"Auth disabled\"} (refresh failed)`\n : \"Failed to refresh token\");\n continue;\n }\n\n await manager.refresh();\n }\n\n const freshAccounts = manager.getAccounts();\n const freshAccount = freshAccounts.find((candidate) => candidate.uuid === account.uuid);\n\n if (!freshAccount?.accessToken) {\n printQuotaError(account, \"No access token available\");\n continue;\n }\n\n const usageResult = await fetchUsage(freshAccount.accessToken, freshAccount.accountId);\n if (!usageResult.ok) {\n printQuotaError(freshAccount, `Failed to fetch usage: ${usageResult.reason}`);\n continue;\n }\n\n if (freshAccount.uuid) {\n await manager.applyUsageCache(freshAccount.uuid, usageResult.data);\n }\n\n // Determine plan: JWT profile first, WHAM plan_type as fallback\n const profileResult = fetchProfile(freshAccount.accessToken);\n let email = freshAccount.email;\n let planTier = freshAccount.planTier ?? \"\";\n\n if (profileResult.ok) {\n email = profileResult.data.email ?? email;\n planTier = profileResult.data.planTier;\n }\n\n // If JWT didn't have plan info, use WHAM plan_type as fallback\n if ((!planTier || planTier === \"free\") && usageResult.planType) {\n planTier = derivePlanTier(usageResult.planType);\n }\n\n const profileData = { email, planTier };\n if (freshAccount.uuid) {\n await manager.applyProfileCache(freshAccount.uuid, profileData);\n }\n\n const reportAccount = { ...freshAccount, email, planTier };\n printQuotaReport(reportAccount, usageResult.data);\n }\n}\n\nasync function handleLoadBalancing(): Promise<void> {\n const current = getConfig().account_selection_strategy;\n const selected = await showStrategySelect(current);\n\n if (!selected || selected === current) return;\n\n await updateConfigField(\"account_selection_strategy\", selected);\n console.log(`\\nLoad balancing strategy changed: ${current} → ${selected}\\n`);\n}\n\ntype ManageActionResult =\n | { triggerOAuth: false }\n | { triggerOAuth: true; account: ManagedAccount };\n\nasync function handleManageAction(\n manager: AccountManager,\n action: string,\n account?: ManagedAccount,\n client?: PluginClient,\n): Promise<ManageActionResult> {\n if (!account) return { triggerOAuth: false };\n\n const label = getAccountLabel(account);\n\n switch (action) {\n case \"toggle\":\n if (!account.uuid) break;\n await manager.toggleEnabled(account.uuid);\n await manager.refresh();\n {\n const updated = manager.getAccounts().find((candidate) => candidate.uuid === account.uuid);\n console.log(`\\n${label} ${updated?.enabled ? \"enabled\" : \"disabled\"}.\\n`);\n }\n break;\n\n case \"delete\":\n if (!account.uuid) break;\n {\n const removed = await manager.removeAccount(account.index);\n console.log(removed ? \"\\nAccount deleted.\\n\" : \"\\nFailed to delete account.\\n\");\n }\n break;\n\n case \"retry-auth\": {\n if (!account.uuid) break;\n const effectiveClient = client ?? createMinimalClient();\n console.log(`\\nRetrying authentication for ${label}...\\n`);\n const result = await manager.retryAuth(account.uuid, effectiveClient);\n\n if (result.ok) {\n console.log(`✅ ${label} re-authenticated successfully.\\n`);\n } else {\n console.log(\"Token refresh failed — starting OAuth flow...\\n\");\n return { triggerOAuth: true, account };\n }\n break;\n }\n }\n\n return { triggerOAuth: false };\n}\n","export {\n ANSI,\n isTTY,\n parseKey,\n type KeyAction,\n} from \"opencode-multi-account-core\";\n","export {\n select,\n type MenuItem,\n type SelectOptions,\n} from \"opencode-multi-account-core\";\n","export { confirm } from \"opencode-multi-account-core\";\n","import { ANSI } from \"./ansi\";\nimport { select, type MenuItem } from \"./select\";\nimport { confirm } from \"./confirm\";\nimport { getAccountLabel } from \"../utils\";\nimport { getPlanLabel } from \"../usage\";\nimport type { AccountSelectionStrategy, ManagedAccount, UsageLimits } from \"../types\";\n\nexport type AuthMenuAction =\n | { type: \"add\" }\n | { type: \"check-quotas\" }\n | { type: \"manage\" }\n | { type: \"load-balancing\" }\n | { type: \"delete-all\" }\n | { type: \"cancel\" };\n\nexport type AccountAction = \"back\" | \"toggle\" | \"delete\" | \"retry-auth\" | \"cancel\";\n\nfunction formatRelativeTime(timestamp: number | undefined): string {\n if (!timestamp) return \"never\";\n const days = Math.floor((Date.now() - timestamp) / 86_400_000);\n if (days === 0) return \"today\";\n if (days === 1) return \"yesterday\";\n if (days < 7) return `${days}d ago`;\n if (days < 30) return `${Math.floor(days / 7)}w ago`;\n return new Date(timestamp).toLocaleDateString();\n}\n\nfunction formatDate(timestamp: number | undefined): string {\n if (!timestamp) return \"unknown\";\n return new Date(timestamp).toLocaleDateString();\n}\n\ntype AccountStatus = \"active\" | \"rate-limited\" | \"auth-disabled\" | \"disabled\";\n\nexport function getAccountStatus(account: ManagedAccount): AccountStatus {\n if (account.isAuthDisabled) return \"auth-disabled\";\n if (!account.enabled) return \"disabled\";\n if (account.cachedUsage) {\n const now = Date.now();\n const usage = account.cachedUsage;\n const hasEvaluableUsageTier = [usage.five_hour, usage.seven_day].some((tier) => tier != null);\n const exhaustedTiers = [usage.five_hour, usage.seven_day].filter((tier) =>\n tier\n && tier.utilization >= 100\n && tier.resets_at != null\n && Date.parse(tier.resets_at) > now,\n );\n if (exhaustedTiers.length > 0) {\n return \"rate-limited\";\n }\n if (hasEvaluableUsageTier) {\n return \"active\";\n }\n }\n if (account.rateLimitResetAt && account.rateLimitResetAt > Date.now()) return \"rate-limited\";\n return \"active\";\n}\n\nconst STATUS_BADGE: Record<AccountStatus, string> = {\n \"active\": `${ANSI.green}[active]${ANSI.reset}`,\n \"rate-limited\": `${ANSI.yellow}[rate-limited]${ANSI.reset}`,\n \"auth-disabled\": `${ANSI.red}[auth-disabled]${ANSI.reset}`,\n \"disabled\": `${ANSI.red}[disabled]${ANSI.reset}`,\n};\n\nfunction buildAccountMenuItem(account: ManagedAccount): MenuItem<ManagedAccount> {\n const label = getAccountLabel(account);\n const status = getAccountStatus(account);\n const badge = STATUS_BADGE[status];\n const fullLabel = `${label} ${badge}`;\n\n return {\n label: fullLabel,\n hint: account.lastUsed ? `used ${formatRelativeTime(account.lastUsed)}` : \"\",\n value: account,\n disabled: false,\n };\n}\n\nexport async function showAuthMenu(accounts: ManagedAccount[]): Promise<AuthMenuAction> {\n const items: MenuItem<AuthMenuAction>[] = [\n { label: \"Add new account\", value: { type: \"add\" }, color: \"green\" },\n { label: \"Check quotas\", value: { type: \"check-quotas\" }, color: \"cyan\" },\n { label: \"Manage accounts\", value: { type: \"manage\" } },\n { label: \"Load balancing\", value: { type: \"load-balancing\" } },\n { label: \"\", value: { type: \"cancel\" }, separator: true },\n { label: \"Delete all accounts\", value: { type: \"delete-all\" }, color: \"red\" },\n ];\n\n while (true) {\n const subtitle = `${accounts.length} account(s) registered`;\n const result = await select(items, {\n message: \"Codex Multi-Auth\",\n subtitle,\n });\n\n if (!result) return { type: \"cancel\" };\n\n if (result.type === \"delete-all\") {\n const confirmed = await confirm(\"Delete ALL accounts? This cannot be undone.\");\n if (!confirmed) continue;\n }\n\n return result;\n }\n}\n\nexport async function showManageAccounts(accounts: ManagedAccount[]): Promise<{ action: AccountAction; account?: ManagedAccount }> {\n const items: MenuItem<ManagedAccount | null>[] = [\n { label: \"Back\", value: null },\n { label: \"\", value: null, separator: true },\n ...accounts.map(buildAccountMenuItem),\n ];\n\n const selected = await select(items, {\n message: \"Manage Accounts\",\n subtitle: \"Select an account to manage\",\n });\n\n if (!selected) return { action: \"back\" };\n\n return showAccountDetails(selected);\n}\n\nasync function showAccountDetails(account: ManagedAccount): Promise<{ action: AccountAction; account: ManagedAccount }> {\n const label = getAccountLabel(account);\n const status = getAccountStatus(account);\n const badge = STATUS_BADGE[status];\n\n console.log(\"\");\n console.log(`${ANSI.bold}Account: ${label} ${badge}${ANSI.reset}`);\n console.log(`${ANSI.dim}Added: ${formatDate(account.addedAt)}${ANSI.reset}`);\n console.log(`${ANSI.dim}Last used: ${formatRelativeTime(account.lastUsed)}${ANSI.reset}`);\n if (account.isAuthDisabled) {\n console.log(`${ANSI.red}Auth disabled: ${account.authDisabledReason ?? \"unknown\"}${ANSI.reset}`);\n }\n console.log(\"\");\n\n while (true) {\n const toggleLabel = account.enabled ? \"Disable account\" : \"Enable account\";\n const toggleColor = account.enabled ? \"yellow\" as const : \"green\" as const;\n\n const items: MenuItem<AccountAction>[] = [\n { label: \"Back\", value: \"back\" },\n ];\n\n items.push({ label: toggleLabel, value: \"toggle\", color: toggleColor });\n\n items.push({ label: \"Re-authenticate\", value: \"retry-auth\", color: \"cyan\" });\n\n items.push({ label: \"Delete this account\", value: \"delete\", color: \"red\" });\n\n const result = await select(items, {\n message: \"Account options\",\n subtitle: label,\n });\n\n if (result === \"delete\") {\n const confirmed = await confirm(`Delete ${label}?`);\n if (!confirmed) continue;\n }\n\n return { action: result ?? \"cancel\", account };\n }\n}\n\nfunction getUsageColor(utilization: number): string {\n if (utilization >= 90) return ANSI.red;\n if (utilization >= 60) return ANSI.yellow;\n return ANSI.green;\n}\n\nfunction createProgressBar(utilization: number, width = 20): string {\n const filled = Math.round((utilization / 100) * width);\n const empty = width - filled;\n const color = getUsageColor(utilization);\n return `${color}${\"█\".repeat(filled)}${ANSI.reset}${\"░\".repeat(empty)} ${color}${Math.round(utilization)}% used${ANSI.reset}`;\n}\n\nfunction formatResetTime(resetAt: string | null): string {\n if (!resetAt) return \"\";\n const date = new Date(resetAt);\n const now = new Date();\n const tz = Intl.DateTimeFormat().resolvedOptions().timeZone;\n\n const timeStr = date.toLocaleTimeString(undefined, { hour: \"numeric\", minute: \"2-digit\", hour12: true });\n\n const isSameDay = date.getFullYear() === now.getFullYear()\n && date.getMonth() === now.getMonth()\n && date.getDate() === now.getDate();\n\n if (isSameDay) {\n return ` (resets ${timeStr}, ${tz})`;\n }\n const dateStr = date.toLocaleDateString(undefined, { month: \"short\", day: \"numeric\" });\n return ` (resets ${dateStr} ${timeStr}, ${tz})`;\n}\n\nfunction printUsageEntry(name: string, entry: { utilization: number; resets_at: string | null } | null, isLast: boolean): void {\n const connector = isLast ? \"└─\" : \"├─\";\n if (!entry) {\n console.log(` ${connector} ${name.padEnd(16)} no data`);\n return;\n }\n const bar = createProgressBar(entry.utilization);\n const resetInfo = entry.resets_at\n ? formatResetTime(entry.resets_at)\n : \"\";\n console.log(` ${connector} ${name.padEnd(16)} ${bar}${resetInfo}`);\n}\n\nexport function printQuotaReport(account: ManagedAccount, usage: UsageLimits): void {\n const label = getAccountLabel(account);\n const status = getAccountStatus(account);\n const badge = STATUS_BADGE[status];\n const planLabel = getPlanLabel(account) || \"Free\";\n\n console.log(`━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━`);\n console.log(` ${label} ${badge}`);\n console.log(`━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━`);\n if (account.email) {\n console.log(` 📧 ${account.email}`);\n }\n console.log(` 📋 ${planLabel}`);\n\n console.log(`\\n └─ Codex Quota`);\n printUsageEntry(\"Current session\", usage.five_hour, false);\n printUsageEntry(\"Current week\", usage.seven_day, true);\n console.log(\"\");\n}\n\nconst STRATEGY_DESCRIPTIONS: Record<AccountSelectionStrategy, string> = {\n \"sticky\": \"Same account until rate-limited\",\n \"round-robin\": \"Rotate every request\",\n \"hybrid\": \"Score-based (usage + health)\",\n};\n\nexport async function showStrategySelect(current: AccountSelectionStrategy): Promise<AccountSelectionStrategy | null> {\n const strategies: AccountSelectionStrategy[] = [\"sticky\", \"round-robin\", \"hybrid\"];\n\n const items: MenuItem<AccountSelectionStrategy>[] = strategies.map((s) => ({\n label: `${s}${s === current ? \" (current)\" : \"\"}`,\n hint: STRATEGY_DESCRIPTIONS[s],\n value: s,\n }));\n\n return select(items, {\n message: \"Load Balancing Strategy\",\n subtitle: `Current: ${current}`,\n });\n}\n\nexport type AuthMethod = \"browser\" | \"headless\";\n\nexport async function showMethodSelect(): Promise<AuthMethod | null> {\n const items: MenuItem<AuthMethod>[] = [\n { label: \"ChatGPT Pro/Plus (browser)\", value: \"browser\", color: \"green\" },\n { label: \"ChatGPT Pro/Plus (headless)\", value: \"headless\" },\n ];\n\n return select(items, {\n message: \"Login Method\",\n subtitle: \"Select authentication method\",\n });\n}\n\nexport function printQuotaError(account: ManagedAccount, error: string): void {\n const label = getAccountLabel(account);\n console.log(`━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━`);\n console.log(` ${label}`);\n if (account.email) {\n console.log(` 📧 ${account.email}`);\n }\n console.log(`━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━`);\n console.log(` ${ANSI.red}Error: ${error}${ANSI.reset}\\n`);\n}\n","import {\n AccountStore,\n setAccountsFilename,\n type DiskCredentials,\n} from \"opencode-multi-account-core\";\nimport { ACCOUNTS_FILENAME } from \"./constants\";\n\nsetAccountsFilename(ACCOUNTS_FILENAME);\n\nexport {\n AccountStore,\n type DiskCredentials,\n};\n","import { createProactiveRefreshQueueForProvider } from \"opencode-multi-account-core\";\nimport { getConfig } from \"./config\";\nimport { isTokenExpired, refreshToken } from \"./token\";\nimport { debugLog } from \"./utils\";\n\nexport const ProactiveRefreshQueue = createProactiveRefreshQueueForProvider({\n providerAuthId: \"openai\",\n getConfig,\n isTokenExpired,\n refreshToken,\n debugLog,\n});\n\nexport type ProactiveRefreshQueue = InstanceType<typeof ProactiveRefreshQueue>;\n","import { CODEX_API_ENDPOINT, OPENAI_CLI_USER_AGENT } from \"./constants\";\n\nfunction mergeHeaders(base: Headers, incoming?: HeadersInit): void {\n if (!incoming) return;\n\n if (incoming instanceof Headers) {\n incoming.forEach((value, key) => base.set(key, value));\n return;\n }\n\n if (Array.isArray(incoming)) {\n for (const [key, value] of incoming) {\n if (value !== undefined) base.set(key, String(value));\n }\n return;\n }\n\n for (const [key, value] of Object.entries(incoming)) {\n if (value !== undefined) base.set(key, String(value));\n }\n}\n\nexport function buildRequestHeaders(\n input: RequestInfo | URL,\n init: RequestInit | undefined,\n accessToken: string,\n accountId?: string,\n): Headers {\n const headers = new Headers();\n\n if (input instanceof Request) {\n input.headers.forEach((value, key) => headers.set(key, value));\n }\n\n mergeHeaders(headers, init?.headers);\n\n headers.delete(\"authorization\");\n headers.delete(\"Authorization\");\n headers.set(\"authorization\", `Bearer ${accessToken}`);\n headers.set(\"originator\", \"opencode\");\n headers.set(\"User-Agent\", OPENAI_CLI_USER_AGENT);\n\n if (accountId) {\n headers.set(\"ChatGPT-Account-Id\", accountId);\n } else {\n headers.delete(\"ChatGPT-Account-Id\");\n }\n\n headers.delete(\"x-api-key\");\n\n return headers;\n}\n\nfunction asUrl(input: RequestInfo | URL): URL | null {\n try {\n if (typeof input === \"string\" || input instanceof URL) {\n return new URL(input.toString());\n }\n\n if (input instanceof Request) {\n return new URL(input.url);\n }\n\n return null;\n } catch {\n return null;\n }\n}\n\nexport function transformRequestUrl(input: RequestInfo | URL): RequestInfo | URL {\n const url = asUrl(input);\n if (!url) return input;\n\n const shouldRewrite = url.pathname.includes(\"/v1/responses\") || url.pathname.includes(\"/chat/completions\");\n if (!shouldRewrite) return input;\n\n const rewritten = new URL(CODEX_API_ENDPOINT);\n rewritten.search = url.search;\n\n if (input instanceof Request) {\n return new Request(rewritten.toString(), input);\n }\n\n return rewritten;\n}\n","import { AccountStore } from \"./account-store\";\nimport { isTokenExpired, refreshToken } from \"./token\";\nimport { buildRequestHeaders, transformRequestUrl } from \"./request-transform\";\nimport { TokenRefreshError } from \"opencode-multi-account-core\";\nimport type { PluginClient, StoredAccount } from \"./types\";\nimport { debugLog } from \"./utils\";\n\ntype BaseFetch = (input: RequestInfo | URL, init?: RequestInit) => Promise<Response>;\n\ninterface AccountRuntime {\n fetch: BaseFetch;\n}\n\nexport class AccountRuntimeFactory {\n private runtimes = new Map<string, AccountRuntime>();\n private initLocks = new Map<string, Promise<AccountRuntime>>();\n\n constructor(\n private readonly store: AccountStore,\n private readonly client: PluginClient,\n ) {}\n\n async getRuntime(uuid: string): Promise<AccountRuntime> {\n const cached = this.runtimes.get(uuid);\n if (cached) return cached;\n\n const existing = this.initLocks.get(uuid);\n if (existing) return existing;\n\n const initPromise = this.createRuntime(uuid);\n this.initLocks.set(uuid, initPromise);\n\n try {\n const runtime = await initPromise;\n this.runtimes.set(uuid, runtime);\n return runtime;\n } finally {\n this.initLocks.delete(uuid);\n }\n }\n\n invalidate(uuid: string): void {\n this.runtimes.delete(uuid);\n }\n\n invalidateAll(): void {\n this.runtimes.clear();\n }\n\n private async createRuntime(uuid: string): Promise<AccountRuntime> {\n const fetchWithAccount: BaseFetch = async (input, init) => {\n const storage = await this.store.load();\n const storedAccount = storage.accounts.find((account: StoredAccount) => account.uuid === uuid);\n if (!storedAccount) {\n throw new Error(`No credentials found for account ${uuid}`);\n }\n\n let accessToken = storedAccount.accessToken;\n let expiresAt = storedAccount.expiresAt;\n let accountId = storedAccount.accountId;\n\n if (!accessToken || !expiresAt || isTokenExpired({ accessToken, expiresAt })) {\n const refreshed = await refreshToken(storedAccount.refreshToken, uuid, this.client);\n if (!refreshed.ok) {\n throw new TokenRefreshError(refreshed.permanent, refreshed.status);\n }\n\n accessToken = refreshed.patch.accessToken;\n expiresAt = refreshed.patch.expiresAt;\n accountId = refreshed.patch.accountId ?? accountId;\n\n await this.store.mutateAccount(uuid, (account) => {\n account.accessToken = refreshed.patch.accessToken;\n account.expiresAt = refreshed.patch.expiresAt;\n if (refreshed.patch.refreshToken) account.refreshToken = refreshed.patch.refreshToken;\n if (refreshed.patch.accountId) account.accountId = refreshed.patch.accountId;\n if (refreshed.patch.email) account.email = refreshed.patch.email;\n account.consecutiveAuthFailures = 0;\n account.isAuthDisabled = false;\n account.authDisabledReason = undefined;\n });\n }\n\n if (!accessToken) {\n throw new Error(`No access token available for account ${uuid}`);\n }\n\n const transformedInput = transformRequestUrl(input);\n const headers = buildRequestHeaders(transformedInput, init, accessToken, accountId);\n\n return fetch(transformedInput, {\n ...init,\n headers,\n });\n };\n\n debugLog(this.client, `Runtime created for account ${uuid.slice(0, 8)}`);\n return { fetch: fetchWithAccount };\n }\n}\n"],"mappings":"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","names":["v","v","v","v","flow","formatResetTime","usage"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-codex-multi-account",
3
- "version": "0.2.6",
3
+ "version": "0.2.9",
4
4
  "description": "OpenCode plugin for Codex (OpenAI) multi-account management with automatic rate limit switching",
5
5
  "main": "./dist/index.js",
6
6
  "type": "module",
@@ -13,7 +13,7 @@
13
13
  }
14
14
  },
15
15
  "scripts": {
16
- "build": "esbuild src/index.ts --bundle --outdir=dist --platform=node --format=esm --packages=external && tsc -p tsconfig.build.json --emitDeclarationOnly",
16
+ "build": "tsup",
17
17
  "typecheck": "tsc --noEmit",
18
18
  "test": "for f in tests/*.test.ts; do bun test \"$f\" || exit 1; done",
19
19
  "prepack": "bun run build",
@@ -40,7 +40,7 @@
40
40
  "directory": "packages/codex-multi-account"
41
41
  },
42
42
  "dependencies": {
43
- "opencode-multi-account-core": "^0.2.6",
43
+ "opencode-multi-account-core": "^0.2.9",
44
44
  "valibot": "^1.2.0"
45
45
  },
46
46
  "devDependencies": {
@@ -1,2 +0,0 @@
1
- export declare const AccountManager: import("opencode-multi-account-core").AccountManagerClass;
2
- export type AccountManager = InstanceType<typeof AccountManager>;
@@ -1,2 +0,0 @@
1
- import { AccountStore, type DiskCredentials } from "opencode-multi-account-core";
2
- export { AccountStore, type DiskCredentials, };
@@ -1,20 +0,0 @@
1
- import { AccountManager } from "./account-manager";
2
- import type { PluginClient } from "./types";
3
- type OAuthCallbackResponse = ({
4
- type: "success";
5
- } & {
6
- refresh: string;
7
- access: string;
8
- expires: number;
9
- accountId?: string;
10
- }) | {
11
- type: "failed";
12
- };
13
- export interface OAuthFlowResult {
14
- url: string;
15
- instructions: string;
16
- method: "auto";
17
- callback(): Promise<OAuthCallbackResponse>;
18
- }
19
- export declare function handleAuthorize(manager: AccountManager | null, inputs?: Record<string, string>, client?: PluginClient): Promise<OAuthFlowResult>;
20
- export {};
package/dist/claims.d.ts DELETED
@@ -1 +0,0 @@
1
- export { isClaimedByOther, readClaims, releaseClaim, writeClaim, type ClaimsMap, } from "opencode-multi-account-core";
package/dist/config.d.ts DELETED
@@ -1,2 +0,0 @@
1
- import { getConfig, loadConfig, resetConfigCache, updateConfigField } from "opencode-multi-account-core";
2
- export { getConfig, loadConfig, resetConfigCache, updateConfigField, };
@@ -1,32 +0,0 @@
1
- /** OpenAI OAuth adapter config */
2
- export declare const OPENAI_OAUTH_ADAPTER: import("opencode-multi-account-core").OAuthAdapter;
3
- /** OpenAI OAuth Client ID */
4
- export declare const OPENAI_CLIENT_ID: string;
5
- /** Token exchange / refresh endpoint */
6
- export declare const OPENAI_TOKEN_ENDPOINT: string;
7
- /** OAuth usage stats endpoint */
8
- export declare const OPENAI_USAGE_ENDPOINT: string;
9
- /** OAuth profile endpoint */
10
- export declare const OPENAI_PROFILE_ENDPOINT: string;
11
- /** Codex upstream endpoint used by OpenCode */
12
- export declare const CODEX_API_ENDPOINT = "https://chatgpt.com/backend-api/codex/responses";
13
- /** Codex usage/quota endpoint (WHAM API) */
14
- export declare const CODEX_USAGE_ENDPOINT = "https://chatgpt.com/backend-api/wham/usage";
15
- /** OpenAI OAuth issuer */
16
- export declare const OAUTH_ISSUER = "https://auth.openai.com";
17
- /** Local callback port for browser OAuth */
18
- export declare const OAUTH_PORT = 1455;
19
- /** Required beta header for OAuth requests */
20
- export declare const OPENAI_BETA_HEADER: string;
21
- /** User-Agent header */
22
- export declare const OPENAI_CLI_USER_AGENT: string;
23
- /** Tool name prefix */
24
- export declare const TOOL_PREFIX: string;
25
- /** Account storage filename */
26
- export declare const ACCOUNTS_FILENAME: string;
27
- /** Plan display labels derived from adapter */
28
- export declare const PLAN_LABELS: import("opencode-multi-account-core").OAuthAdapterPlanLabels;
29
- /** Access token expiry buffer (refresh 60s before expiry) */
30
- export declare const TOKEN_EXPIRY_BUFFER_MS = 60000;
31
- /** Maximum time to wait for a token refresh HTTP request */
32
- export declare const TOKEN_REFRESH_TIMEOUT_MS = 30000;
@@ -1,2 +0,0 @@
1
- declare const executeWithAccountRotation: (manager: import("opencode-multi-account-core").ExecutorAccountManager, runtimeFactory: import("opencode-multi-account-core").ExecutorRuntimeFactory, client: import("opencode-multi-account-core").PluginClient, input: RequestInfo | URL, init?: RequestInit) => Promise<Response>;
2
- export { executeWithAccountRotation };
package/dist/oauth.d.ts DELETED
@@ -1,37 +0,0 @@
1
- import type { TokenResponse } from "./types";
2
- type PKCE = {
3
- verifier: string;
4
- challenge: string;
5
- };
6
- export declare function generatePKCE(): Promise<{
7
- verifier: string;
8
- challenge: string;
9
- }>;
10
- export declare function generateState(): string;
11
- export declare function exchangeCodeForTokens(code: string, redirectUri: string, pkce: PKCE): Promise<TokenResponse>;
12
- export declare function refreshAccessToken(refreshToken: string): Promise<TokenResponse>;
13
- export interface IdTokenClaims {
14
- chatgpt_account_id?: string;
15
- organizations?: Array<{
16
- id: string;
17
- }>;
18
- email?: string;
19
- "https://api.openai.com/auth"?: {
20
- chatgpt_account_id?: string;
21
- };
22
- }
23
- export declare function parseJwtClaims(token: string): IdTokenClaims | undefined;
24
- export declare function extractAccountId(tokens: {
25
- id_token?: string;
26
- access_token: string;
27
- }): string | undefined;
28
- export declare function startOAuthServer(): Promise<{
29
- port: number;
30
- redirectUri: string;
31
- }>;
32
- export declare function stopOAuthServer(): void;
33
- export declare function waitForOAuthCallback(pkce: PKCE, state: string): Promise<TokenResponse>;
34
- export declare function buildAuthorizeUrl(redirectUri: string, pkce: {
35
- challenge: string;
36
- }, state: string): string;
37
- export {};
@@ -1,2 +0,0 @@
1
- export declare const ProactiveRefreshQueue: import("opencode-multi-account-core").ProactiveRefreshQueueClass;
2
- export type ProactiveRefreshQueue = InstanceType<typeof ProactiveRefreshQueue>;
@@ -1,2 +0,0 @@
1
- declare const fetchUsageLimits: (accessToken: string, accountId?: string) => Promise<import("opencode-multi-account-core").UsageLimits | null>, getResetMsFromUsage: (account: import("opencode-multi-account-core").ManagedAccount) => number | null, handleRateLimitResponse: (manager: import("opencode-multi-account-core").RateLimitAccountManager, client: import("opencode-multi-account-core").PluginClient, account: import("opencode-multi-account-core").ManagedAccount, response: Response) => Promise<void>, retryAfterMsFromResponse: (response: Response) => number;
2
- export { fetchUsageLimits, getResetMsFromUsage, handleRateLimitResponse, retryAfterMsFromResponse, };
@@ -1,2 +0,0 @@
1
- export declare function buildRequestHeaders(input: RequestInfo | URL, init: RequestInit | undefined, accessToken: string, accountId?: string): Headers;
2
- export declare function transformRequestUrl(input: RequestInfo | URL): RequestInfo | URL;
@@ -1,18 +0,0 @@
1
- import { AccountStore } from "./account-store";
2
- import type { PluginClient } from "./types";
3
- type BaseFetch = (input: RequestInfo | URL, init?: RequestInit) => Promise<Response>;
4
- interface AccountRuntime {
5
- fetch: BaseFetch;
6
- }
7
- export declare class AccountRuntimeFactory {
8
- private readonly store;
9
- private readonly client;
10
- private runtimes;
11
- private initLocks;
12
- constructor(store: AccountStore, client: PluginClient);
13
- getRuntime(uuid: string): Promise<AccountRuntime>;
14
- invalidate(uuid: string): void;
15
- invalidateAll(): void;
16
- private createRuntime;
17
- }
18
- export {};
package/dist/storage.d.ts DELETED
@@ -1 +0,0 @@
1
- export { deduplicateAccounts, loadAccounts, readStorageFromDisk, } from "opencode-multi-account-core";
package/dist/token.d.ts DELETED
@@ -1,4 +0,0 @@
1
- import { type ManagedAccount, type PluginClient, type TokenRefreshResult } from "./types";
2
- export declare function isTokenExpired(account: Pick<ManagedAccount, "accessToken" | "expiresAt">): boolean;
3
- export declare function refreshToken(currentRefreshToken: string, accountId: string, client: PluginClient): Promise<TokenRefreshResult>;
4
- export declare function clearRefreshMutex(accountId?: string): void;