codex-multi-auth 2.16.0 → 2.17.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 (256) hide show
  1. package/.codex-plugin/plugin.json +1 -1
  2. package/README.md +22 -1
  3. package/dist/index.d.ts.map +1 -1
  4. package/dist/index.js +8 -3
  5. package/dist/lib/account-policy.d.ts +4 -0
  6. package/dist/lib/account-policy.d.ts.map +1 -1
  7. package/dist/lib/account-policy.js +8 -0
  8. package/dist/lib/accounts/rate-limits.d.ts.map +1 -1
  9. package/dist/lib/accounts/rate-limits.js +2 -0
  10. package/dist/lib/accounts.d.ts +21 -3
  11. package/dist/lib/accounts.d.ts.map +1 -1
  12. package/dist/lib/accounts.js +229 -17
  13. package/dist/lib/api-route-store.d.ts +24 -0
  14. package/dist/lib/api-route-store.d.ts.map +1 -0
  15. package/dist/lib/api-route-store.js +145 -0
  16. package/dist/lib/auth/account-access.d.ts +115 -0
  17. package/dist/lib/auth/account-access.d.ts.map +1 -0
  18. package/dist/lib/auth/account-access.js +214 -0
  19. package/dist/lib/auth/token-utils.d.ts +54 -1
  20. package/dist/lib/auth/token-utils.d.ts.map +1 -1
  21. package/dist/lib/auth/token-utils.js +92 -7
  22. package/dist/lib/cli.d.ts +1 -1
  23. package/dist/lib/cli.d.ts.map +1 -1
  24. package/dist/lib/cli.js +4 -0
  25. package/dist/lib/codex-cli/state.d.ts +7 -0
  26. package/dist/lib/codex-cli/state.d.ts.map +1 -1
  27. package/dist/lib/codex-cli/state.js +18 -0
  28. package/dist/lib/codex-cli/writer.d.ts.map +1 -1
  29. package/dist/lib/codex-cli/writer.js +60 -8
  30. package/dist/lib/codex-manager/account-manager-commands.d.ts.map +1 -1
  31. package/dist/lib/codex-manager/account-manager-commands.js +1 -0
  32. package/dist/lib/codex-manager/account-pool-write.d.ts +3 -1
  33. package/dist/lib/codex-manager/account-pool-write.d.ts.map +1 -1
  34. package/dist/lib/codex-manager/account-pool-write.js +4 -0
  35. package/dist/lib/codex-manager/api-login-menu.d.ts +14 -0
  36. package/dist/lib/codex-manager/api-login-menu.d.ts.map +1 -0
  37. package/dist/lib/codex-manager/api-login-menu.js +224 -0
  38. package/dist/lib/codex-manager/commands/account.d.ts.map +1 -1
  39. package/dist/lib/codex-manager/commands/account.js +27 -0
  40. package/dist/lib/codex-manager/commands/best.d.ts.map +1 -1
  41. package/dist/lib/codex-manager/commands/best.js +6 -2
  42. package/dist/lib/codex-manager/commands/check.d.ts +7 -1
  43. package/dist/lib/codex-manager/commands/check.d.ts.map +1 -1
  44. package/dist/lib/codex-manager/commands/check.js +24 -3
  45. package/dist/lib/codex-manager/commands/forecast.d.ts.map +1 -1
  46. package/dist/lib/codex-manager/commands/forecast.js +5 -1
  47. package/dist/lib/codex-manager/commands/report.d.ts.map +1 -1
  48. package/dist/lib/codex-manager/commands/report.js +5 -1
  49. package/dist/lib/codex-manager/commands/resets.d.ts +2 -0
  50. package/dist/lib/codex-manager/commands/resets.d.ts.map +1 -0
  51. package/dist/lib/codex-manager/commands/resets.js +67 -0
  52. package/dist/lib/codex-manager/commands/rotation.d.ts +2 -2
  53. package/dist/lib/codex-manager/commands/rotation.d.ts.map +1 -1
  54. package/dist/lib/codex-manager/commands/rotation.js +63 -12
  55. package/dist/lib/codex-manager/commands/status.d.ts +12 -1
  56. package/dist/lib/codex-manager/commands/status.d.ts.map +1 -1
  57. package/dist/lib/codex-manager/commands/status.js +166 -22
  58. package/dist/lib/codex-manager/commands/uninstall.js +1 -1
  59. package/dist/lib/codex-manager/formatters/quota-formatters.d.ts.map +1 -1
  60. package/dist/lib/codex-manager/formatters/quota-formatters.js +3 -2
  61. package/dist/lib/codex-manager/health-check.d.ts +3 -0
  62. package/dist/lib/codex-manager/health-check.d.ts.map +1 -1
  63. package/dist/lib/codex-manager/health-check.js +56 -6
  64. package/dist/lib/codex-manager/help.d.ts.map +1 -1
  65. package/dist/lib/codex-manager/help.js +4 -2
  66. package/dist/lib/codex-manager/login-flow.d.ts.map +1 -1
  67. package/dist/lib/codex-manager/login-flow.js +69 -7
  68. package/dist/lib/codex-manager/login-menu-data.d.ts.map +1 -1
  69. package/dist/lib/codex-manager/login-menu-data.js +14 -5
  70. package/dist/lib/codex-manager/login-oauth.d.ts +3 -0
  71. package/dist/lib/codex-manager/login-oauth.d.ts.map +1 -1
  72. package/dist/lib/codex-manager/login-oauth.js +6 -1
  73. package/dist/lib/codex-manager/login-workspace-choice.d.ts +11 -0
  74. package/dist/lib/codex-manager/login-workspace-choice.d.ts.map +1 -0
  75. package/dist/lib/codex-manager/login-workspace-choice.js +37 -0
  76. package/dist/lib/codex-manager/persist-selected-account.d.ts.map +1 -1
  77. package/dist/lib/codex-manager/persist-selected-account.js +2 -1
  78. package/dist/lib/codex-manager/repair-commands.d.ts +13 -0
  79. package/dist/lib/codex-manager/repair-commands.d.ts.map +1 -1
  80. package/dist/lib/codex-manager/repair-commands.js +143 -8
  81. package/dist/lib/codex-manager.d.ts.map +1 -1
  82. package/dist/lib/codex-manager.js +25 -6
  83. package/dist/lib/concurrency.d.ts +3 -0
  84. package/dist/lib/concurrency.d.ts.map +1 -0
  85. package/dist/lib/concurrency.js +31 -0
  86. package/dist/lib/model-route-policy.d.ts +52 -0
  87. package/dist/lib/model-route-policy.d.ts.map +1 -0
  88. package/dist/lib/model-route-policy.js +159 -0
  89. package/dist/lib/policy/runtime-policy.d.ts +1 -0
  90. package/dist/lib/policy/runtime-policy.d.ts.map +1 -1
  91. package/dist/lib/policy/runtime-policy.js +3 -0
  92. package/dist/lib/preemptive-quota-scheduler.d.ts +2 -0
  93. package/dist/lib/preemptive-quota-scheduler.d.ts.map +1 -1
  94. package/dist/lib/preemptive-quota-scheduler.js +4 -0
  95. package/dist/lib/quota-probe.d.ts +5 -0
  96. package/dist/lib/quota-probe.d.ts.map +1 -1
  97. package/dist/lib/quota-probe.js +26 -2
  98. package/dist/lib/request/client-cancellation.d.ts +5 -0
  99. package/dist/lib/request/client-cancellation.d.ts.map +1 -0
  100. package/dist/lib/request/client-cancellation.js +7 -0
  101. package/dist/lib/request/response-outcome.d.ts +25 -0
  102. package/dist/lib/request/response-outcome.d.ts.map +1 -0
  103. package/dist/lib/request/response-outcome.js +49 -0
  104. package/dist/lib/request/stream-failover-runtime.d.ts +2 -1
  105. package/dist/lib/request/stream-failover-runtime.d.ts.map +1 -1
  106. package/dist/lib/request/stream-failover-runtime.js +29 -10
  107. package/dist/lib/runtime/account-check.d.ts.map +1 -1
  108. package/dist/lib/runtime/account-check.js +2 -8
  109. package/dist/lib/runtime/account-model-catalog.d.ts +64 -0
  110. package/dist/lib/runtime/account-model-catalog.d.ts.map +1 -0
  111. package/dist/lib/runtime/account-model-catalog.js +154 -0
  112. package/dist/lib/runtime/account-pool.d.ts +3 -1
  113. package/dist/lib/runtime/account-pool.d.ts.map +1 -1
  114. package/dist/lib/runtime/account-pool.js +4 -0
  115. package/dist/lib/runtime/account-reset-credits.d.ts +42 -0
  116. package/dist/lib/runtime/account-reset-credits.d.ts.map +1 -0
  117. package/dist/lib/runtime/account-reset-credits.js +82 -0
  118. package/dist/lib/runtime/api-model-capabilities.d.ts +30 -0
  119. package/dist/lib/runtime/api-model-capabilities.d.ts.map +1 -0
  120. package/dist/lib/runtime/api-model-capabilities.js +434 -0
  121. package/dist/lib/runtime/api-model-runtime.d.ts +42 -0
  122. package/dist/lib/runtime/api-model-runtime.d.ts.map +1 -0
  123. package/dist/lib/runtime/api-model-runtime.js +358 -0
  124. package/dist/lib/runtime/app-bind.d.ts +19 -1
  125. package/dist/lib/runtime/app-bind.d.ts.map +1 -1
  126. package/dist/lib/runtime/app-bind.js +79 -9
  127. package/dist/lib/runtime/automatic-account-checks.d.ts +31 -0
  128. package/dist/lib/runtime/automatic-account-checks.d.ts.map +1 -0
  129. package/dist/lib/runtime/automatic-account-checks.js +113 -0
  130. package/dist/lib/runtime/automatic-subscription-checks.d.ts +7 -0
  131. package/dist/lib/runtime/automatic-subscription-checks.d.ts.map +1 -0
  132. package/dist/lib/runtime/automatic-subscription-checks.js +57 -0
  133. package/dist/lib/runtime/catalog-capabilities.d.ts +8 -0
  134. package/dist/lib/runtime/catalog-capabilities.d.ts.map +1 -0
  135. package/dist/lib/runtime/catalog-capabilities.js +61 -0
  136. package/dist/lib/runtime/inference-activity.d.ts +15 -0
  137. package/dist/lib/runtime/inference-activity.d.ts.map +1 -0
  138. package/dist/lib/runtime/inference-activity.js +95 -0
  139. package/dist/lib/runtime/model-discovery-status.d.ts +100 -0
  140. package/dist/lib/runtime/model-discovery-status.d.ts.map +1 -0
  141. package/dist/lib/runtime/model-discovery-status.js +387 -0
  142. package/dist/lib/runtime/native-account-storage.d.ts +11 -0
  143. package/dist/lib/runtime/native-account-storage.d.ts.map +1 -0
  144. package/dist/lib/runtime/native-account-storage.js +50 -0
  145. package/dist/lib/runtime/native-account-sync.d.ts +19 -0
  146. package/dist/lib/runtime/native-account-sync.d.ts.map +1 -0
  147. package/dist/lib/runtime/native-account-sync.js +62 -0
  148. package/dist/lib/runtime/native-binding-lock.d.ts +3 -0
  149. package/dist/lib/runtime/native-binding-lock.d.ts.map +1 -0
  150. package/dist/lib/runtime/native-binding-lock.js +5 -0
  151. package/dist/lib/runtime/native-client-auth.d.ts +3 -0
  152. package/dist/lib/runtime/native-client-auth.d.ts.map +1 -0
  153. package/dist/lib/runtime/native-client-auth.js +42 -0
  154. package/dist/lib/runtime/native-provider-config.d.ts +4 -0
  155. package/dist/lib/runtime/native-provider-config.d.ts.map +1 -0
  156. package/dist/lib/runtime/native-provider-config.js +52 -0
  157. package/dist/lib/runtime/native-rate-limits.d.ts +18 -0
  158. package/dist/lib/runtime/native-rate-limits.d.ts.map +1 -0
  159. package/dist/lib/runtime/native-rate-limits.js +135 -0
  160. package/dist/lib/runtime/reset-credit-routing.d.ts +41 -0
  161. package/dist/lib/runtime/reset-credit-routing.d.ts.map +1 -0
  162. package/dist/lib/runtime/reset-credit-routing.js +66 -0
  163. package/dist/lib/runtime/reset-credits.d.ts +101 -0
  164. package/dist/lib/runtime/reset-credits.d.ts.map +1 -0
  165. package/dist/lib/runtime/reset-credits.js +162 -0
  166. package/dist/lib/runtime/response-output-history.d.ts +17 -0
  167. package/dist/lib/runtime/response-output-history.d.ts.map +1 -0
  168. package/dist/lib/runtime/response-output-history.js +85 -0
  169. package/dist/lib/runtime/responses-websocket.d.ts +31 -0
  170. package/dist/lib/runtime/responses-websocket.d.ts.map +1 -0
  171. package/dist/lib/runtime/responses-websocket.js +636 -0
  172. package/dist/lib/runtime/resume-picker.d.ts +41 -0
  173. package/dist/lib/runtime/resume-picker.d.ts.map +1 -0
  174. package/dist/lib/runtime/resume-picker.js +169 -0
  175. package/dist/lib/runtime/rotation-account-selection.d.ts +6 -0
  176. package/dist/lib/runtime/rotation-account-selection.d.ts.map +1 -1
  177. package/dist/lib/runtime/rotation-account-selection.js +63 -0
  178. package/dist/lib/runtime/rotation-proxy-state.d.ts +33 -0
  179. package/dist/lib/runtime/rotation-proxy-state.d.ts.map +1 -1
  180. package/dist/lib/runtime/rotation-server-types.d.ts +18 -0
  181. package/dist/lib/runtime/rotation-server-types.d.ts.map +1 -1
  182. package/dist/lib/runtime/runtime-capability-failures.d.ts +14 -0
  183. package/dist/lib/runtime/runtime-capability-failures.d.ts.map +1 -0
  184. package/dist/lib/runtime/runtime-capability-failures.js +76 -0
  185. package/dist/lib/runtime/runtime-observability.d.ts +7 -0
  186. package/dist/lib/runtime/runtime-observability.d.ts.map +1 -1
  187. package/dist/lib/runtime/runtime-observability.js +42 -2
  188. package/dist/lib/runtime/subscription-first-use.d.ts +10 -0
  189. package/dist/lib/runtime/subscription-first-use.d.ts.map +1 -0
  190. package/dist/lib/runtime/subscription-first-use.js +64 -0
  191. package/dist/lib/runtime/subscription-quota-event.d.ts +6 -0
  192. package/dist/lib/runtime/subscription-quota-event.d.ts.map +1 -0
  193. package/dist/lib/runtime/subscription-quota-event.js +31 -0
  194. package/dist/lib/runtime/subscription-quota-order.d.ts +17 -0
  195. package/dist/lib/runtime/subscription-quota-order.d.ts.map +1 -0
  196. package/dist/lib/runtime/subscription-quota-order.js +31 -0
  197. package/dist/lib/runtime/workspace-model-scopes.d.ts +15 -0
  198. package/dist/lib/runtime/workspace-model-scopes.d.ts.map +1 -0
  199. package/dist/lib/runtime/workspace-model-scopes.js +34 -0
  200. package/dist/lib/runtime-constants.d.ts +3 -0
  201. package/dist/lib/runtime-constants.d.ts.map +1 -1
  202. package/dist/lib/runtime-constants.js +5 -0
  203. package/dist/lib/runtime-paths.d.ts.map +1 -1
  204. package/dist/lib/runtime-paths.js +4 -1
  205. package/dist/lib/runtime-rotation-proxy.d.ts.map +1 -1
  206. package/dist/lib/runtime-rotation-proxy.js +852 -42
  207. package/dist/lib/schemas.d.ts +20 -0
  208. package/dist/lib/schemas.d.ts.map +1 -1
  209. package/dist/lib/schemas.js +3 -0
  210. package/dist/lib/storage/credential-sidecars.d.ts +13 -0
  211. package/dist/lib/storage/credential-sidecars.d.ts.map +1 -0
  212. package/dist/lib/storage/credential-sidecars.js +52 -0
  213. package/dist/lib/storage/file-lock.d.ts +9 -0
  214. package/dist/lib/storage/file-lock.d.ts.map +1 -0
  215. package/dist/lib/storage/file-lock.js +186 -0
  216. package/dist/lib/storage/flagged-storage.d.ts.map +1 -1
  217. package/dist/lib/storage/flagged-storage.js +12 -0
  218. package/dist/lib/storage/path-state.d.ts +2 -0
  219. package/dist/lib/storage/path-state.d.ts.map +1 -1
  220. package/dist/lib/storage/path-state.js +9 -0
  221. package/dist/lib/storage/paths.js +4 -4
  222. package/dist/lib/storage/pending-auth.d.ts +17 -0
  223. package/dist/lib/storage/pending-auth.d.ts.map +1 -0
  224. package/dist/lib/storage/pending-auth.js +153 -0
  225. package/dist/lib/storage/public-types.d.ts +13 -0
  226. package/dist/lib/storage/public-types.d.ts.map +1 -1
  227. package/dist/lib/storage/snapshot-merge.d.ts +16 -0
  228. package/dist/lib/storage/snapshot-merge.d.ts.map +1 -0
  229. package/dist/lib/storage/snapshot-merge.js +206 -0
  230. package/dist/lib/storage/transactions.d.ts.map +1 -1
  231. package/dist/lib/storage/transactions.js +5 -4
  232. package/dist/lib/storage.d.ts +6 -0
  233. package/dist/lib/storage.d.ts.map +1 -1
  234. package/dist/lib/storage.js +77 -7
  235. package/dist/lib/ui/auth-menu-builder.d.ts +2 -0
  236. package/dist/lib/ui/auth-menu-builder.d.ts.map +1 -1
  237. package/dist/lib/ui/auth-menu-builder.js +1 -0
  238. package/dist/lib/ui/auth-menu.d.ts.map +1 -1
  239. package/dist/lib/ui/auth-menu.js +1 -0
  240. package/dist/lib/ui/check-progress.d.ts +8 -0
  241. package/dist/lib/ui/check-progress.d.ts.map +1 -0
  242. package/dist/lib/ui/check-progress.js +30 -0
  243. package/dist/lib/ui/format.d.ts +3 -1
  244. package/dist/lib/ui/format.d.ts.map +1 -1
  245. package/dist/lib/ui/format.js +8 -0
  246. package/dist/lib/ui/ui-copy.d.ts +2 -2
  247. package/dist/lib/ui/ui-copy.js +2 -2
  248. package/dist/lib/usage/pricing.js +2 -2
  249. package/dist/lib/usage/usage-extraction.d.ts +3 -1
  250. package/dist/lib/usage/usage-extraction.d.ts.map +1 -1
  251. package/dist/lib/usage/usage-extraction.js +46 -9
  252. package/package.json +7 -4
  253. package/scripts/codex-app-router.js +7 -0
  254. package/scripts/codex-bin-resolver.js +40 -8
  255. package/scripts/codex-routing.js +1 -0
  256. package/scripts/codex.js +100 -22
@@ -144,8 +144,8 @@ export const UI_COPY = {
144
144
  fallback: {
145
145
  addAnotherTip: "Tip: Use private mode or sign out before adding another account.",
146
146
  addAnotherQuestion: (count) => `Add another account? (${count} added) (y/n): `,
147
- selectModePrompt: "(a) add, (c) check, (b) best, fi(x), (s) settings, (d) deep, (g) problem, (f) fresh, (q) back [a/c/b/x/s/d/g/f/q]: ",
148
- invalidModePrompt: "Use one of: a, c, b, x, s, d, g, f, q.",
147
+ selectModePrompt: "(api) API models, (a) add, (c) check, (b) best, fi(x), (s) settings, (d) deep, (g) problem, (f) fresh, (q) back [api/a/c/b/x/s/d/g/f/q]: ",
148
+ invalidModePrompt: "Use one of: api, a, c, b, x, s, d, g, f, q.",
149
149
  },
150
150
  };
151
151
  /**
@@ -159,7 +159,7 @@ function normalizeModelName(model) {
159
159
  return trimmed && trimmed.length > 0 ? trimmed : null;
160
160
  }
161
161
  export function getUsageModelPricing(model) {
162
- const normalized = normalizeModelName(model);
162
+ const normalized = normalizeModelName(model?.replace(/^(api|zdr)\//, ""));
163
163
  if (!normalized) {
164
164
  return null;
165
165
  }
@@ -177,7 +177,7 @@ export function getUsageModelPricing(model) {
177
177
  // `gpt-5.6-sol` request; pricing it at the retired model's old rate would
178
178
  // under-count a `maxCostUsd` budget. Rows already on disk are unaffected:
179
179
  // the ledger stores `costUsd` when a row is written and never re-prices it.
180
- const effective = Object.hasOwn(RETIRED_MODEL_REPLACEMENTS, normalized)
180
+ const effective = !/^(api|zdr)\//.test(model ?? "") && Object.hasOwn(RETIRED_MODEL_REPLACEMENTS, normalized)
181
181
  ? RETIRED_MODEL_REPLACEMENTS[normalized]
182
182
  : normalized;
183
183
  if (!effective || !Object.hasOwn(MODEL_PRICING, effective)) {
@@ -30,7 +30,7 @@ export interface UsageStreamScanner {
30
30
  /**
31
31
  * Observe a forwarded response body and recover its token counts.
32
32
  *
33
- * SSE bodies are scanned line by line so only the current partial line is
33
+ * SSE bodies are scanned frame by frame so only the current bounded event is
34
34
  * retained; a full response can be gigabytes of deltas and must never be
35
35
  * buffered. Non-SSE JSON bodies have no incremental structure to exploit, so
36
36
  * they are accumulated up to `MAX_BUFFERED_BYTES` and parsed at the end —
@@ -39,5 +39,7 @@ export interface UsageStreamScanner {
39
39
  */
40
40
  export declare function createUsageStreamScanner(options: {
41
41
  contentType?: string | null;
42
+ /** Observe parsed upstream events without reparsing the stream. */
43
+ onEvent?: (event: unknown) => void;
42
44
  }): UsageStreamScanner;
43
45
  //# sourceMappingURL=usage-extraction.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"usage-extraction.d.ts","sourceRoot":"","sources":["../../../lib/usage/usage-extraction.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAoB,gBAAgB,EAAE,MAAM,YAAY,CAAC;AA+BrE;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,uBAAuB,CACtC,KAAK,EAAE,OAAO,GACZ,gBAAgB,GAAG,IAAI,CA+BzB;AAoCD;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,OAAO,GAAG,gBAAgB,GAAG,IAAI,CAa/E;AAED,MAAM,WAAW,kBAAkB;IAClC,8CAA8C;IAC9C,IAAI,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,CAAC;IAClC,2EAA2E;IAC3E,MAAM,EAAE,MAAM,gBAAgB,GAAG,IAAI,CAAC;CACtC;AAED;;;;;;;;;GASG;AACH,wBAAgB,wBAAwB,CAAC,OAAO,EAAE;IACjD,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B,GAAG,kBAAkB,CA6ErB"}
1
+ {"version":3,"file":"usage-extraction.d.ts","sourceRoot":"","sources":["../../../lib/usage/usage-extraction.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAoB,gBAAgB,EAAE,MAAM,YAAY,CAAC;AA+BrE;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,uBAAuB,CACtC,KAAK,EAAE,OAAO,GACZ,gBAAgB,GAAG,IAAI,CA+BzB;AAoCD;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,OAAO,GAAG,gBAAgB,GAAG,IAAI,CAa/E;AAED,MAAM,WAAW,kBAAkB;IAClC,8CAA8C;IAC9C,IAAI,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,CAAC;IAClC,2EAA2E;IAC3E,MAAM,EAAE,MAAM,gBAAgB,GAAG,IAAI,CAAC;CACtC;AAED;;;;;;;;;GASG;AACH,wBAAgB,wBAAwB,CAAC,OAAO,EAAE;IACjD,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,mEAAmE;IACnE,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;CACnC,GAAG,kBAAkB,CAmGrB"}
@@ -124,7 +124,7 @@ export function extractResponsesUsage(payload) {
124
124
  /**
125
125
  * Observe a forwarded response body and recover its token counts.
126
126
  *
127
- * SSE bodies are scanned line by line so only the current partial line is
127
+ * SSE bodies are scanned frame by frame so only the current bounded event is
128
128
  * retained; a full response can be gigabytes of deltas and must never be
129
129
  * buffered. Non-SSE JSON bodies have no incremental structure to exploit, so
130
130
  * they are accumulated up to `MAX_BUFFERED_BYTES` and parsed at the end —
@@ -138,11 +138,20 @@ export function createUsageStreamScanner(options) {
138
138
  let bufferedBytes = 0;
139
139
  let overflowed = false;
140
140
  let latest = null;
141
- const consumeLine = (line) => {
142
- const trimmed = line.trim();
143
- if (!trimmed.startsWith("data:"))
141
+ let eventData = [];
142
+ let eventSize = 0;
143
+ let droppingEvent = false;
144
+ let droppingLine = false;
145
+ const consumeEvent = () => {
146
+ if (droppingEvent) {
147
+ droppingEvent = false;
148
+ eventData = [];
149
+ eventSize = 0;
144
150
  return;
145
- const payload = trimmed.slice("data:".length).trim();
151
+ }
152
+ const payload = eventData.join("\n");
153
+ eventData = [];
154
+ eventSize = 0;
146
155
  if (payload.length === 0 || payload === "[DONE]")
147
156
  return;
148
157
  let parsed;
@@ -152,6 +161,7 @@ export function createUsageStreamScanner(options) {
152
161
  catch {
153
162
  return;
154
163
  }
164
+ options.onEvent?.(parsed);
155
165
  // Prefer terminal events, which carry the authoritative totals, but fall
156
166
  // back to any event that reports usage so a stream that ends on a
157
167
  // non-standard terminal type still records something.
@@ -162,6 +172,24 @@ export function createUsageStreamScanner(options) {
162
172
  latest = counts;
163
173
  }
164
174
  };
175
+ const consumeLine = (raw) => {
176
+ const line = raw.endsWith("\r") ? raw.slice(0, -1) : raw;
177
+ if (line.length === 0) {
178
+ consumeEvent();
179
+ return;
180
+ }
181
+ if (droppingEvent || !line.startsWith("data:"))
182
+ return;
183
+ const value = line.slice(5).replace(/^ /, "");
184
+ eventSize += value.length + 1;
185
+ if (eventSize > MAX_BUFFERED_BYTES) {
186
+ droppingEvent = true;
187
+ eventData = [];
188
+ eventSize = 0;
189
+ return;
190
+ }
191
+ eventData.push(value);
192
+ };
165
193
  return {
166
194
  push: (chunk) => {
167
195
  try {
@@ -178,14 +206,20 @@ export function createUsageStreamScanner(options) {
178
206
  }
179
207
  let newlineAt = pending.indexOf("\n");
180
208
  while (newlineAt !== -1) {
181
- consumeLine(pending.slice(0, newlineAt));
209
+ if (droppingLine)
210
+ droppingLine = false;
211
+ else
212
+ consumeLine(pending.slice(0, newlineAt));
182
213
  pending = pending.slice(newlineAt + 1);
183
214
  newlineAt = pending.indexOf("\n");
184
215
  }
185
216
  // A single unterminated line this long is not SSE any more; stop
186
217
  // retaining it rather than growing the buffer for the whole body.
187
- if (pending.length > MAX_BUFFERED_BYTES) {
188
- overflowed = true;
218
+ if (pending.length > MAX_BUFFERED_BYTES || droppingLine) {
219
+ droppingEvent = true;
220
+ droppingLine = true;
221
+ eventData = [];
222
+ eventSize = 0;
189
223
  pending = "";
190
224
  }
191
225
  }
@@ -202,13 +236,16 @@ export function createUsageStreamScanner(options) {
202
236
  if (pending.length > 0)
203
237
  consumeLine(pending);
204
238
  pending = "";
239
+ consumeEvent();
205
240
  return latest;
206
241
  }
207
242
  if (pending.trim().length === 0)
208
243
  return latest;
209
244
  const parsed = JSON.parse(pending);
210
245
  pending = "";
211
- return extractResponsesUsage(parsed) ?? latest;
246
+ options.onEvent?.(parsed);
247
+ latest = extractResponsesUsage(parsed) ?? latest;
248
+ return latest;
212
249
  }
213
250
  catch {
214
251
  return latest;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codex-multi-auth",
3
- "version": "2.16.0",
3
+ "version": "2.17.0",
4
4
  "description": "Codex CLI multi-account OAuth manager with account switching, health checks, runtime rotation, diagnostics, and recovery tools for @openai/codex",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
@@ -157,6 +157,7 @@
157
157
  },
158
158
  "devDependencies": {
159
159
  "@types/node": "^20.19.42",
160
+ "@types/ws": "8.18.1",
160
161
  "@typescript-eslint/eslint-plugin": "^8.56.0",
161
162
  "@typescript-eslint/parser": "^8.56.0",
162
163
  "@vitest/coverage-v8": "^4.1.8",
@@ -174,12 +175,13 @@
174
175
  "dependencies": {
175
176
  "@codex-ai/plugin": "file:vendor/codex-ai-plugin",
176
177
  "@codex-ai/sdk": "file:vendor/codex-ai-sdk",
177
- "hono": "4.12.33",
178
+ "hono": "4.13.9",
178
179
  "undici": "6.28.0",
180
+ "ws": "8.21.3",
179
181
  "zod": "4.4.3"
180
182
  },
181
183
  "overrides": {
182
- "hono": "4.12.33",
184
+ "hono": "4.13.9",
183
185
  "flatted": "3.4.2",
184
186
  "minimatch": "10.2.4",
185
187
  "picomatch": "4.0.4",
@@ -192,6 +194,7 @@
192
194
  "minimatch": "9.0.9"
193
195
  },
194
196
  "brace-expansion": "5.0.9",
195
- "postcss": "8.5.25"
197
+ "postcss": "8.5.25",
198
+ "nanoid": "3.3.18"
196
199
  }
197
200
  }
@@ -177,11 +177,16 @@ function createStatusPayload({
177
177
  baseUrl: proxyServer?.baseUrl ?? stateRecord?.baseUrl ?? null,
178
178
  totalRequests: proxyStatus.totalRequests ?? 0,
179
179
  upstreamRequests: proxyStatus.upstreamRequests ?? 0,
180
+ websocketConnections: proxyStatus.websocketConnections ?? 0,
181
+ websocketUpstreamRequests: proxyStatus.websocketUpstreamRequests ?? 0,
182
+ streamQuotaUpdates: proxyStatus.streamQuotaUpdates ?? 0,
183
+ lastStreamQuotaUpdateAt: proxyStatus.lastStreamQuotaUpdateAt ?? null,
180
184
  retries: proxyStatus.retries ?? 0,
181
185
  rotations: proxyStatus.rotations ?? 0,
182
186
  lastAccountIndex,
183
187
  lastAccountLabel,
184
188
  lastAccountId: proxyStatus.lastAccountId ?? null,
189
+ lastRequestedWorkspaceId: proxyStatus.lastRequestedWorkspaceId ?? null,
185
190
  lastAccountUpdatedAt: proxyStatus.lastAccountUpdatedAt ?? null,
186
191
  lastError: error ? (error instanceof Error ? error.message : String(error)) : proxyStatus.lastError ?? null,
187
192
  };
@@ -323,6 +328,8 @@ async function main() {
323
328
  try {
324
329
  const proxyModule = await import("../dist/lib/runtime-rotation-proxy.js");
325
330
  proxyServer = await proxyModule.startRuntimeRotationProxy({
331
+ nativeOpenai: stateRecord?.nativeOpenai === true,
332
+ catalogAccount: stateRecord?.catalogAccount,
326
333
  host,
327
334
  port,
328
335
  clientApiKey,
@@ -1,7 +1,7 @@
1
1
  import { spawnSync } from "node:child_process";
2
2
  import { existsSync, realpathSync } from "node:fs";
3
3
  import { createRequire } from "node:module";
4
- import { basename, delimiter, dirname, extname, isAbsolute, join, relative } from "node:path";
4
+ import { basename, dirname, extname, isAbsolute, join, posix, relative, win32 } from "node:path";
5
5
  import process from "node:process";
6
6
  import { fileURLToPath } from "node:url";
7
7
 
@@ -55,6 +55,29 @@ function defaultResolvePackageBin(moduleUrl) {
55
55
  }
56
56
  }
57
57
 
58
+ // spawn() without a shell cannot run these on Windows: `.cmd`/`.bat` are
59
+ // EINVAL, `.ps1` is not an executable image, and an extensionless file
60
+ // (npm's `#!/bin/sh` shim) is ENOENT even when it is a real PE image. Going through cmd.exe instead would put every
61
+ // forwarded argument through cmd's quoting rules.
62
+ export function isWindowsShimPath(candidatePath) {
63
+ const extension = win32.extname(candidatePath).toLowerCase();
64
+ return extension === "" || extension === ".cmd" || extension === ".bat" || extension === ".ps1";
65
+ }
66
+
67
+ // npm's Windows shims sit in the prefix dir and run
68
+ // `<prefix>\node_modules\@openai\codex\bin\codex.js`.
69
+ export function resolveWindowsShimPackageEntry(shimPath, existsSyncImpl = existsSync) {
70
+ const entry = win32.join(
71
+ win32.dirname(shimPath),
72
+ "node_modules",
73
+ "@openai",
74
+ "codex",
75
+ "bin",
76
+ "codex.js",
77
+ );
78
+ return existsSyncImpl(entry) ? entry : null;
79
+ }
80
+
58
81
  function resolveWindowsCmdPath(env) {
59
82
  const comSpec = (env.ComSpec ?? env.COMSPEC ?? "").trim();
60
83
  if (comSpec.length > 0) return comSpec;
@@ -67,12 +90,12 @@ function resolveWindowsCmdPath(env) {
67
90
  return "cmd.exe";
68
91
  }
69
92
 
70
- export function splitPathEntries(pathValue) {
93
+ export function splitPathEntries(pathValue, platform = process.platform) {
71
94
  if (typeof pathValue !== "string" || pathValue.trim().length === 0) {
72
95
  return [];
73
96
  }
74
97
  return pathValue
75
- .split(delimiter)
98
+ .split(platform === "win32" ? ";" : ":")
76
99
  .map((entry) => entry.trim())
77
100
  .filter((entry) => entry.length > 0);
78
101
  }
@@ -85,7 +108,12 @@ function resolveCandidateExecutableNames(platform) {
85
108
  if (platform !== "win32") {
86
109
  return [resolvePathExecutableName(platform)];
87
110
  }
88
- return ["codex.exe", "codex"];
111
+ // npm on Windows puts `codex.cmd` plus an extensionless `#!/bin/sh` shim in
112
+ // the prefix dir and the package under `<prefix>\node_modules`. Neither shim
113
+ // can be spawned without a shell (`.cmd` is EINVAL, the sh script ENOENT),
114
+ // so launch the package entry the shims point at before falling back to an
115
+ // extensionless `codex`.
116
+ return ["codex.exe", win32.join("node_modules", "@openai", "codex", "bin", "codex.js"), "codex"];
89
117
  }
90
118
 
91
119
  function resolveCodexExecutableFromPath(
@@ -97,7 +125,7 @@ function resolveCodexExecutableFromPath(
97
125
  ) {
98
126
  for (const entry of pathEntries) {
99
127
  for (const executableName of resolveCandidateExecutableNames(platform)) {
100
- const candidate = join(entry, executableName);
128
+ const candidate = (platform === "win32" ? win32 : posix).join(entry, executableName);
101
129
  if (!existsSyncImpl(candidate)) {
102
130
  continue;
103
131
  }
@@ -134,7 +162,7 @@ function resolveCodexExecutableFromSystemPath(
134
162
  selfScriptPath,
135
163
  realpathSyncImpl,
136
164
  ) {
137
- const pathEntries = splitPathEntries(env.PATH ?? env.Path ?? "");
165
+ const pathEntries = splitPathEntries(env.PATH ?? env.Path ?? "", platform);
138
166
  const fromEnvPath = resolveCodexExecutableFromPath(
139
167
  pathEntries,
140
168
  platform,
@@ -207,8 +235,12 @@ export function resolveRealCodexBin(options = {}) {
207
235
 
208
236
  const override = (env.CODEX_MULTI_AUTH_REAL_CODEX_BIN ?? "").trim();
209
237
  if (override.length > 0) {
210
- if (existsSyncImpl(override)) return createResolvedCodexBin(override);
211
- return null;
238
+ if (!existsSyncImpl(override)) return null;
239
+ if (platform === "win32" && isWindowsShimPath(override)) {
240
+ const entry = resolveWindowsShimPackageEntry(override, existsSyncImpl);
241
+ return entry ? createResolvedCodexBin(entry) : null;
242
+ }
243
+ return createResolvedCodexBin(override);
212
244
  }
213
245
 
214
246
  const resolved = resolvePackageBin(moduleUrl);
@@ -10,6 +10,7 @@ const AUTH_SUBCOMMANDS = new Set([
10
10
  "check",
11
11
  "features",
12
12
  "usage",
13
+ "resets",
13
14
  "verify-flagged",
14
15
  "verify",
15
16
  "forecast",
package/scripts/codex.js CHANGED
@@ -26,7 +26,9 @@ import process from "node:process";
26
26
  import { StringDecoder } from "node:string_decoder";
27
27
  import { fileURLToPath, pathToFileURL } from "node:url";
28
28
  import {
29
+ isWindowsShimPath,
29
30
  resolveRealCodexBin as resolveRealCodexBinFromEnvironment,
31
+ resolveWindowsShimPackageEntry,
30
32
  splitPathEntries,
31
33
  } from "./codex-bin-resolver.js";
32
34
  import { normalizeAuthAlias, shouldHandleMultiAuthAuth } from "./codex-routing.js";
@@ -1350,6 +1352,17 @@ function resolveRealCodexBin() {
1350
1352
  );
1351
1353
  return null;
1352
1354
  }
1355
+ if (
1356
+ process.platform === "win32" &&
1357
+ isWindowsShimPath(override) &&
1358
+ !resolveWindowsShimPackageEntry(override)
1359
+ ) {
1360
+ console.error(
1361
+ `CODEX_MULTI_AUTH_REAL_CODEX_BIN points at a script shim that cannot be launched directly on Windows: ${override}\n` +
1362
+ "Point it at codex.exe or @openai/codex/bin/codex.js instead.",
1363
+ );
1364
+ return null;
1365
+ }
1353
1366
  return resolveRealCodexBinFromEnvironment({
1354
1367
  moduleUrl: import.meta.url,
1355
1368
  env: process.env,
@@ -3599,7 +3612,16 @@ function parseRuntimeRotationProxyEnv(value) {
3599
3612
  return undefined;
3600
3613
  }
3601
3614
 
3615
+ function hasNativeAppBinding(env = process.env) {
3616
+ try {
3617
+ const config = readFileSync(join(resolveCodexHomeDir(env), "config.toml"), "utf8");
3618
+ return config.includes("# codex-multi-auth native provider begin") &&
3619
+ extractConfigAssignmentValue(config, "model_provider") === "openai";
3620
+ } catch { return false; }
3621
+ }
3622
+
3602
3623
  async function isRuntimeRotationProxyEnabled(rawArgs, baseEnv = process.env) {
3624
+ if (hasNativeAppBinding(baseEnv)) return false;
3603
3625
  if ((baseEnv.CODEX_MULTI_AUTH_BYPASS ?? "").trim() === "1") {
3604
3626
  return false;
3605
3627
  }
@@ -4021,29 +4043,20 @@ function installRuntimeRotationAppServerCliShim(forwardedEnv, configArgs = []) {
4021
4043
  // Best-effort stale shim cleanup only; the copy below will report a
4022
4044
  // persistent failure without leaving a partially-created helper.
4023
4045
  }
4024
- if (
4025
- process.platform === "win32" ||
4026
- (process.env.CODEX_MULTI_AUTH_TEST_FORCE_APP_SERVER_SHIM_COPY ?? "") === "1"
4027
- ) {
4028
- // A Windows hard link to the running node.exe remains locked by the
4029
- // helper process itself, which prevents the shim directory from being
4030
- // removed during graceful helper shutdown. Use an independent image so
4031
- // the helper can clean up its app-server shim before exiting.
4046
+ if (process.platform === "win32") {
4047
+ // A running hard-linked node.exe prevents helper cleanup on Windows.
4032
4048
  withSynchronousFileOperationRetry(() => {
4033
4049
  maybeThrowSimulatedAppServerShimFileError("copy");
4034
4050
  copyFileSync(process.execPath, executablePath);
4035
4051
  });
4036
4052
  } else {
4037
- try {
4038
- linkSync(process.execPath, executablePath);
4039
- } catch {
4040
- withSynchronousFileOperationRetry(() => {
4041
- maybeThrowSimulatedAppServerShimFileError("copy");
4042
- copyFileSync(process.execPath, executablePath);
4043
- });
4044
- }
4045
- }
4046
- if (process.platform !== "win32") {
4053
+ // Relocating Node breaks installations with executable-relative shared
4054
+ // libraries (including Homebrew). Invoke the original image in place.
4055
+ const quotedNode = "'" + process.execPath.replace(/'/g, "'\\''") + "'";
4056
+ withSynchronousFileOperationRetry(() => {
4057
+ maybeThrowSimulatedAppServerShimFileError("copy");
4058
+ writeFileSync(executablePath, `#!/bin/sh\nexec ${quotedNode} "$@"\n`, { mode: 0o755 });
4059
+ });
4047
4060
  chmodSync(executablePath, 0o755);
4048
4061
  }
4049
4062
  writeFileSync(
@@ -5964,8 +5977,13 @@ function createCompatibilityCodexHome(
5964
5977
  };
5965
5978
  }
5966
5979
 
5967
- function buildForwardArgs(rawArgs) {
5968
- const { args: compatibilityArgs, requestedModel } = rewriteReasoningConfigArgs(rawArgs);
5980
+ function buildForwardArgs(rawArgs, { preserveNativeSettings = false } = {}) {
5981
+ // Native app binding keeps the caller's model and reasoning settings verbatim;
5982
+ // it still needs the file auth store, because the router authenticates the
5983
+ // desktop token it reads from auth.json.
5984
+ const { args: compatibilityArgs, requestedModel } = preserveNativeSettings
5985
+ ? { args: [...rawArgs], requestedModel: extractRequestedModel(rawArgs) }
5986
+ : rewriteReasoningConfigArgs(rawArgs);
5969
5987
  const forceFileAuthStore = (process.env.CODEX_MULTI_AUTH_FORCE_FILE_AUTH_STORE ?? "1").trim() !== "0";
5970
5988
  if (!forceFileAuthStore) {
5971
5989
  return { args: compatibilityArgs, requestedModel };
@@ -6473,6 +6491,33 @@ function ensureWindowsShellShimGuards() {
6473
6491
  }
6474
6492
  }
6475
6493
 
6494
+ export function getResumePickerRequest(args, cwd = process.cwd()) {
6495
+ const baseCwd = cwd;
6496
+ const command = findForwardedCommand(args);
6497
+ if (command?.command !== "resume" || findForwardedSubcommand(args, command.index)) return null;
6498
+ const configArgs = [];
6499
+ let showAll = false;
6500
+ let includeNonInteractive = false;
6501
+ for (let i = 0; i < args.length; i += 1) {
6502
+ const arg = args[i];
6503
+ if (arg === "--") break;
6504
+ if (consumesNextArg(arg) && args[i + 1] === undefined) return null;
6505
+ if (["--last", "--help", "-h", "--remote"].includes(arg) || arg.startsWith("--remote=")) return null;
6506
+ if (arg === "--all") showAll = true;
6507
+ if (arg === "--include-non-interactive") includeNonInteractive = true;
6508
+ if (arg === "-C" || arg === "--cd") cwd = resolvePath(baseCwd, args[i + 1]);
6509
+ else if (arg.startsWith("--cd=")) cwd = resolvePath(baseCwd, arg.slice(5));
6510
+ else if (arg.startsWith("-C") && arg.length > 2) cwd = resolvePath(baseCwd, arg.slice(2));
6511
+ if (["-c", "--config", "-p", "--profile", "--enable", "--disable"].includes(arg)) {
6512
+ configArgs.push(arg, args[i + 1]);
6513
+ } else if (/^--(config|profile|enable|disable)=/.test(arg) || /^-[cp].+/.test(arg)) {
6514
+ configArgs.push(arg);
6515
+ }
6516
+ i = skipOptionValueSpan(args, i);
6517
+ }
6518
+ return { commandIndex: command.index, cwd, configArgs, showAll, includeNonInteractive };
6519
+ }
6520
+
6476
6521
  async function main() {
6477
6522
  hydrateCliVersionEnv();
6478
6523
 
@@ -6513,7 +6558,9 @@ async function main() {
6513
6558
  [
6514
6559
  "Could not locate the official Codex CLI.",
6515
6560
  "Install it with npm, Homebrew, or an official native release so `codex` is on PATH.",
6516
- "Or set CODEX_MULTI_AUTH_REAL_CODEX_BIN to the full path of either codex or @openai/codex/bin/codex.js.",
6561
+ process.platform === "win32"
6562
+ ? "Or set CODEX_MULTI_AUTH_REAL_CODEX_BIN to the full path of codex.exe or @openai/codex/bin/codex.js."
6563
+ : "Or set CODEX_MULTI_AUTH_REAL_CODEX_BIN to the full path of either codex or @openai/codex/bin/codex.js.",
6517
6564
  ].join("\n"),
6518
6565
  );
6519
6566
  return 1;
@@ -6522,12 +6569,42 @@ async function main() {
6522
6569
  // Resolve `--account` / CODEX_MULTI_AUTH_FORCE_ACCOUNT before forwarding: strip
6523
6570
  // the launcher-only flag from the Codex args and publish the resolved pin, or
6524
6571
  // fail hard so a forced account can never silently fall back to another one.
6572
+ if (hasNativeAppBinding(process.env)) {
6573
+ const forced = resolveForcedAccountSelector(rawArgs, process.env);
6574
+ if (forced.error || forced.selector !== null) {
6575
+ console.error(forced.error ?? "Native app binding uses the persistent inference selection. Use codex-multi-auth switch instead of --account.");
6576
+ return 1;
6577
+ }
6578
+ delete process.env.CODEX_MULTI_AUTH_FORCE_ACCOUNT_INDEX;
6579
+ // Best effort: a locked or read-only config.toml (Windows EPERM/EBUSY)
6580
+ // must not block the launch; the per-invocation override below still applies.
6581
+ await ensurePersistedCodexFileAuthStore();
6582
+ const { args: nativeArgs } = buildForwardArgs(forced.strippedArgs, { preserveNativeSettings: true });
6583
+ const result = await forwardToRealCodexOnce(realCodexBin, nativeArgs, process.env);
6584
+ return result.exitCode;
6585
+ }
6525
6586
  const forcedAccount = await applyForcedAccountSelection(rawArgs, process.env);
6526
6587
  if (forcedAccount.error) {
6527
6588
  console.error(forcedAccount.error);
6528
6589
  return 1;
6529
6590
  }
6530
- const forwardArgs = forcedAccount.forwardArgs;
6591
+ const forwardArgs = [...forcedAccount.forwardArgs];
6592
+
6593
+
6594
+ if (process.stdin.isTTY && process.stdout.isTTY && !bypass) {
6595
+ const pickerRequest = getResumePickerRequest(forwardArgs);
6596
+ if (pickerRequest && await isRuntimeRotationProxyEnabled(forwardArgs)) {
6597
+ try {
6598
+ const { pickResumeThread } = await import("../dist/lib/runtime/resume-picker.js");
6599
+ const id = await pickResumeThread({ ...pickerRequest, codexBin: realCodexBin });
6600
+ if (!id) return 0;
6601
+ forwardArgs.splice(pickerRequest.commandIndex + 1, 0, id);
6602
+ } catch (error) {
6603
+ // Discovery is optional: fall back to native `codex resume` with the original args.
6604
+ console.error(`Could not list saved Codex sessions: ${error instanceof Error ? error.message : String(error)}`);
6605
+ }
6606
+ }
6607
+ }
6531
6608
 
6532
6609
  await ensurePersistedCodexFileAuthStore();
6533
6610
  await autoSyncManagerActiveSelectionIfEnabled();
@@ -6546,6 +6623,7 @@ async function main() {
6546
6623
  // lib/request/helpers/model-map.ts (see test/codex-model-resolution.test.ts,
6547
6624
  // which asserts wrapper<->lib parity).
6548
6625
  export {
6626
+ isRuntimeRotationProxyEnabled,
6549
6627
  normalizeRequestedModel,
6550
6628
  coerceReasoningEffortForModel,
6551
6629
  resolveModelFamilyForStatus,