@bitkyc08/opencodex 2.42.0 → 2.43.0

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 (246) hide show
  1. package/AGENTS_INSTALL.md +2 -2
  2. package/README.md +31 -0
  3. package/bin/ocx.mjs +10 -1
  4. package/gui/dist/assets/index-DS1NE4Jn.css +1 -0
  5. package/gui/dist/assets/index-Djowl68T.js +112 -0
  6. package/gui/dist/index.html +2 -2
  7. package/package.json +1 -1
  8. package/src/adapters/anthropic-image-codec.ts +304 -0
  9. package/src/adapters/anthropic-image-normalize.ts +8 -298
  10. package/src/adapters/anthropic.ts +30 -7
  11. package/src/adapters/command-code.ts +7 -5
  12. package/src/adapters/cursor/desktop-executor-contract.ts +15 -0
  13. package/src/adapters/cursor/images.ts +36 -6
  14. package/src/adapters/cursor/live-transport.ts +7 -2
  15. package/src/adapters/cursor/native-exec-desktop.ts +2 -15
  16. package/src/adapters/cursor/protobuf-request.ts +13 -3
  17. package/src/adapters/cursor/tool-definitions.ts +5 -670
  18. package/src/adapters/cursor/tool-guidance.ts +236 -0
  19. package/src/adapters/cursor/tool-naming.ts +252 -0
  20. package/src/adapters/cursor/tool-schemas.ts +195 -0
  21. package/src/adapters/cursor/types.ts +6 -3
  22. package/src/adapters/exec-tool-result-normalize.ts +1 -1
  23. package/src/adapters/google-errors.ts +9 -1
  24. package/src/adapters/google.ts +1 -0
  25. package/src/adapters/kiro-calibration.ts +181 -0
  26. package/src/adapters/kiro.ts +135 -3
  27. package/src/adapters/openai-responses.ts +216 -26
  28. package/src/adapters/responses-code-mode.ts +59 -0
  29. package/src/adapters/tool-catalog-nudge.ts +1 -1
  30. package/src/adapters/xai-schema-analysis.ts +86 -0
  31. package/src/adapters/xai-tool-schema.ts +2 -87
  32. package/src/adapters/xai-web-search.ts +1 -1
  33. package/src/bridge.ts +22 -10
  34. package/src/chat/inbound.ts +11 -3
  35. package/src/claude/inbound-content-options.ts +60 -0
  36. package/src/claude/inbound-model-options.ts +142 -0
  37. package/src/claude/inbound-records.ts +7 -0
  38. package/src/claude/inbound.ts +10 -202
  39. package/src/claude/model-info.ts +45 -0
  40. package/src/cli/account-auth.ts +21 -6
  41. package/src/cli/capabilities.ts +13 -2
  42. package/src/cli/claude.ts +232 -39
  43. package/src/cli/config-command.ts +9 -1
  44. package/src/cli/dispatch.ts +5 -1
  45. package/src/cli/doctor.ts +10 -0
  46. package/src/cli/effort.ts +372 -0
  47. package/src/cli/export-command.ts +3 -9
  48. package/src/cli/help.ts +1 -0
  49. package/src/cli/index.ts +13 -0
  50. package/src/cli/init.ts +4 -0
  51. package/src/cli/model-selection-guidance.ts +30 -0
  52. package/src/cli/models-runtime.ts +3 -2
  53. package/src/cli/models.ts +8 -3
  54. package/src/cli/opencode.ts +4 -1
  55. package/src/cli/provider-runtime.ts +65 -0
  56. package/src/cli/provider.ts +8 -0
  57. package/src/cli/registry.ts +16 -2
  58. package/src/cli/runtime-api.ts +3 -1
  59. package/src/cli/star-prompt.ts +22 -6
  60. package/src/cli/status-probes.ts +168 -0
  61. package/src/cli/status.ts +5 -168
  62. package/src/clients/config-export/constants.ts +69 -0
  63. package/src/clients/config-export/contracts.ts +154 -0
  64. package/src/clients/config-export/dsh.ts +132 -0
  65. package/src/clients/config-export/fast-models.ts +29 -0
  66. package/src/clients/config-export/mcode.ts +83 -0
  67. package/src/clients/config-export/model-metadata.ts +108 -0
  68. package/src/clients/config-export/omp.ts +104 -0
  69. package/src/clients/config-export/zcode.ts +92 -0
  70. package/src/clients/config-export.ts +18 -710
  71. package/src/codex/account-lifecycle.ts +20 -3
  72. package/src/codex/account-usability.ts +2 -0
  73. package/src/codex/auth-api.ts +170 -23
  74. package/src/codex/auth-context.ts +328 -24
  75. package/src/codex/catalog/effort.ts +30 -4
  76. package/src/codex/catalog/metadata.ts +39 -9
  77. package/src/codex/catalog/native-models.ts +53 -12
  78. package/src/codex/catalog/parsing.ts +119 -5
  79. package/src/codex/catalog/provider-fetch.ts +150 -20
  80. package/src/codex/catalog/reserve.ts +52 -0
  81. package/src/codex/catalog/sync.ts +89 -16
  82. package/src/codex/convergence-types.ts +1 -0
  83. package/src/codex/convergence.ts +2 -0
  84. package/src/codex/data/upstream-models.json +1 -1
  85. package/src/codex/forward-transport-headers.ts +25 -0
  86. package/src/codex/inject.ts +3 -28
  87. package/src/codex/legacy-config-keys.ts +68 -0
  88. package/src/codex/log-guard/inspect-schema.ts +137 -0
  89. package/src/codex/log-guard/inspect.ts +2 -134
  90. package/src/codex/loopback-target.ts +54 -0
  91. package/src/codex/main-account-cache.ts +63 -1
  92. package/src/codex/main-account-hard-lock.ts +52 -0
  93. package/src/codex/main-account.ts +3 -1
  94. package/src/codex/management-convergence.ts +3 -0
  95. package/src/codex/model-entitlements.ts +54 -4
  96. package/src/codex/project-config-warnings.ts +92 -2
  97. package/src/codex/prompt-layers/encoding.ts +80 -0
  98. package/src/codex/prompt-layers/paths.ts +54 -0
  99. package/src/codex/prompt-layers/revision.ts +55 -0
  100. package/src/codex/prompt-layers/toml-edit.ts +163 -0
  101. package/src/codex/prompt-layers/toml-read.ts +181 -0
  102. package/src/codex/prompt-layers.ts +14 -520
  103. package/src/codex/quota-auto-refresh-state.ts +16 -0
  104. package/src/codex/quota-auto-refresh.ts +219 -0
  105. package/src/codex/quota-types.ts +51 -0
  106. package/src/codex/quota.ts +252 -93
  107. package/src/codex/reserve-availability.ts +177 -0
  108. package/src/codex/routing.ts +28 -9
  109. package/src/codex/shim.ts +53 -11
  110. package/src/codex/subagent-model-fallback.ts +23 -3
  111. package/src/combos/failover.ts +125 -7
  112. package/src/combos/identifiers.ts +89 -0
  113. package/src/combos/index.ts +4 -0
  114. package/src/combos/resolve.ts +80 -9
  115. package/src/combos/types.ts +20 -93
  116. package/src/config/subagent-models.ts +24 -0
  117. package/src/config.ts +156 -13
  118. package/src/generated/compatibility-version.json +454 -166
  119. package/src/generated/model-metadata.ts +1 -1
  120. package/src/integrations/journal.ts +65 -4
  121. package/src/integrations/store.ts +5 -0
  122. package/src/lab/events/limits.ts +4 -0
  123. package/src/lib/destination-policy.ts +31 -2
  124. package/src/lib/errors.ts +39 -0
  125. package/src/lib/provider-outbound.ts +69 -3
  126. package/src/lib/proxy-env.ts +22 -0
  127. package/src/lib/redact-folding.ts +176 -0
  128. package/src/lib/redact.ts +2 -175
  129. package/src/lib/state-store-sweeper.ts +20 -6
  130. package/src/lib/token-estimate.ts +94 -27
  131. package/src/lib/windows-user-principal.ts +53 -5
  132. package/src/oauth/anthropic-routing.ts +99 -3
  133. package/src/oauth/generic-account-failover.ts +36 -13
  134. package/src/oauth/index.ts +127 -26
  135. package/src/oauth/login-cli.ts +5 -0
  136. package/src/oauth/meta-muse.ts +117 -15
  137. package/src/oauth/pool-settings-capability.ts +15 -4
  138. package/src/providers/api-keys.ts +8 -10
  139. package/src/providers/default-aliases.ts +39 -0
  140. package/src/providers/derive.ts +10 -2
  141. package/src/providers/fastwire.ts +36 -7
  142. package/src/providers/initial-model-selection-runtime.ts +90 -0
  143. package/src/providers/initial-model-selection.ts +120 -0
  144. package/src/providers/key-failover.ts +134 -54
  145. package/src/providers/key-store.ts +11 -1
  146. package/src/providers/label.ts +1 -1
  147. package/src/providers/model-discovery.ts +76 -0
  148. package/src/providers/model-rename-startup.ts +72 -8
  149. package/src/providers/openai-sidecar.ts +17 -5
  150. package/src/providers/openai-tiers-destination.ts +102 -0
  151. package/src/providers/openai-tiers.ts +2 -99
  152. package/src/providers/opencode-go-transport.ts +41 -0
  153. package/src/providers/quota-key-accounts.ts +141 -0
  154. package/src/providers/quota-types.ts +9 -0
  155. package/src/providers/quota.ts +535 -104
  156. package/src/providers/registry.ts +60 -17
  157. package/src/providers/xai-responses-opt-in.ts +31 -5
  158. package/src/quota/reset-activation.ts +81 -0
  159. package/src/quota/reset-detector.ts +305 -0
  160. package/src/quota/reset-notify-config.ts +162 -0
  161. package/src/quota/reset-observer.ts +125 -0
  162. package/src/quota/reset-poller.ts +160 -0
  163. package/src/quota/reset-seen-store.ts +385 -0
  164. package/src/quota/reset-sinks.ts +199 -0
  165. package/src/quota/window-mapping.ts +106 -0
  166. package/src/responses/apply-patch-envelope.ts +46 -0
  167. package/src/responses/code-mode-helper-compat.ts +39 -1
  168. package/src/responses/custom-tool-compat.ts +10 -4
  169. package/src/responses/hosted-tool-policy.ts +12 -4
  170. package/src/responses/parser-content.ts +133 -0
  171. package/src/responses/parser-text-format.ts +24 -0
  172. package/src/responses/parser-tools.ts +188 -0
  173. package/src/responses/parser.ts +3 -326
  174. package/src/responses/state.ts +124 -28
  175. package/src/router.ts +48 -13
  176. package/src/routing/analytics.ts +1 -0
  177. package/src/routing/capability.ts +17 -4
  178. package/src/server/auth-cors.ts +7 -1
  179. package/src/server/background-lifecycle.ts +23 -1
  180. package/src/server/chat-completions.ts +25 -3
  181. package/src/server/claude-messages.ts +62 -5
  182. package/src/server/effort-row.ts +1 -1
  183. package/src/server/fast-row.ts +295 -0
  184. package/src/server/gui-static.ts +30 -4
  185. package/src/server/index.ts +107 -21
  186. package/src/server/management/agent-settings-routes.ts +2 -2
  187. package/src/server/management/combo-routes.ts +37 -9
  188. package/src/server/management/config-routes.ts +93 -2
  189. package/src/server/management/integration-routes.ts +108 -0
  190. package/src/server/management/model-routes.ts +13 -3
  191. package/src/server/management/model-rows.ts +20 -1
  192. package/src/server/management/native-integration-routes.ts +4 -1
  193. package/src/server/management/oauth-account-routes.ts +38 -10
  194. package/src/server/management/provider-routes.ts +34 -3
  195. package/src/server/management/quota-reset-routes.ts +57 -0
  196. package/src/server/management/route-registry.ts +7 -4
  197. package/src/server/management/shared.ts +19 -5
  198. package/src/server/management/system-routes.ts +3 -2
  199. package/src/server/management-api.ts +14 -2
  200. package/src/server/ports.ts +12 -2
  201. package/src/server/relay-eager.ts +38 -23
  202. package/src/server/relay.ts +4 -0
  203. package/src/server/request-log.ts +6 -0
  204. package/src/server/responses/codex-ws-correlation.ts +65 -0
  205. package/src/server/responses/codex-ws-exchange.ts +261 -0
  206. package/src/server/responses/codex-ws-metadata.ts +134 -0
  207. package/src/server/responses/codex-ws-pool.ts +162 -0
  208. package/src/server/responses/codex-ws-request.ts +87 -0
  209. package/src/server/responses/codex-ws-session.ts +93 -0
  210. package/src/server/responses/codex-ws-wire.ts +144 -0
  211. package/src/server/responses/collaboration.ts +41 -1
  212. package/src/server/responses/compact.ts +105 -12
  213. package/src/server/responses/core.ts +476 -57
  214. package/src/server/responses/fetch-helpers.ts +10 -3
  215. package/src/server/responses/input-admission.ts +16 -9
  216. package/src/server/responses/responses-field-backfill.ts +1 -1
  217. package/src/server/responses/ws-upstream.ts +34 -318
  218. package/src/server/responses-custom-tool-repair.ts +20 -4
  219. package/src/server/responses-undeclared-tool-guard.ts +100 -8
  220. package/src/server/safe-response-headers.ts +23 -0
  221. package/src/server/search.ts +9 -0
  222. package/src/server/subagent-models-startup.ts +27 -0
  223. package/src/server/system-env-shell.ts +238 -0
  224. package/src/server/system-env.ts +7 -234
  225. package/src/server/ws-bridge.ts +3 -25
  226. package/src/server/xai-responses-startup.ts +21 -0
  227. package/src/service-manager-probe.ts +1 -1
  228. package/src/service.ts +55 -16
  229. package/src/types/config.ts +108 -12
  230. package/src/types/provider.ts +36 -7
  231. package/src/types/tools.ts +26 -1
  232. package/src/types.ts +2 -0
  233. package/src/update/notify.ts +8 -2
  234. package/src/usage/cost.ts +38 -28
  235. package/src/usage/expected-prices.ts +34 -15
  236. package/src/usage/log.ts +2 -0
  237. package/src/usage/model-identity.ts +26 -0
  238. package/src/usage/summary.ts +15 -1
  239. package/src/vision/describe.ts +6 -0
  240. package/src/vision/image-rewrite.ts +108 -0
  241. package/src/vision/index.ts +19 -306
  242. package/src/vision/plan.ts +205 -0
  243. package/src/web-search/executor.ts +6 -0
  244. package/src/web-search/index.ts +8 -1
  245. package/gui/dist/assets/index-BU1tE0sr.js +0 -112
  246. package/gui/dist/assets/index-DL9-iS6J.css +0 -1
@@ -0,0 +1,219 @@
1
+ import { mutatePersistedConfig } from "../config";
2
+ import { registerStateSweepAfterTick } from "../lib/state-store-sweeper";
3
+ import { isCanonicalOpenAiForwardProvider, OPENAI_CODEX_PROVIDER_ID } from "../providers/openai-tiers";
4
+ import { normalizeResetAt } from "../providers/quota-wire";
5
+ import { providerCodexAccountMode } from "../providers/registry";
6
+ import type { OcxConfig } from "../types";
7
+ import { isSelectableCodexPoolAccount } from "./account-id";
8
+ import { reconcileMainCodexAccountRuntimeState } from "./account-lifecycle";
9
+ import { isCodexAccountPaused } from "./account-pause";
10
+ import { isAccountNeedsReauth } from "./account-runtime-state";
11
+ import { getValidCodexToken } from "./account-store";
12
+ import { getMainAccountToken, getValidMainAccountToken, MAIN_CODEX_ACCOUNT_ID } from "./main-account";
13
+ import { isMainAccountHardLocked } from "./main-account-hard-lock";
14
+ import { tryAcquireNativeMainProfileClaim } from "./native-main-admission";
15
+ import { withNativeMainSharedClaim } from "./native-main-claim";
16
+ import { resolveNativeProfileContext } from "./native-profile-store";
17
+ import { getAccountQuota, type StoredAccountQuota } from "./quota";
18
+ import { warmCodexAccount } from "./warmup";
19
+ import {
20
+ completedByAccount, retryAfterByAccount, resetCodexQuotaAutoRefreshStateForTests,
21
+ type CodexQuotaAutoRefreshWindows,
22
+ } from "./quota-auto-refresh-state";
23
+ export type { CodexQuotaAutoRefreshWindows } from "./quota-auto-refresh-state";
24
+ export { forgetCodexQuotaAutoRefreshAccount } from "./quota-auto-refresh-state";
25
+
26
+ export const FIVE_HOUR_WINDOW_SECONDS = 5 * 60 * 60;
27
+ const RETRY_MS = 5 * 60_000;
28
+ const CONCURRENCY = 4;
29
+
30
+ export interface CodexQuotaAutoRefreshStatus {
31
+ fiveHourAvailable: boolean;
32
+ weeklyAvailable: boolean;
33
+ fiveHourEnabled: boolean;
34
+ weeklyEnabled: boolean;
35
+ }
36
+
37
+ export interface CodexQuotaAutoRefreshRunDeps {
38
+ getQuota?: (accountId: string) => StoredAccountQuota | null;
39
+ /** Only false means skipped; existing void callbacks still report a successful warmup. */
40
+ warmAccount?: (config: OcxConfig, accountId: string) => Promise<void | false>;
41
+ persistCompleted?: (
42
+ config: OcxConfig,
43
+ accountId: string,
44
+ completed: CodexQuotaAutoRefreshWindows,
45
+ ) => boolean;
46
+ }
47
+
48
+ let inFlight: Promise<void> | null = null;
49
+
50
+ export function codexQuotaAutoRefreshStatus(
51
+ config: OcxConfig,
52
+ accountId: string,
53
+ quota: StoredAccountQuota | null,
54
+ ): CodexQuotaAutoRefreshStatus {
55
+ const saved = config.codexQuotaAutoRefresh?.[accountId];
56
+ return {
57
+ fiveHourAvailable: quota?.shortWindowSeconds === FIVE_HOUR_WINDOW_SECONDS
58
+ && typeof quota.shortResetAt === "number",
59
+ weeklyAvailable: typeof quota?.weeklyResetAt === "number",
60
+ fiveHourEnabled: saved?.fiveHour === true,
61
+ weeklyEnabled: saved?.weekly === true,
62
+ };
63
+ }
64
+
65
+ export function dueCodexQuotaAutoRefreshWindows(
66
+ config: OcxConfig,
67
+ accountId: string,
68
+ quota: StoredAccountQuota | null,
69
+ now: number,
70
+ completed = completedByAccount.get(accountId),
71
+ ): CodexQuotaAutoRefreshWindows | null {
72
+ if (!quota) return null;
73
+ const saved = config.codexQuotaAutoRefresh?.[accountId];
74
+ const due: CodexQuotaAutoRefreshWindows = {};
75
+ const shortResetAt = normalizeResetAt(quota.shortResetAt);
76
+ const weeklyResetAt = normalizeResetAt(quota.weeklyResetAt);
77
+ if (saved?.fiveHour === true
78
+ && quota.shortWindowSeconds === FIVE_HOUR_WINDOW_SECONDS
79
+ && shortResetAt !== undefined
80
+ && shortResetAt <= now
81
+ && normalizeResetAt(saved.lastFiveHourResetAt) !== shortResetAt
82
+ && normalizeResetAt(completed?.fiveHour) !== shortResetAt) {
83
+ due.fiveHour = shortResetAt;
84
+ }
85
+ if (saved?.weekly === true
86
+ && weeklyResetAt !== undefined
87
+ && weeklyResetAt <= now
88
+ && normalizeResetAt(saved.lastWeeklyResetAt) !== weeklyResetAt
89
+ && normalizeResetAt(completed?.weekly) !== weeklyResetAt) {
90
+ due.weekly = weeklyResetAt;
91
+ }
92
+ return due.fiveHour === undefined && due.weekly === undefined ? null : due;
93
+ }
94
+
95
+ function mainWarmupRestricted(config: OcxConfig): boolean {
96
+ return isMainAccountHardLocked(config)
97
+ || isCodexAccountPaused(config, MAIN_CODEX_ACCOUNT_ID)
98
+ || isAccountNeedsReauth(MAIN_CODEX_ACCOUNT_ID);
99
+ }
100
+
101
+ async function warmAccount(config: OcxConfig, accountId: string): Promise<void | false> {
102
+ if (accountId !== MAIN_CODEX_ACCOUNT_ID) {
103
+ await warmCodexAccount(await getValidCodexToken(accountId));
104
+ return;
105
+ }
106
+ const lease = tryAcquireNativeMainProfileClaim();
107
+ if (!lease) throw new Error("native main busy");
108
+ try {
109
+ reconcileMainCodexAccountRuntimeState();
110
+ if (mainWarmupRestricted(config)) return false;
111
+ // Refresh may need exclusive ownership. Finish it before the warmup's shared ownership.
112
+ const prepared = await getValidMainAccountToken({ preserveReauth: true });
113
+ if (!prepared) throw new Error("main account unavailable");
114
+ return await withNativeMainSharedClaim(resolveNativeProfileContext(), async (): Promise<void | false> => {
115
+ const token = getMainAccountToken();
116
+ if (!token || token.accessToken !== prepared.accessToken
117
+ || token.chatgptAccountId !== prepared.chatgptAccountId) return false;
118
+ if (mainWarmupRestricted(config)) return false;
119
+ await warmCodexAccount(token);
120
+ });
121
+ } finally {
122
+ lease.release();
123
+ }
124
+ }
125
+
126
+ function persistCompleted(
127
+ config: OcxConfig,
128
+ accountId: string,
129
+ completed: CodexQuotaAutoRefreshWindows,
130
+ ): boolean {
131
+ try {
132
+ const outcome = mutatePersistedConfig(persisted => {
133
+ const saved = persisted.codexQuotaAutoRefresh?.[accountId];
134
+ if (!saved) return { changed: false, value: null };
135
+ const next = {
136
+ ...saved,
137
+ ...(completed.fiveHour !== undefined ? { lastFiveHourResetAt: completed.fiveHour } : {}),
138
+ ...(completed.weekly !== undefined ? { lastWeeklyResetAt: completed.weekly } : {}),
139
+ };
140
+ persisted.codexQuotaAutoRefresh = { ...persisted.codexQuotaAutoRefresh, [accountId]: next };
141
+ return { changed: true, value: next };
142
+ });
143
+ if (outcome.status === "unavailable" || !outcome.value) return false;
144
+ config.codexQuotaAutoRefresh = { ...config.codexQuotaAutoRefresh, [accountId]: outcome.value };
145
+ return true;
146
+ } catch {
147
+ return false;
148
+ }
149
+ }
150
+
151
+ function retryPendingMarkers(
152
+ config: OcxConfig,
153
+ persist: NonNullable<CodexQuotaAutoRefreshRunDeps["persistCompleted"]>,
154
+ ): void {
155
+ for (const [accountId, completed] of completedByAccount) {
156
+ const saved = config.codexQuotaAutoRefresh?.[accountId];
157
+ if (!saved) continue;
158
+ if ((completed.fiveHour === undefined
159
+ || normalizeResetAt(saved.lastFiveHourResetAt) === normalizeResetAt(completed.fiveHour))
160
+ && (completed.weekly === undefined
161
+ || normalizeResetAt(saved.lastWeeklyResetAt) === normalizeResetAt(completed.weekly))) continue;
162
+ persist(config, accountId, completed);
163
+ }
164
+ }
165
+
166
+ export async function runCodexQuotaAutoRefresh(
167
+ config: OcxConfig,
168
+ now = Date.now(),
169
+ deps: CodexQuotaAutoRefreshRunDeps = {},
170
+ ): Promise<void> {
171
+ const openai = config.providers[OPENAI_CODEX_PROVIDER_ID];
172
+ if (!openai || openai.disabled === true || !isCanonicalOpenAiForwardProvider(openai)) return;
173
+ if (providerCodexAccountMode(OPENAI_CODEX_PROVIDER_ID, openai) !== "pool") return;
174
+ if (inFlight) return inFlight;
175
+ const quotaFor = deps.getQuota ?? getAccountQuota;
176
+ const warm = deps.warmAccount ?? warmAccount;
177
+ const persist = deps.persistCompleted ?? persistCompleted;
178
+ inFlight = (async () => {
179
+ retryPendingMarkers(config, persist);
180
+ const accountIds = [
181
+ MAIN_CODEX_ACCOUNT_ID,
182
+ ...(config.codexAccounts ?? []).filter(isSelectableCodexPoolAccount).map(account => account.id),
183
+ ];
184
+ const due = accountIds.flatMap(accountId => {
185
+ if (isCodexAccountPaused(config, accountId)
186
+ || isAccountNeedsReauth(accountId)
187
+ || (accountId === MAIN_CODEX_ACCOUNT_ID && isMainAccountHardLocked(config))
188
+ || (retryAfterByAccount.get(accountId) ?? 0) > now) return [];
189
+ const windows = dueCodexQuotaAutoRefreshWindows(config, accountId, quotaFor(accountId), now);
190
+ return windows ? [{ accountId, windows }] : [];
191
+ });
192
+ for (let index = 0; index < due.length; index += CONCURRENCY) {
193
+ await Promise.all(due.slice(index, index + CONCURRENCY).map(async ({ accountId, windows }) => {
194
+ try {
195
+ if (await warm(config, accountId) === false) return;
196
+ retryAfterByAccount.delete(accountId);
197
+ const completed = { ...completedByAccount.get(accountId), ...windows };
198
+ completedByAccount.set(accountId, completed);
199
+ persist(config, accountId, completed);
200
+ } catch {
201
+ retryAfterByAccount.set(accountId, now + RETRY_MS);
202
+ }
203
+ }));
204
+ }
205
+ })().finally(() => { inFlight = null; });
206
+ return inFlight;
207
+ }
208
+
209
+ export function registerCodexQuotaAutoRefreshWorker(config: OcxConfig): () => void {
210
+ return registerStateSweepAfterTick({
211
+ name: "codex-quota-auto-refresh",
212
+ afterTick: () => { void runCodexQuotaAutoRefresh(config); },
213
+ });
214
+ }
215
+
216
+ export function resetCodexQuotaAutoRefreshForTests(): void {
217
+ inFlight = null;
218
+ resetCodexQuotaAutoRefreshStateForTests();
219
+ }
@@ -0,0 +1,51 @@
1
+ /** Quota wire/storage shapes. This leaf must not import credential or config owners. */
2
+ export type StoredAccountQuota = {
3
+ weeklyPercent?: number;
4
+ monthlyPercent?: number;
5
+ weeklyResetAt?: number;
6
+ monthlyResetAt?: number;
7
+ /** Sub-day burst window, independent of the weekly window; duration supplies its meaning. */
8
+ shortPercent?: number;
9
+ shortResetAt?: number;
10
+ /** Local short-usage observation time; partial/credit updates do not refresh it. */
11
+ shortObservedAt?: number;
12
+ shortWindowSeconds?: number;
13
+ customWindows?: Array<{ label: string; percent: number; resetAt?: number }>;
14
+ resetCredits?: number;
15
+ /** Monthly usage came from an explicitly monthly PRIMARY, not supplementary tertiary, window. */
16
+ monthlyIsPrimaryWindow?: boolean;
17
+ updatedAt: number;
18
+ };
19
+
20
+ export type WhamUsageWindow = {
21
+ used_percent?: number;
22
+ reset_at?: number;
23
+ limit_window_seconds?: number;
24
+ };
25
+
26
+ export type WhamAdditionalRateLimit = {
27
+ limit_name?: unknown;
28
+ metered_feature?: unknown;
29
+ rate_limit?: {
30
+ allowed?: unknown;
31
+ primary_window?: WhamUsageWindow | null;
32
+ secondary_window?: WhamUsageWindow | null;
33
+ } | null;
34
+ };
35
+
36
+ export type WhamUsageResponse = {
37
+ email?: string | null;
38
+ plan_type?: unknown;
39
+ account_id?: unknown;
40
+ user_id?: unknown;
41
+ rate_limit_upsell?: { banner_type?: unknown } | null;
42
+ rate_limit?: {
43
+ allowed?: unknown;
44
+ // WHAM sends explicit nulls for absent windows.
45
+ primary_window?: WhamUsageWindow | null;
46
+ secondary_window?: WhamUsageWindow | null;
47
+ tertiary_window?: WhamUsageWindow | null;
48
+ };
49
+ rate_limit_reset_credits?: { available_count: number } | null;
50
+ additional_rate_limits?: WhamAdditionalRateLimit[] | null;
51
+ };