oc-codex-multi-auth 6.1.3 → 6.1.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/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,19 @@ 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
+ By default, the installer writes the compact UI config:
45
+ - model picker entries stay on actual OAuth model families such as `gpt-5.5` and `gpt-5.5-fast`
46
+ - reasoning presets are selected through OpenCode's model variant picker (`none`, `low`, `medium`, `high`, `xhigh`)
47
+ - rerunning the default installer removes explicit preset entries and stale base models from earlier plugin catalogs
45
48
 
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.
49
+ If you prefer direct model IDs such as `openai/gpt-5.5-medium` or `openai/gpt-5.5-fast-medium`, install with `--full`.
47
50
 
48
51
  ## Example Usage
49
52
 
50
53
  ```bash
51
54
  # General GPT-5 workflow
52
- opencode run "Summarize the failing test and suggest a fix" --model=openai/gpt-5.5-medium
55
+ opencode run "Summarize the failing test and suggest a fix" --model=openai/gpt-5.5 --variant=medium
56
+ opencode run "Summarize the failing test and suggest a fix" --model=openai/gpt-5.5-fast --variant=medium
53
57
 
54
58
  # Codex-focused workflow
55
59
  opencode run "Refactor the retry logic and update the tests" --model=openai/gpt-5-codex --variant=high
@@ -86,7 +90,7 @@ OpenCode users often want the same GPT-5 and Codex model experience they use in
86
90
 
87
91
  ## Common Workflows
88
92
 
89
- - Personal coding sessions in OpenCode using `gpt-5.5-medium`, `gpt-5.5-high`, or `gpt-5-codex`
93
+ - Personal coding sessions in OpenCode using `gpt-5.5` / `gpt-5.5-fast` with variants, or `gpt-5-codex`
90
94
  - Switching between personal and workspace-linked ChatGPT accounts
91
95
  - Keeping separate account pools per project or monorepo
92
96
  - Recovering from unsupported-model, auth, or rate-limit issues with guided commands
@@ -106,10 +110,10 @@ See [Architecture](docs/development/ARCHITECTURE.md) for implementation details.
106
110
 
107
111
  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
112
 
109
- If you prefer the compact variant-only config on OpenCode `v1.0.210+`, use:
113
+ For direct selector IDs in scripts or older habits, use the full catalog:
110
114
 
111
115
  ```bash
112
- npx -y oc-codex-multi-auth@latest --modern
116
+ npx -y oc-codex-multi-auth@latest --full
113
117
  ```
114
118
 
115
119
  ## 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;AAiM/D;;;;;;;;;;;;;;;GAeG;AAEH,eAAO,MAAM,iBAAiB,EAAE,MAy3G/B,CAAC;AAEF,eAAO,MAAM,gBAAgB,QAAoB,CAAC;AAElD,eAAe,iBAAiB,CAAC"}
package/dist/index.js CHANGED
@@ -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) {
@@ -1357,6 +1385,10 @@ export const OpenAIOAuthPlugin = async ({ client }) => {
1357
1385
  }
1358
1386
  account.email =
1359
1387
  extractAccountEmail(accountAuth.access) ?? account.email;
1388
+ // Keep the persisted active identity in step with the account used
1389
+ // for this request so the TUI quota cache accepts the next real
1390
+ // response-header snapshot instead of filtering it as stale.
1391
+ accountManager.saveToDiskDebounced();
1360
1392
  if (accountCount > 1 &&
1361
1393
  accountManager.shouldShowAccountToast(account.index, rateLimitToastDebounceMs)) {
1362
1394
  const accountLabel = formatAccountLabel(account, account.index);
@@ -1480,6 +1512,7 @@ export const OpenAIOAuthPlugin = async ({ client }) => {
1480
1512
  latencyMs: fetchLatencyMs,
1481
1513
  headers: Object.fromEntries(response.headers.entries()),
1482
1514
  });
1515
+ void recordPromptQuotaHeaders(response, account, accountCount);
1483
1516
  if (!response.ok) {
1484
1517
  const contextOverflowResult = await handleContextOverflow(response, model);
1485
1518
  if (contextOverflowResult.handled) {