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.
- package/README.md +17 -10
- package/config/README.md +12 -12
- package/config/opencode-legacy.json +125 -0
- package/config/opencode-modern.json +43 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +36 -2
- package/dist/index.js.map +1 -1
- package/dist/lib/auto-update-checker.d.ts +7 -1
- package/dist/lib/auto-update-checker.d.ts.map +1 -1
- package/dist/lib/auto-update-checker.js +51 -3
- package/dist/lib/auto-update-checker.js.map +1 -1
- package/dist/lib/codex-usage.d.ts +91 -0
- package/dist/lib/codex-usage.d.ts.map +1 -0
- package/dist/lib/codex-usage.js +368 -0
- package/dist/lib/codex-usage.js.map +1 -0
- package/dist/lib/config.d.ts +1 -0
- package/dist/lib/config.d.ts.map +1 -1
- package/dist/lib/config.js +4 -0
- package/dist/lib/config.js.map +1 -1
- package/dist/lib/schemas.d.ts +1 -0
- package/dist/lib/schemas.d.ts.map +1 -1
- package/dist/lib/schemas.js +1 -0
- package/dist/lib/schemas.js.map +1 -1
- package/dist/lib/tools/codex-limits.d.ts.map +1 -1
- package/dist/lib/tools/codex-limits.js +39 -340
- package/dist/lib/tools/codex-limits.js.map +1 -1
- package/dist/lib/tools/codex-switch.d.ts.map +1 -1
- package/dist/lib/tools/codex-switch.js +9 -0
- package/dist/lib/tools/codex-switch.js.map +1 -1
- package/dist/lib/tui-quota-cache.d.ts +33 -0
- package/dist/lib/tui-quota-cache.d.ts.map +1 -0
- package/dist/lib/tui-quota-cache.js +247 -0
- package/dist/lib/tui-quota-cache.js.map +1 -0
- package/dist/lib/tui-status.d.ts +55 -0
- package/dist/lib/tui-status.d.ts.map +1 -0
- package/dist/lib/tui-status.js +343 -0
- package/dist/lib/tui-status.js.map +1 -0
- package/dist/tui.d.ts +6 -0
- package/dist/tui.d.ts.map +1 -0
- package/dist/tui.js +363 -0
- package/dist/tui.js.map +1 -0
- package/package.json +16 -2
- 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
|
[](https://nodejs.org)
|
|
9
9
|
[](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,
|
|
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
|
|
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
|
-
|
|
43
|
-
|
|
44
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
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 --
|
|
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
|
|
10
|
-
| [`opencode-legacy.json`](./opencode-legacy.json) | **v1.0.209 and below** | Legacy explicit entries:
|
|
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
|
|
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
|
|
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-
|
|
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.
|
|
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
|
|
58
|
+
Recommended compact UI selectors:
|
|
59
59
|
|
|
60
60
|
```bash
|
|
61
|
-
opencode run "task" --model=openai/gpt-5.5
|
|
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
|
|
66
|
+
If you need direct explicit selector IDs for scripts, install with:
|
|
66
67
|
|
|
67
68
|
```bash
|
|
68
|
-
|
|
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
|
|
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": {
|
package/dist/index.d.ts.map
CHANGED
|
@@ -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;
|
|
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) {
|