oc-codex-multi-auth 6.1.3 → 6.1.7

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 (43) hide show
  1. package/README.md +17 -10
  2. package/config/README.md +12 -12
  3. package/config/opencode-legacy.json +125 -0
  4. package/config/opencode-modern.json +43 -0
  5. package/dist/index.d.ts.map +1 -1
  6. package/dist/index.js +36 -2
  7. package/dist/index.js.map +1 -1
  8. package/dist/lib/auto-update-checker.d.ts +7 -1
  9. package/dist/lib/auto-update-checker.d.ts.map +1 -1
  10. package/dist/lib/auto-update-checker.js +51 -3
  11. package/dist/lib/auto-update-checker.js.map +1 -1
  12. package/dist/lib/codex-usage.d.ts +91 -0
  13. package/dist/lib/codex-usage.d.ts.map +1 -0
  14. package/dist/lib/codex-usage.js +368 -0
  15. package/dist/lib/codex-usage.js.map +1 -0
  16. package/dist/lib/config.d.ts +1 -0
  17. package/dist/lib/config.d.ts.map +1 -1
  18. package/dist/lib/config.js +4 -0
  19. package/dist/lib/config.js.map +1 -1
  20. package/dist/lib/schemas.d.ts +1 -0
  21. package/dist/lib/schemas.d.ts.map +1 -1
  22. package/dist/lib/schemas.js +1 -0
  23. package/dist/lib/schemas.js.map +1 -1
  24. package/dist/lib/tools/codex-limits.d.ts.map +1 -1
  25. package/dist/lib/tools/codex-limits.js +39 -340
  26. package/dist/lib/tools/codex-limits.js.map +1 -1
  27. package/dist/lib/tools/codex-switch.d.ts.map +1 -1
  28. package/dist/lib/tools/codex-switch.js +9 -0
  29. package/dist/lib/tools/codex-switch.js.map +1 -1
  30. package/dist/lib/tui-quota-cache.d.ts +33 -0
  31. package/dist/lib/tui-quota-cache.d.ts.map +1 -0
  32. package/dist/lib/tui-quota-cache.js +247 -0
  33. package/dist/lib/tui-quota-cache.js.map +1 -0
  34. package/dist/lib/tui-status.d.ts +55 -0
  35. package/dist/lib/tui-status.d.ts.map +1 -0
  36. package/dist/lib/tui-status.js +343 -0
  37. package/dist/lib/tui-status.js.map +1 -0
  38. package/dist/tui.d.ts +6 -0
  39. package/dist/tui.d.ts.map +1 -0
  40. package/dist/tui.js +363 -0
  41. package/dist/tui.js.map +1 -0
  42. package/package.json +16 -2
  43. package/scripts/install-oc-codex-multi-auth-core.js +119 -18
package/README.md CHANGED
@@ -8,6 +8,8 @@ Badges: CI + OpenSSF Scorecard will turn green once Phase 3 Batch A (CI workflow
8
8
  [![Node.js Version](https://img.shields.io/node/v/oc-codex-multi-auth.svg)](https://nodejs.org)
9
9
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
10
10
 
11
+ <img width="1227" height="702" alt="cover" src="https://github.com/user-attachments/assets/b796eb2f-282e-468a-ba6a-acadf09d731b" />
12
+
11
13
  Use your ChatGPT Plus/Pro subscription inside OpenCode with OAuth login, GPT-5/Codex model presets, and multi-account failover.
12
14
 
13
15
  `oc-codex-multi-auth` is an OpenCode plugin for developers who want Codex-first GPT-5 workflows in OpenCode without switching to separate Platform API credentials for personal use. It uses the same official OAuth flow as the Codex CLI, adds model templates for current GPT-5 families, and can rotate across multiple ChatGPT accounts when one account is rate-limited or unavailable.
@@ -15,7 +17,7 @@ Use your ChatGPT Plus/Pro subscription inside OpenCode with OAuth login, GPT-5/C
15
17
  ## What This Project Does
16
18
 
17
19
  - Adds an OpenCode plugin that authenticates with ChatGPT Plus/Pro through official OAuth
18
- - Ships ready-to-use GPT-5.5 templates, explicit `gpt-5.5-medium` / `gpt-5.5-high` selectors, `gpt-5-codex`, and related GPT-5 families
20
+ - Ships ready-to-use GPT-5.5 OAuth model templates, variant picker presets, optional explicit selector IDs, `gpt-5-codex`, and related GPT-5 families
19
21
  - Routes requests through a stateless Codex-compatible request pipeline with automatic token refresh
20
22
  - Supports multi-account rotation, per-project account storage, and guided onboarding commands
21
23
 
@@ -29,7 +31,7 @@ npx -y oc-codex-multi-auth@latest
29
31
  opencode auth login
30
32
 
31
33
  # 3. Run a prompt in OpenCode
32
- opencode run "Explain this repository" --model=openai/gpt-5.5-medium
34
+ opencode run "Explain this repository" --model=openai/gpt-5.5 --variant=medium
33
35
  ```
34
36
 
35
37
  What the installer does:
@@ -39,17 +41,21 @@ What the installer does:
39
41
  - normalizes the plugin entry to `"oc-codex-multi-auth"`
40
42
  - clears the cached plugin copy so OpenCode reinstalls the latest package
41
43
 
42
- By default, the installer now writes a full catalog config that includes both:
43
- - modern base model entries such as `gpt-5.5` for `--variant` workflows
44
- - explicit preset entries such as `gpt-5.5-medium` / `gpt-5.5-high` so the shipped catalog is visible directly in model pickers
44
+ After install, the plugin checks npm once per day. When a newer version exists, it clears its OpenCode-managed cached package on exit; restart OpenCode and the latest package is installed automatically. Disable this with `"autoUpdate": false` in `~/.opencode/openai-codex-auth-config.json` or `CODEX_AUTH_AUTO_UPDATE=0`.
45
+
46
+ By default, the installer writes the compact UI config:
47
+ - model picker entries stay on actual OAuth model families such as `gpt-5.5` and `gpt-5.5-fast`
48
+ - reasoning presets are selected through OpenCode's model variant picker (`none`, `low`, `medium`, `high`, `xhigh`)
49
+ - rerunning the default installer removes explicit preset entries and stale base models from earlier plugin catalogs
45
50
 
46
- Tested live on OpenCode `1.14.22`: explicit GPT-5.5 model IDs like `openai/gpt-5.5-medium` and `openai/gpt-5.5-high` work directly. Some OpenCode releases still reject bare `openai/gpt-5.5` on the CLI even when the base config entry exists in the effective config.
51
+ If you prefer direct model IDs such as `openai/gpt-5.5-medium` or `openai/gpt-5.5-fast-medium`, install with `--full`.
47
52
 
48
53
  ## Example Usage
49
54
 
50
55
  ```bash
51
56
  # General GPT-5 workflow
52
- opencode run "Summarize the failing test and suggest a fix" --model=openai/gpt-5.5-medium
57
+ opencode run "Summarize the failing test and suggest a fix" --model=openai/gpt-5.5 --variant=medium
58
+ opencode run "Summarize the failing test and suggest a fix" --model=openai/gpt-5.5-fast --variant=medium
53
59
 
54
60
  # Codex-focused workflow
55
61
  opencode run "Refactor the retry logic and update the tests" --model=openai/gpt-5-codex --variant=high
@@ -82,11 +88,12 @@ OpenCode users often want the same GPT-5 and Codex model experience they use in
82
88
  - Beginner-focused commands such as `codex-setup`, `codex-help`, `codex-doctor`, and `codex-next`
83
89
  - Interactive account switching, labeling, tagging, and backup/import commands
84
90
  - Stateless request handling with `reasoning.encrypted_content` for multi-turn sessions
91
+ - Daily npm update detection with OpenCode cache refresh on restart
85
92
  - Request logging and troubleshooting hooks for debugging OpenCode integration issues
86
93
 
87
94
  ## Common Workflows
88
95
 
89
- - Personal coding sessions in OpenCode using `gpt-5.5-medium`, `gpt-5.5-high`, or `gpt-5-codex`
96
+ - Personal coding sessions in OpenCode using `gpt-5.5` / `gpt-5.5-fast` with variants, or `gpt-5-codex`
90
97
  - Switching between personal and workspace-linked ChatGPT accounts
91
98
  - Keeping separate account pools per project or monorepo
92
99
  - Recovering from unsupported-model, auth, or rate-limit issues with guided commands
@@ -106,10 +113,10 @@ See [Architecture](docs/development/ARCHITECTURE.md) for implementation details.
106
113
 
107
114
  Use the quick-start path above for the fastest setup. For full setup, local development installs, legacy OpenCode support, and verification steps, see [Getting Started](docs/getting-started.md).
108
115
 
109
- If you prefer the compact variant-only config on OpenCode `v1.0.210+`, use:
116
+ For direct selector IDs in scripts or older habits, use the full catalog:
110
117
 
111
118
  ```bash
112
- npx -y oc-codex-multi-auth@latest --modern
119
+ npx -y oc-codex-multi-auth@latest --full
113
120
  ```
114
121
 
115
122
  ## Configuration
package/config/README.md CHANGED
@@ -6,10 +6,10 @@ This directory contains the official OpenCode config templates for `oc-codex-mul
6
6
 
7
7
  | File | OpenCode version | Description |
8
8
  |------|------------------|-------------|
9
- | [`opencode-modern.json`](./opencode-modern.json) | **v1.0.210+** | Variant-based config: 9 base models with 34 total presets |
10
- | [`opencode-legacy.json`](./opencode-legacy.json) | **v1.0.209 and below** | Legacy explicit entries: 34 individual model definitions |
9
+ | [`opencode-modern.json`](./opencode-modern.json) | **v1.0.210+** | Variant-based config: 9 base models with 36 total presets |
10
+ | [`opencode-legacy.json`](./opencode-legacy.json) | **v1.0.209 and below** | Legacy explicit entries: 36 individual model definitions |
11
11
 
12
- The installer currently uses a merged full-catalog mode by default so users get both the modern base entries and the explicit preset entries without having to hand-edit `opencode.json`.
12
+ The installer uses the compact modern template by default so the model picker shows only base OAuth model families. Rerun the default installer to remove explicit preset IDs and stale base models left by earlier plugin catalogs. Use `--full` when you want the explicit preset IDs installed too.
13
13
 
14
14
  ## Quick pick
15
15
 
@@ -36,12 +36,12 @@ opencode --version
36
36
  OpenCode v1.0.210+ added model `variants`, so one model entry can expose multiple reasoning levels. That keeps modern config much smaller while preserving the same effective presets.
37
37
 
38
38
  Both templates include:
39
- - GPT-5.5, GPT-5.5 Pro, GPT-5.4 Mini, GPT-5.4 Nano, GPT-5 Codex, GPT-5.1, GPT-5.1 Codex, GPT-5.1 Codex Max, GPT-5.1 Codex Mini
39
+ - GPT-5.5, GPT-5.5 Fast, GPT-5.4 Mini, GPT-5.4 Nano, GPT-5 Codex, GPT-5.1, GPT-5.1 Codex, GPT-5.1 Codex Max, GPT-5.1 Codex Mini
40
40
  - Reasoning variants per model family
41
41
  - `store: false` and `include: ["reasoning.encrypted_content"]`
42
- - Context metadata (`gpt-5.5`/`gpt-5.5-pro`: 1,050,000; `gpt-5.4-mini`/`gpt-5.4-nano`/Codex models: 400,000; `gpt-5.1`: 272,000; all output: 128,000)
42
+ - Context metadata (`gpt-5.5`/`gpt-5.5-fast`: 1,050,000; `gpt-5.4-mini`/`gpt-5.4-nano`/Codex models: 400,000; `gpt-5.1`: 272,000; all output: 128,000)
43
43
 
44
- Use `opencode debug config` to verify that these template entries were merged into your effective config. On tested OpenCode `1.14.22`, `opencode models openai` exposes explicit GPT-5.5 entries such as `gpt-5.5-medium` / `gpt-5.5-high`, while bare `gpt-5.5` may still be omitted or rejected by provider lookup even when it exists in the effective config.
44
+ Use `opencode debug config` to verify that these template entries were merged into your effective config. The default compact install shows base OAuth entries such as `gpt-5.5` / `gpt-5.5-fast`; the separate OpenCode variant picker exposes the reasoning presets.
45
45
 
46
46
  If your OpenCode runtime supports global compaction tuning, you can also set:
47
47
  - `model_context_window = 1050000`
@@ -55,17 +55,18 @@ If your workspace is entitled, you can add Spark model IDs manually.
55
55
 
56
56
  ## Usage examples
57
57
 
58
- Recommended real-session selectors (tested on OpenCode `1.14.22`):
58
+ Recommended compact UI selectors:
59
59
 
60
60
  ```bash
61
- opencode run "task" --model=openai/gpt-5.5-medium
61
+ opencode run "task" --model=openai/gpt-5.5 --variant=medium
62
+ opencode run "task" --model=openai/gpt-5.5-fast --variant=medium
62
63
  opencode run "task" --model=openai/gpt-5-codex --variant=high
63
64
  ```
64
65
 
65
- If your OpenCode release already exposes bare GPT-5.5 base entries, the compact modern template also supports:
66
+ If you need direct explicit selector IDs for scripts, install with:
66
67
 
67
68
  ```bash
68
- opencode run "task" --model=openai/gpt-5.5 --variant=medium
69
+ npx -y oc-codex-multi-auth@latest --full
69
70
  ```
70
71
 
71
72
  ## Minimal config (advanced)
@@ -79,13 +80,12 @@ Current defaults are strict entitlement handling:
79
80
  - set `unsupportedCodexPolicy: "fallback"` (or `CODEX_AUTH_UNSUPPORTED_MODEL_POLICY=fallback`) to enable automatic fallback retries
80
81
  - `fallbackToGpt52OnUnsupportedGpt53: true` keeps the legacy `gpt-5.3-codex -> gpt-5.2-codex` edge inside fallback mode
81
82
  - `gpt-5.5 -> gpt-5.4` is included by default for accounts/workspaces that do not yet expose GPT-5.5
82
- - `gpt-5.5-pro -> gpt-5.5` is included by default in fallback mode
83
+ - user-typed `gpt-5.5-pro*` is canonicalized to `gpt-5.5` before fallback because GPT-5.5 Pro is ChatGPT-only, not a Codex-routable model
83
84
  - `gpt-5.4-pro -> gpt-5.4` remains available for older manual configs
84
85
  - `unsupportedCodexFallbackChain` lets you override fallback order per model
85
86
 
86
87
  Default fallback chain (when policy is `fallback`):
87
88
  - `gpt-5.5 -> gpt-5.4`
88
- - `gpt-5.5-pro -> gpt-5.5`
89
89
  - `gpt-5.4-pro -> gpt-5.4` (if you manually select `gpt-5.4-pro`)
90
90
  - `gpt-5.3-codex -> gpt-5-codex -> gpt-5.2-codex`
91
91
  - `gpt-5.3-codex-spark -> gpt-5-codex -> gpt-5.3-codex -> gpt-5.2-codex` (only relevant if Spark IDs are added manually)
@@ -140,6 +140,131 @@
140
140
  "store": false
141
141
  }
142
142
  },
143
+ "gpt-5.5-fast-none": {
144
+ "name": "GPT 5.5 Fast None (OAuth)",
145
+ "limit": {
146
+ "context": 1050000,
147
+ "output": 128000
148
+ },
149
+ "modalities": {
150
+ "input": [
151
+ "text",
152
+ "image"
153
+ ],
154
+ "output": [
155
+ "text"
156
+ ]
157
+ },
158
+ "options": {
159
+ "reasoningEffort": "none",
160
+ "reasoningSummary": "auto",
161
+ "textVerbosity": "medium",
162
+ "include": [
163
+ "reasoning.encrypted_content"
164
+ ],
165
+ "store": false
166
+ }
167
+ },
168
+ "gpt-5.5-fast-low": {
169
+ "name": "GPT 5.5 Fast Low (OAuth)",
170
+ "limit": {
171
+ "context": 1050000,
172
+ "output": 128000
173
+ },
174
+ "modalities": {
175
+ "input": [
176
+ "text",
177
+ "image"
178
+ ],
179
+ "output": [
180
+ "text"
181
+ ]
182
+ },
183
+ "options": {
184
+ "reasoningEffort": "low",
185
+ "reasoningSummary": "auto",
186
+ "textVerbosity": "medium",
187
+ "include": [
188
+ "reasoning.encrypted_content"
189
+ ],
190
+ "store": false
191
+ }
192
+ },
193
+ "gpt-5.5-fast-medium": {
194
+ "name": "GPT 5.5 Fast Medium (OAuth)",
195
+ "limit": {
196
+ "context": 1050000,
197
+ "output": 128000
198
+ },
199
+ "modalities": {
200
+ "input": [
201
+ "text",
202
+ "image"
203
+ ],
204
+ "output": [
205
+ "text"
206
+ ]
207
+ },
208
+ "options": {
209
+ "reasoningEffort": "medium",
210
+ "reasoningSummary": "auto",
211
+ "textVerbosity": "medium",
212
+ "include": [
213
+ "reasoning.encrypted_content"
214
+ ],
215
+ "store": false
216
+ }
217
+ },
218
+ "gpt-5.5-fast-high": {
219
+ "name": "GPT 5.5 Fast High (OAuth)",
220
+ "limit": {
221
+ "context": 1050000,
222
+ "output": 128000
223
+ },
224
+ "modalities": {
225
+ "input": [
226
+ "text",
227
+ "image"
228
+ ],
229
+ "output": [
230
+ "text"
231
+ ]
232
+ },
233
+ "options": {
234
+ "reasoningEffort": "high",
235
+ "reasoningSummary": "detailed",
236
+ "textVerbosity": "medium",
237
+ "include": [
238
+ "reasoning.encrypted_content"
239
+ ],
240
+ "store": false
241
+ }
242
+ },
243
+ "gpt-5.5-fast-xhigh": {
244
+ "name": "GPT 5.5 Fast Extra High (OAuth)",
245
+ "limit": {
246
+ "context": 1050000,
247
+ "output": 128000
248
+ },
249
+ "modalities": {
250
+ "input": [
251
+ "text",
252
+ "image"
253
+ ],
254
+ "output": [
255
+ "text"
256
+ ]
257
+ },
258
+ "options": {
259
+ "reasoningEffort": "xhigh",
260
+ "reasoningSummary": "detailed",
261
+ "textVerbosity": "medium",
262
+ "include": [
263
+ "reasoning.encrypted_content"
264
+ ],
265
+ "store": false
266
+ }
267
+ },
143
268
  "gpt-5.4-mini-none": {
144
269
  "name": "GPT 5.4 Mini None (OAuth)",
145
270
  "limit": {
@@ -58,6 +58,49 @@
58
58
  }
59
59
  }
60
60
  },
61
+ "gpt-5.5-fast": {
62
+ "name": "GPT 5.5 Fast (OAuth)",
63
+ "limit": {
64
+ "context": 1050000,
65
+ "output": 128000
66
+ },
67
+ "modalities": {
68
+ "input": [
69
+ "text",
70
+ "image"
71
+ ],
72
+ "output": [
73
+ "text"
74
+ ]
75
+ },
76
+ "variants": {
77
+ "none": {
78
+ "reasoningEffort": "none",
79
+ "reasoningSummary": "auto",
80
+ "textVerbosity": "medium"
81
+ },
82
+ "low": {
83
+ "reasoningEffort": "low",
84
+ "reasoningSummary": "auto",
85
+ "textVerbosity": "medium"
86
+ },
87
+ "medium": {
88
+ "reasoningEffort": "medium",
89
+ "reasoningSummary": "auto",
90
+ "textVerbosity": "medium"
91
+ },
92
+ "high": {
93
+ "reasoningEffort": "high",
94
+ "reasoningSummary": "detailed",
95
+ "textVerbosity": "medium"
96
+ },
97
+ "xhigh": {
98
+ "reasoningEffort": "xhigh",
99
+ "reasoningSummary": "detailed",
100
+ "textVerbosity": "medium"
101
+ }
102
+ }
103
+ },
61
104
  "gpt-5.4-mini": {
62
105
  "name": "GPT 5.4 Mini (OAuth)",
63
106
  "limit": {
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAKH,OAAO,KAAK,EAAE,MAAM,EAAe,MAAM,qBAAqB,CAAC;AA2L/D;;;;;;;;;;;;;;;GAeG;AAEH,eAAO,MAAM,iBAAiB,EAAE,MA60G/B,CAAC;AAEF,eAAO,MAAM,gBAAgB,QAAoB,CAAC;AAElD,eAAe,iBAAiB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAKH,OAAO,KAAK,EAAE,MAAM,EAAe,MAAM,qBAAqB,CAAC;AAkM/D;;;;;;;;;;;;;;;GAeG;AAEH,eAAO,MAAM,iBAAiB,EAAE,MA03G/B,CAAC;AAEF,eAAO,MAAM,gBAAgB,QAAoB,CAAC;AAElD,eAAe,iBAAiB,CAAC"}
package/dist/index.js CHANGED
@@ -32,7 +32,7 @@ import { queuedRefresh } from "./lib/refresh-queue.js";
32
32
  import { openBrowserUrl } from "./lib/auth/browser.js";
33
33
  import { startLocalOAuthServer } from "./lib/auth/server.js";
34
34
  import { promptAddAnotherAccount, promptLoginMode } from "./lib/cli.js";
35
- import { getCodexMode, getRequestTransformMode, getFastSession, getFastSessionStrategy, getFastSessionMaxInputItems, getRetryProfile, getRetryBudgetOverrides, getRateLimitToastDebounceMs, getRetryAllAccountsMaxRetries, getRetryAllAccountsMaxWaitMs, getRetryAllAccountsRateLimited, getFallbackToGpt52OnUnsupportedGpt53, getUnsupportedCodexPolicy, getUnsupportedCodexFallbackChain, getTokenRefreshSkewMs, getSessionRecovery, getAutoResume, getToastDurationMs, getPerProjectAccounts, getEmptyResponseMaxRetries, getEmptyResponseRetryDelayMs, getPidOffsetEnabled, getFetchTimeoutMs, getStreamStallTimeoutMs, getCodexTuiV2, getCodexTuiColorProfile, getCodexTuiGlyphMode, getBeginnerSafeMode, loadPluginConfig, } from "./lib/config.js";
35
+ import { getCodexMode, getRequestTransformMode, getFastSession, getFastSessionStrategy, getFastSessionMaxInputItems, getRetryProfile, getRetryBudgetOverrides, getRateLimitToastDebounceMs, getRetryAllAccountsMaxRetries, getRetryAllAccountsMaxWaitMs, getRetryAllAccountsRateLimited, getFallbackToGpt52OnUnsupportedGpt53, getUnsupportedCodexPolicy, getUnsupportedCodexFallbackChain, getTokenRefreshSkewMs, getSessionRecovery, getAutoResume, getAutoUpdate, getToastDurationMs, getPerProjectAccounts, getEmptyResponseMaxRetries, getEmptyResponseRetryDelayMs, getPidOffsetEnabled, getFetchTimeoutMs, getStreamStallTimeoutMs, getCodexTuiV2, getCodexTuiColorProfile, getCodexTuiGlyphMode, getBeginnerSafeMode, loadPluginConfig, } from "./lib/config.js";
36
36
  import { AUTH_LABELS, CODEX_BASE_URL, DUMMY_API_KEY, LOG_STAGES, PLUGIN_NAME, PROVIDER_ID, ACCOUNT_LIMITS, } from "./lib/constants.js";
37
37
  import { initLogger, logRequest, logDebug, logInfo, logWarn, logError, setCorrelationId, clearCorrelationId, } from "./lib/logger.js";
38
38
  import { checkAndNotify } from "./lib/auto-update-checker.js";
@@ -55,6 +55,8 @@ import { prewarmOpenCodeCodexPrompt } from "./lib/prompts/opencode-codex.js";
55
55
  import { createSessionRecoveryHook, isRecoverableError, detectErrorType, getRecoveryToastContent, } from "./lib/recovery.js";
56
56
  import { matchesWorkspaceIdentity, upsertFlaggedAccountRecord, createRetryBudgetUsage, serializeSelectionExplainability, formatRoutingValue, formatExplainabilitySummary, } from "./lib/runtime.js";
57
57
  import { createToolRegistry, } from "./lib/tools/index.js";
58
+ import { createUsageAccountFingerprint } from "./lib/codex-usage.js";
59
+ import { clearTuiQuotaSnapshot, parseTuiQuotaSnapshotFromHeaders, writeTuiQuotaSnapshot, } from "./lib/tui-quota-cache.js";
58
60
  /**
59
61
  * OpenAI Codex OAuth authentication plugin for opencode
60
62
  *
@@ -290,6 +292,31 @@ export const OpenAIOAuthPlugin = async ({ client }) => {
290
292
  // Ignore when TUI is not available.
291
293
  }
292
294
  };
295
+ const clearPromptQuotaCache = async () => {
296
+ try {
297
+ await clearTuiQuotaSnapshot();
298
+ }
299
+ catch (error) {
300
+ logDebug(`[${PLUGIN_NAME}] Failed to clear TUI quota cache: ${error instanceof Error ? error.message : String(error)}`);
301
+ }
302
+ };
303
+ const recordPromptQuotaHeaders = async (response, account, accountCount) => {
304
+ try {
305
+ const snapshot = parseTuiQuotaSnapshotFromHeaders(response.headers, {
306
+ fingerprint: createUsageAccountFingerprint(account),
307
+ accountIndex: account.index + 1,
308
+ accountCount,
309
+ accountEmail: account.email?.trim() || undefined,
310
+ accountLabel: formatAccountLabel(account, account.index),
311
+ });
312
+ if (!snapshot)
313
+ return;
314
+ await writeTuiQuotaSnapshot(snapshot);
315
+ }
316
+ catch (error) {
317
+ logDebug(`[${PLUGIN_NAME}] Failed to record TUI quota headers: ${error instanceof Error ? error.message : String(error)}`);
318
+ }
319
+ };
293
320
  const resolveActiveIndex = (storage, family = "codex") => {
294
321
  const total = storage.accounts.length;
295
322
  if (total === 0)
@@ -844,6 +871,7 @@ export const OpenAIOAuthPlugin = async ({ client }) => {
844
871
  storage.activeIndexByFamily[family] = index;
845
872
  }
846
873
  await saveAccounts(storage);
874
+ await clearPromptQuotaCache();
847
875
  // Reload manager from disk so we don't overwrite newer rotated
848
876
  // refresh tokens with stale in-memory state.
849
877
  if (cachedAccountManager) {
@@ -1026,6 +1054,7 @@ export const OpenAIOAuthPlugin = async ({ client }) => {
1026
1054
  const streamStallTimeoutMs = getStreamStallTimeoutMs(pluginConfig);
1027
1055
  const sessionRecoveryEnabled = getSessionRecovery(pluginConfig);
1028
1056
  const autoResumeEnabled = getAutoResume(pluginConfig);
1057
+ const autoUpdateEnabled = getAutoUpdate(pluginConfig);
1029
1058
  const emptyResponseMaxRetries = getEmptyResponseMaxRetries(pluginConfig);
1030
1059
  const emptyResponseRetryDelayMs = getEmptyResponseRetryDelayMs(pluginConfig);
1031
1060
  const pidOffsetEnabled = getPidOffsetEnabled(pluginConfig);
@@ -1064,7 +1093,7 @@ export const OpenAIOAuthPlugin = async ({ client }) => {
1064
1093
  : null;
1065
1094
  checkAndNotify(async (message, variant) => {
1066
1095
  await showToast(message, variant);
1067
- }).catch((err) => {
1096
+ }, { autoUpdate: autoUpdateEnabled }).catch((err) => {
1068
1097
  logDebug(`Update check failed: ${err instanceof Error ? err.message : String(err)}`);
1069
1098
  });
1070
1099
  await runStartupPreflight();
@@ -1357,6 +1386,10 @@ export const OpenAIOAuthPlugin = async ({ client }) => {
1357
1386
  }
1358
1387
  account.email =
1359
1388
  extractAccountEmail(accountAuth.access) ?? account.email;
1389
+ // Keep the persisted active identity in step with the account used
1390
+ // for this request so the TUI quota cache accepts the next real
1391
+ // response-header snapshot instead of filtering it as stale.
1392
+ accountManager.saveToDiskDebounced();
1360
1393
  if (accountCount > 1 &&
1361
1394
  accountManager.shouldShowAccountToast(account.index, rateLimitToastDebounceMs)) {
1362
1395
  const accountLabel = formatAccountLabel(account, account.index);
@@ -1480,6 +1513,7 @@ export const OpenAIOAuthPlugin = async ({ client }) => {
1480
1513
  latencyMs: fetchLatencyMs,
1481
1514
  headers: Object.fromEntries(response.headers.entries()),
1482
1515
  });
1516
+ void recordPromptQuotaHeaders(response, account, accountCount);
1483
1517
  if (!response.ok) {
1484
1518
  const contextOverflowResult = await handleContextOverflow(response, model);
1485
1519
  if (contextOverflowResult.handled) {