codex-multi-auth 2.16.0 → 2.17.2

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 (303) hide show
  1. package/.codex-plugin/plugin.json +9 -9
  2. package/LICENSE +21 -21
  3. package/README.md +487 -463
  4. package/assets/codex-multi-auth-icon.svg +39 -39
  5. package/assets/readme-hero.svg +31 -31
  6. package/config/README.md +31 -31
  7. package/config/codex-legacy.json +1221 -1221
  8. package/config/codex-modern.json +423 -423
  9. package/config/minimal-codex.json +15 -15
  10. package/dist/index.d.ts.map +1 -1
  11. package/dist/index.js +8 -3
  12. package/dist/lib/account-policy.d.ts +4 -0
  13. package/dist/lib/account-policy.d.ts.map +1 -1
  14. package/dist/lib/account-policy.js +8 -0
  15. package/dist/lib/accounts/rate-limits.d.ts.map +1 -1
  16. package/dist/lib/accounts/rate-limits.js +2 -0
  17. package/dist/lib/accounts.d.ts +15 -3
  18. package/dist/lib/accounts.d.ts.map +1 -1
  19. package/dist/lib/accounts.js +231 -30
  20. package/dist/lib/api-route-store.d.ts +24 -0
  21. package/dist/lib/api-route-store.d.ts.map +1 -0
  22. package/dist/lib/api-route-store.js +145 -0
  23. package/dist/lib/auth/account-access.d.ts +115 -0
  24. package/dist/lib/auth/account-access.d.ts.map +1 -0
  25. package/dist/lib/auth/account-access.js +214 -0
  26. package/dist/lib/auth/token-utils.d.ts +54 -1
  27. package/dist/lib/auth/token-utils.d.ts.map +1 -1
  28. package/dist/lib/auth/token-utils.js +92 -7
  29. package/dist/lib/cli.d.ts +1 -1
  30. package/dist/lib/cli.d.ts.map +1 -1
  31. package/dist/lib/cli.js +4 -0
  32. package/dist/lib/codex-cli/state.d.ts +7 -0
  33. package/dist/lib/codex-cli/state.d.ts.map +1 -1
  34. package/dist/lib/codex-cli/state.js +18 -0
  35. package/dist/lib/codex-cli/writer.d.ts.map +1 -1
  36. package/dist/lib/codex-cli/writer.js +60 -8
  37. package/dist/lib/codex-manager/account-manager-commands.d.ts.map +1 -1
  38. package/dist/lib/codex-manager/account-manager-commands.js +1 -0
  39. package/dist/lib/codex-manager/account-pool-write.d.ts +3 -1
  40. package/dist/lib/codex-manager/account-pool-write.d.ts.map +1 -1
  41. package/dist/lib/codex-manager/account-pool-write.js +4 -0
  42. package/dist/lib/codex-manager/api-login-menu.d.ts +14 -0
  43. package/dist/lib/codex-manager/api-login-menu.d.ts.map +1 -0
  44. package/dist/lib/codex-manager/api-login-menu.js +224 -0
  45. package/dist/lib/codex-manager/commands/account.d.ts.map +1 -1
  46. package/dist/lib/codex-manager/commands/account.js +27 -0
  47. package/dist/lib/codex-manager/commands/best.d.ts.map +1 -1
  48. package/dist/lib/codex-manager/commands/best.js +6 -2
  49. package/dist/lib/codex-manager/commands/check.d.ts +7 -1
  50. package/dist/lib/codex-manager/commands/check.d.ts.map +1 -1
  51. package/dist/lib/codex-manager/commands/check.js +24 -3
  52. package/dist/lib/codex-manager/commands/forecast.d.ts +1 -1
  53. package/dist/lib/codex-manager/commands/forecast.d.ts.map +1 -1
  54. package/dist/lib/codex-manager/commands/forecast.js +7 -3
  55. package/dist/lib/codex-manager/commands/report.d.ts.map +1 -1
  56. package/dist/lib/codex-manager/commands/report.js +5 -1
  57. package/dist/lib/codex-manager/commands/resets.d.ts +2 -0
  58. package/dist/lib/codex-manager/commands/resets.d.ts.map +1 -0
  59. package/dist/lib/codex-manager/commands/resets.js +67 -0
  60. package/dist/lib/codex-manager/commands/rotation.d.ts +2 -2
  61. package/dist/lib/codex-manager/commands/rotation.d.ts.map +1 -1
  62. package/dist/lib/codex-manager/commands/rotation.js +63 -12
  63. package/dist/lib/codex-manager/commands/status.d.ts +12 -1
  64. package/dist/lib/codex-manager/commands/status.d.ts.map +1 -1
  65. package/dist/lib/codex-manager/commands/status.js +166 -22
  66. package/dist/lib/codex-manager/commands/uninstall.js +1 -1
  67. package/dist/lib/codex-manager/formatters/quota-formatters.d.ts.map +1 -1
  68. package/dist/lib/codex-manager/formatters/quota-formatters.js +3 -2
  69. package/dist/lib/codex-manager/health-check.d.ts +3 -0
  70. package/dist/lib/codex-manager/health-check.d.ts.map +1 -1
  71. package/dist/lib/codex-manager/health-check.js +57 -7
  72. package/dist/lib/codex-manager/help.d.ts.map +1 -1
  73. package/dist/lib/codex-manager/help.js +4 -2
  74. package/dist/lib/codex-manager/login-flow.d.ts.map +1 -1
  75. package/dist/lib/codex-manager/login-flow.js +69 -7
  76. package/dist/lib/codex-manager/login-menu-data.d.ts.map +1 -1
  77. package/dist/lib/codex-manager/login-menu-data.js +21 -8
  78. package/dist/lib/codex-manager/login-oauth.d.ts +3 -0
  79. package/dist/lib/codex-manager/login-oauth.d.ts.map +1 -1
  80. package/dist/lib/codex-manager/login-oauth.js +6 -1
  81. package/dist/lib/codex-manager/login-workspace-choice.d.ts +11 -0
  82. package/dist/lib/codex-manager/login-workspace-choice.d.ts.map +1 -0
  83. package/dist/lib/codex-manager/login-workspace-choice.js +37 -0
  84. package/dist/lib/codex-manager/persist-selected-account.d.ts.map +1 -1
  85. package/dist/lib/codex-manager/persist-selected-account.js +2 -1
  86. package/dist/lib/codex-manager/quota-cache-helpers.d.ts +7 -1
  87. package/dist/lib/codex-manager/quota-cache-helpers.d.ts.map +1 -1
  88. package/dist/lib/codex-manager/quota-cache-helpers.js +34 -19
  89. package/dist/lib/codex-manager/repair-commands.d.ts +13 -0
  90. package/dist/lib/codex-manager/repair-commands.d.ts.map +1 -1
  91. package/dist/lib/codex-manager/repair-commands.js +144 -9
  92. package/dist/lib/codex-manager.d.ts.map +1 -1
  93. package/dist/lib/codex-manager.js +25 -6
  94. package/dist/lib/concurrency.d.ts +3 -0
  95. package/dist/lib/concurrency.d.ts.map +1 -0
  96. package/dist/lib/concurrency.js +31 -0
  97. package/dist/lib/context-budget-response.js +8 -8
  98. package/dist/lib/context-overflow.js +10 -10
  99. package/dist/lib/model-route-policy.d.ts +52 -0
  100. package/dist/lib/model-route-policy.d.ts.map +1 -0
  101. package/dist/lib/model-route-policy.js +159 -0
  102. package/dist/lib/oauth-success.html +125 -125
  103. package/dist/lib/policy/runtime-policy.d.ts +1 -0
  104. package/dist/lib/policy/runtime-policy.d.ts.map +1 -1
  105. package/dist/lib/policy/runtime-policy.js +3 -0
  106. package/dist/lib/preemptive-quota-scheduler.d.ts +2 -0
  107. package/dist/lib/preemptive-quota-scheduler.d.ts.map +1 -1
  108. package/dist/lib/preemptive-quota-scheduler.js +4 -0
  109. package/dist/lib/prompts/codex-host-bridge.js +138 -138
  110. package/dist/lib/prompts/codex.js +79 -79
  111. package/dist/lib/quota-cache.d.ts +7 -3
  112. package/dist/lib/quota-cache.d.ts.map +1 -1
  113. package/dist/lib/quota-cache.js +91 -59
  114. package/dist/lib/quota-probe.d.ts +5 -0
  115. package/dist/lib/quota-probe.d.ts.map +1 -1
  116. package/dist/lib/quota-probe.js +26 -2
  117. package/dist/lib/quota-readiness.d.ts +7 -2
  118. package/dist/lib/quota-readiness.d.ts.map +1 -1
  119. package/dist/lib/quota-readiness.js +25 -4
  120. package/dist/lib/request/client-cancellation.d.ts +5 -0
  121. package/dist/lib/request/client-cancellation.d.ts.map +1 -0
  122. package/dist/lib/request/client-cancellation.js +7 -0
  123. package/dist/lib/request/response-outcome.d.ts +25 -0
  124. package/dist/lib/request/response-outcome.d.ts.map +1 -0
  125. package/dist/lib/request/response-outcome.js +49 -0
  126. package/dist/lib/request/stream-failover-runtime.d.ts +2 -1
  127. package/dist/lib/request/stream-failover-runtime.d.ts.map +1 -1
  128. package/dist/lib/request/stream-failover-runtime.js +29 -10
  129. package/dist/lib/runtime/account-check.d.ts.map +1 -1
  130. package/dist/lib/runtime/account-check.js +2 -8
  131. package/dist/lib/runtime/account-model-catalog.d.ts +64 -0
  132. package/dist/lib/runtime/account-model-catalog.d.ts.map +1 -0
  133. package/dist/lib/runtime/account-model-catalog.js +154 -0
  134. package/dist/lib/runtime/account-pool.d.ts +3 -1
  135. package/dist/lib/runtime/account-pool.d.ts.map +1 -1
  136. package/dist/lib/runtime/account-pool.js +4 -0
  137. package/dist/lib/runtime/account-reset-credits.d.ts +42 -0
  138. package/dist/lib/runtime/account-reset-credits.d.ts.map +1 -0
  139. package/dist/lib/runtime/account-reset-credits.js +82 -0
  140. package/dist/lib/runtime/api-model-capabilities.d.ts +30 -0
  141. package/dist/lib/runtime/api-model-capabilities.d.ts.map +1 -0
  142. package/dist/lib/runtime/api-model-capabilities.js +434 -0
  143. package/dist/lib/runtime/api-model-runtime.d.ts +42 -0
  144. package/dist/lib/runtime/api-model-runtime.d.ts.map +1 -0
  145. package/dist/lib/runtime/api-model-runtime.js +358 -0
  146. package/dist/lib/runtime/app-bind.d.ts +19 -1
  147. package/dist/lib/runtime/app-bind.d.ts.map +1 -1
  148. package/dist/lib/runtime/app-bind.js +89 -11
  149. package/dist/lib/runtime/automatic-account-checks.d.ts +35 -0
  150. package/dist/lib/runtime/automatic-account-checks.d.ts.map +1 -0
  151. package/dist/lib/runtime/automatic-account-checks.js +140 -0
  152. package/dist/lib/runtime/automatic-subscription-checks.d.ts +7 -0
  153. package/dist/lib/runtime/automatic-subscription-checks.d.ts.map +1 -0
  154. package/dist/lib/runtime/automatic-subscription-checks.js +54 -0
  155. package/dist/lib/runtime/catalog-capabilities.d.ts +8 -0
  156. package/dist/lib/runtime/catalog-capabilities.d.ts.map +1 -0
  157. package/dist/lib/runtime/catalog-capabilities.js +61 -0
  158. package/dist/lib/runtime/inference-activity.d.ts +15 -0
  159. package/dist/lib/runtime/inference-activity.d.ts.map +1 -0
  160. package/dist/lib/runtime/inference-activity.js +95 -0
  161. package/dist/lib/runtime/model-discovery-status.d.ts +100 -0
  162. package/dist/lib/runtime/model-discovery-status.d.ts.map +1 -0
  163. package/dist/lib/runtime/model-discovery-status.js +387 -0
  164. package/dist/lib/runtime/native-account-storage.d.ts +11 -0
  165. package/dist/lib/runtime/native-account-storage.d.ts.map +1 -0
  166. package/dist/lib/runtime/native-account-storage.js +50 -0
  167. package/dist/lib/runtime/native-account-sync.d.ts +19 -0
  168. package/dist/lib/runtime/native-account-sync.d.ts.map +1 -0
  169. package/dist/lib/runtime/native-account-sync.js +62 -0
  170. package/dist/lib/runtime/native-binding-lock.d.ts +3 -0
  171. package/dist/lib/runtime/native-binding-lock.d.ts.map +1 -0
  172. package/dist/lib/runtime/native-binding-lock.js +5 -0
  173. package/dist/lib/runtime/native-client-auth.d.ts +3 -0
  174. package/dist/lib/runtime/native-client-auth.d.ts.map +1 -0
  175. package/dist/lib/runtime/native-client-auth.js +42 -0
  176. package/dist/lib/runtime/native-provider-config.d.ts +4 -0
  177. package/dist/lib/runtime/native-provider-config.d.ts.map +1 -0
  178. package/dist/lib/runtime/native-provider-config.js +52 -0
  179. package/dist/lib/runtime/native-rate-limits.d.ts +18 -0
  180. package/dist/lib/runtime/native-rate-limits.d.ts.map +1 -0
  181. package/dist/lib/runtime/native-rate-limits.js +135 -0
  182. package/dist/lib/runtime/reset-credit-routing.d.ts +41 -0
  183. package/dist/lib/runtime/reset-credit-routing.d.ts.map +1 -0
  184. package/dist/lib/runtime/reset-credit-routing.js +66 -0
  185. package/dist/lib/runtime/reset-credits.d.ts +101 -0
  186. package/dist/lib/runtime/reset-credits.d.ts.map +1 -0
  187. package/dist/lib/runtime/reset-credits.js +162 -0
  188. package/dist/lib/runtime/response-output-history.d.ts +17 -0
  189. package/dist/lib/runtime/response-output-history.d.ts.map +1 -0
  190. package/dist/lib/runtime/response-output-history.js +85 -0
  191. package/dist/lib/runtime/responses-websocket.d.ts +31 -0
  192. package/dist/lib/runtime/responses-websocket.d.ts.map +1 -0
  193. package/dist/lib/runtime/responses-websocket.js +636 -0
  194. package/dist/lib/runtime/resume-picker.d.ts +41 -0
  195. package/dist/lib/runtime/resume-picker.d.ts.map +1 -0
  196. package/dist/lib/runtime/resume-picker.js +169 -0
  197. package/dist/lib/runtime/rotation-account-selection.d.ts +6 -0
  198. package/dist/lib/runtime/rotation-account-selection.d.ts.map +1 -1
  199. package/dist/lib/runtime/rotation-account-selection.js +63 -0
  200. package/dist/lib/runtime/rotation-proxy-state.d.ts +33 -0
  201. package/dist/lib/runtime/rotation-proxy-state.d.ts.map +1 -1
  202. package/dist/lib/runtime/rotation-server-types.d.ts +18 -0
  203. package/dist/lib/runtime/rotation-server-types.d.ts.map +1 -1
  204. package/dist/lib/runtime/runtime-capability-failures.d.ts +14 -0
  205. package/dist/lib/runtime/runtime-capability-failures.d.ts.map +1 -0
  206. package/dist/lib/runtime/runtime-capability-failures.js +76 -0
  207. package/dist/lib/runtime/runtime-observability.d.ts +7 -0
  208. package/dist/lib/runtime/runtime-observability.d.ts.map +1 -1
  209. package/dist/lib/runtime/runtime-observability.js +42 -2
  210. package/dist/lib/runtime/subscription-first-use.d.ts +10 -0
  211. package/dist/lib/runtime/subscription-first-use.d.ts.map +1 -0
  212. package/dist/lib/runtime/subscription-first-use.js +64 -0
  213. package/dist/lib/runtime/subscription-quota-event.d.ts +6 -0
  214. package/dist/lib/runtime/subscription-quota-event.d.ts.map +1 -0
  215. package/dist/lib/runtime/subscription-quota-event.js +31 -0
  216. package/dist/lib/runtime/subscription-quota-order.d.ts +17 -0
  217. package/dist/lib/runtime/subscription-quota-order.d.ts.map +1 -0
  218. package/dist/lib/runtime/subscription-quota-order.js +31 -0
  219. package/dist/lib/runtime/workspace-model-scopes.d.ts +15 -0
  220. package/dist/lib/runtime/workspace-model-scopes.d.ts.map +1 -0
  221. package/dist/lib/runtime/workspace-model-scopes.js +34 -0
  222. package/dist/lib/runtime-constants.d.ts +3 -0
  223. package/dist/lib/runtime-constants.d.ts.map +1 -1
  224. package/dist/lib/runtime-constants.js +5 -0
  225. package/dist/lib/runtime-paths.d.ts.map +1 -1
  226. package/dist/lib/runtime-paths.js +4 -1
  227. package/dist/lib/runtime-rotation-proxy.d.ts.map +1 -1
  228. package/dist/lib/runtime-rotation-proxy.js +852 -42
  229. package/dist/lib/schemas.d.ts +20 -0
  230. package/dist/lib/schemas.d.ts.map +1 -1
  231. package/dist/lib/schemas.js +3 -0
  232. package/dist/lib/storage/credential-sidecars.d.ts +13 -0
  233. package/dist/lib/storage/credential-sidecars.d.ts.map +1 -0
  234. package/dist/lib/storage/credential-sidecars.js +52 -0
  235. package/dist/lib/storage/file-lock.d.ts +9 -0
  236. package/dist/lib/storage/file-lock.d.ts.map +1 -0
  237. package/dist/lib/storage/file-lock.js +186 -0
  238. package/dist/lib/storage/flagged-storage.d.ts.map +1 -1
  239. package/dist/lib/storage/flagged-storage.js +12 -0
  240. package/dist/lib/storage/path-state.d.ts +2 -0
  241. package/dist/lib/storage/path-state.d.ts.map +1 -1
  242. package/dist/lib/storage/path-state.js +9 -0
  243. package/dist/lib/storage/paths.js +4 -4
  244. package/dist/lib/storage/pending-auth.d.ts +18 -0
  245. package/dist/lib/storage/pending-auth.d.ts.map +1 -0
  246. package/dist/lib/storage/pending-auth.js +155 -0
  247. package/dist/lib/storage/public-types.d.ts +13 -0
  248. package/dist/lib/storage/public-types.d.ts.map +1 -1
  249. package/dist/lib/storage/record-identity.d.ts +16 -0
  250. package/dist/lib/storage/record-identity.d.ts.map +1 -0
  251. package/dist/lib/storage/record-identity.js +16 -0
  252. package/dist/lib/storage/snapshot-merge.d.ts +16 -0
  253. package/dist/lib/storage/snapshot-merge.d.ts.map +1 -0
  254. package/dist/lib/storage/snapshot-merge.js +206 -0
  255. package/dist/lib/storage/transactions.d.ts.map +1 -1
  256. package/dist/lib/storage/transactions.js +5 -4
  257. package/dist/lib/storage.d.ts +6 -0
  258. package/dist/lib/storage.d.ts.map +1 -1
  259. package/dist/lib/storage.js +77 -7
  260. package/dist/lib/ui/auth-menu-builder.d.ts +2 -0
  261. package/dist/lib/ui/auth-menu-builder.d.ts.map +1 -1
  262. package/dist/lib/ui/auth-menu-builder.js +1 -0
  263. package/dist/lib/ui/auth-menu.d.ts.map +1 -1
  264. package/dist/lib/ui/auth-menu.js +1 -0
  265. package/dist/lib/ui/check-progress.d.ts +8 -0
  266. package/dist/lib/ui/check-progress.d.ts.map +1 -0
  267. package/dist/lib/ui/check-progress.js +30 -0
  268. package/dist/lib/ui/format.d.ts +3 -1
  269. package/dist/lib/ui/format.d.ts.map +1 -1
  270. package/dist/lib/ui/format.js +8 -0
  271. package/dist/lib/ui/ui-copy.d.ts +2 -2
  272. package/dist/lib/ui/ui-copy.js +2 -2
  273. package/dist/lib/usage/pricing.js +2 -2
  274. package/dist/lib/usage/usage-extraction.d.ts +3 -1
  275. package/dist/lib/usage/usage-extraction.d.ts.map +1 -1
  276. package/dist/lib/usage/usage-extraction.js +46 -9
  277. package/node_modules/@codex-ai/plugin/dist/index.d.ts +2 -2
  278. package/node_modules/@codex-ai/plugin/dist/index.js +2 -2
  279. package/node_modules/@codex-ai/plugin/dist/tool.d.ts +42 -42
  280. package/node_modules/@codex-ai/plugin/dist/tool.js +29 -29
  281. package/node_modules/@codex-ai/plugin/package.json +9 -9
  282. package/node_modules/@codex-ai/sdk/dist/index.d.ts +4 -4
  283. package/node_modules/@codex-ai/sdk/dist/index.js +2 -2
  284. package/node_modules/@codex-ai/sdk/package.json +8 -8
  285. package/package.json +200 -197
  286. package/scripts/codex-app-launcher.js +653 -653
  287. package/scripts/codex-app-router.js +373 -366
  288. package/scripts/codex-bin-resolver.js +313 -281
  289. package/scripts/codex-multi-auth.js +59 -59
  290. package/scripts/codex-routing.js +62 -61
  291. package/scripts/codex.js +6642 -6564
  292. package/scripts/install-codex-auth-utils.js +213 -213
  293. package/scripts/mcodex.js +367 -367
  294. package/scripts/postinstall.js +114 -114
  295. package/scripts/preuninstall.js +265 -265
  296. package/vendor/codex-ai-plugin/dist/index.d.ts +2 -2
  297. package/vendor/codex-ai-plugin/dist/index.js +2 -2
  298. package/vendor/codex-ai-plugin/dist/tool.d.ts +42 -42
  299. package/vendor/codex-ai-plugin/dist/tool.js +29 -29
  300. package/vendor/codex-ai-plugin/package.json +9 -9
  301. package/vendor/codex-ai-sdk/dist/index.d.ts +4 -4
  302. package/vendor/codex-ai-sdk/dist/index.js +2 -2
  303. package/vendor/codex-ai-sdk/package.json +8 -8
@@ -1,366 +1,373 @@
1
- #!/usr/bin/env node
2
-
3
- import {
4
- chmodSync,
5
- closeSync,
6
- fstatSync,
7
- ftruncateSync,
8
- mkdirSync,
9
- openSync,
10
- readFileSync,
11
- renameSync,
12
- rmSync,
13
- statSync,
14
- truncateSync,
15
- writeSync,
16
- writeFileSync,
17
- } from "node:fs";
18
- import { basename, dirname, join } from "node:path";
19
- import process from "node:process";
20
-
21
- const DEFAULT_MAX_LOG_BYTES = 1024 * 1024;
22
- const LOG_SIZE_CHECK_INTERVAL_MS = 60_000;
23
-
24
- function parsePort(value) {
25
- if (typeof value !== "string" && typeof value !== "number") return Number.NaN;
26
- const text = String(value).trim();
27
- if (!/^\d+$/.test(text)) return Number.NaN;
28
- const port = Number(text);
29
- return Number.isInteger(port) && port >= 0 && port <= 65535
30
- ? port
31
- : Number.NaN;
32
- }
33
-
34
- function parseArgs(argv) {
35
- const result = {
36
- host: "127.0.0.1",
37
- port: 0,
38
- statusPath: "",
39
- identityToken: "",
40
- statePath: "",
41
- logPath: "",
42
- maxLogBytes: DEFAULT_MAX_LOG_BYTES,
43
- };
44
- for (let index = 0; index < argv.length; index += 1) {
45
- const arg = argv[index];
46
- const next = argv[index + 1] ?? "";
47
- if (arg === "--host") {
48
- result.host = next;
49
- index += 1;
50
- continue;
51
- }
52
- if (arg === "--port") {
53
- result.port = parsePort(next);
54
- index += 1;
55
- continue;
56
- }
57
- if (arg === "--status") {
58
- result.statusPath = next;
59
- index += 1;
60
- continue;
61
- }
62
- if (arg === "--identity-token") {
63
- result.identityToken = next;
64
- index += 1;
65
- continue;
66
- }
67
- if (arg === "--state") {
68
- result.statePath = next;
69
- index += 1;
70
- continue;
71
- }
72
- if (arg === "--max-log-bytes") {
73
- const parsed = Number.parseInt(next, 10);
74
- result.maxLogBytes =
75
- Number.isFinite(parsed) && parsed > 0
76
- ? parsed
77
- : DEFAULT_MAX_LOG_BYTES;
78
- index += 1;
79
- continue;
80
- }
81
- if (arg === "--log") {
82
- result.logPath = next;
83
- index += 1;
84
- }
85
- }
86
- return result;
87
- }
88
-
89
- function readState(path) {
90
- if (!path) return null;
91
- try {
92
- return JSON.parse(readFileSync(path, "utf8"));
93
- } catch {
94
- return null;
95
- }
96
- }
97
-
98
- function readTrimmedString(record, key) {
99
- const value = record?.[key];
100
- return typeof value === "string" && value.trim().length > 0
101
- ? value.trim()
102
- : undefined;
103
- }
104
-
105
- function writeStatus(statusPath, payload) {
106
- if (!statusPath) return;
107
- const statusDir = dirname(statusPath);
108
- const tempPath = join(
109
- statusDir,
110
- [
111
- `.${basename(statusPath)}`,
112
- String(process.pid),
113
- String(Date.now()),
114
- "tmp",
115
- ].join("."),
116
- );
117
- let fd = null;
118
- try {
119
- mkdirSync(statusDir, { recursive: true });
120
- fd = openSync(tempPath, "w", 0o600);
121
- writeFileSync(fd, `${JSON.stringify(payload, null, 2)}\n`, "utf8");
122
- closeSync(fd);
123
- fd = null;
124
- chmodSync(tempPath, 0o600);
125
- renameSync(tempPath, statusPath);
126
- chmodSync(statusPath, 0o600);
127
- } catch {
128
- // Status is best-effort. The router should keep serving if telemetry is locked.
129
- try {
130
- if (fd !== null) closeSync(fd);
131
- } catch {
132
- // Preserve the original status-write failure.
133
- }
134
- try {
135
- rmSync(tempPath, { force: true });
136
- } catch {
137
- // Preserve the original status-write failure.
138
- }
139
- }
140
- }
141
-
142
- function createStatusPayload({
143
- state,
144
- proxyServer,
145
- error,
146
- stateRecord,
147
- startedAt,
148
- statusPath,
149
- routerScriptPath,
150
- identityToken,
151
- }) {
152
- const proxyStatus =
153
- typeof proxyServer?.getStatus === "function" ? proxyServer.getStatus() : {};
154
- const lastAccountIndex = proxyStatus.lastAccountIndex ?? null;
155
- const lastAccountLabel =
156
- typeof proxyStatus.lastAccountLabel === "string" &&
157
- !proxyStatus.lastAccountLabel.includes("@")
158
- ? proxyStatus.lastAccountLabel
159
- : typeof lastAccountIndex === "number"
160
- ? `Account ${lastAccountIndex + 1}`
161
- : null;
162
- return {
163
- version: 1,
164
- kind: "codex-app-runtime-rotation-router",
165
- state,
166
- pid: process.pid,
167
- startedAt,
168
- statusPath: statusPath || readTrimmedString(stateRecord, "statusPath") || null,
169
- identityToken:
170
- identityToken || readTrimmedString(stateRecord, "identityToken") || null,
171
- routerScriptPath:
172
- routerScriptPath ||
173
- readTrimmedString(stateRecord, "routerScriptPath") ||
174
- process.argv[1] ||
175
- null,
176
- updatedAt: Date.now(),
177
- baseUrl: proxyServer?.baseUrl ?? stateRecord?.baseUrl ?? null,
178
- totalRequests: proxyStatus.totalRequests ?? 0,
179
- upstreamRequests: proxyStatus.upstreamRequests ?? 0,
180
- retries: proxyStatus.retries ?? 0,
181
- rotations: proxyStatus.rotations ?? 0,
182
- lastAccountIndex,
183
- lastAccountLabel,
184
- lastAccountId: proxyStatus.lastAccountId ?? null,
185
- lastAccountUpdatedAt: proxyStatus.lastAccountUpdatedAt ?? null,
186
- lastError: error ? (error instanceof Error ? error.message : String(error)) : proxyStatus.lastError ?? null,
187
- };
188
- }
189
-
190
- function isLoopbackHost(host) {
191
- if (typeof host !== "string") return false;
192
- const normalized = host.trim().toLowerCase();
193
- const unbracketed =
194
- normalized.startsWith("[") && normalized.endsWith("]")
195
- ? normalized.slice(1, -1)
196
- : normalized;
197
- return (
198
- unbracketed === "127.0.0.1" ||
199
- unbracketed === "::1" ||
200
- unbracketed === "localhost"
201
- );
202
- }
203
-
204
- function truncateLogFdIfTooLarge(fd, maxBytes) {
205
- if (!Number.isFinite(maxBytes) || maxBytes <= 0) return;
206
- try {
207
- const stats = fstatSync(fd);
208
- if (!stats.isFile() || stats.size <= maxBytes) return;
209
- ftruncateSync(fd, 0);
210
- writeSync(
211
- fd,
212
- `codex-multi-auth app router log truncated after exceeding ${maxBytes} bytes\n`,
213
- );
214
- } catch {
215
- // stdout/stderr may be pipes or otherwise unavailable; logging must not fail startup.
216
- }
217
- }
218
-
219
- function truncateLogPathIfTooLarge(logPath, maxBytes) {
220
- if (!logPath || !Number.isFinite(maxBytes) || maxBytes <= 0) return false;
221
- try {
222
- const stats = statSync(logPath);
223
- if (!stats.isFile() || stats.size <= maxBytes) return false;
224
- truncateSync(logPath, 0);
225
- return true;
226
- } catch {
227
- // Log path may not exist yet or may be locked; fd-level checks can still work.
228
- return false;
229
- }
230
- }
231
-
232
- function writeLogTruncatedMarker(maxBytes) {
233
- try {
234
- writeSync(
235
- 1,
236
- `codex-multi-auth app router log truncated after exceeding ${maxBytes} bytes\n`,
237
- );
238
- } catch {
239
- // A closed stdout/stderr should not crash the router while enforcing log bounds.
240
- }
241
- }
242
-
243
- function installLogBounds(maxBytes, logPath) {
244
- if (truncateLogPathIfTooLarge(logPath, maxBytes)) {
245
- writeLogTruncatedMarker(maxBytes);
246
- }
247
- truncateLogFdIfTooLarge(1, maxBytes);
248
- truncateLogFdIfTooLarge(2, maxBytes);
249
- return setInterval(() => {
250
- if (truncateLogPathIfTooLarge(logPath, maxBytes)) {
251
- writeLogTruncatedMarker(maxBytes);
252
- }
253
- truncateLogFdIfTooLarge(1, maxBytes);
254
- truncateLogFdIfTooLarge(2, maxBytes);
255
- }, LOG_SIZE_CHECK_INTERVAL_MS);
256
- }
257
-
258
- async function main() {
259
- const routerStartedAt = Date.now();
260
- const args = parseArgs(process.argv.slice(2));
261
- installLogBounds(args.maxLogBytes, args.logPath).unref?.();
262
- const stateRecord = readState(args.statePath);
263
- if (args.statePath && stateRecord === null) {
264
- const error = new Error(
265
- "Codex app runtime router state is unreadable; refusing to bind an ephemeral port.",
266
- );
267
- writeStatus(
268
- args.statusPath,
269
- createStatusPayload({
270
- state: "error",
271
- proxyServer: null,
272
- error,
273
- stateRecord: null,
274
- startedAt: routerStartedAt,
275
- statusPath: args.statusPath,
276
- routerScriptPath: process.argv[1],
277
- identityToken: args.identityToken,
278
- }),
279
- );
280
- throw error;
281
- }
282
- const host =
283
- typeof stateRecord?.host === "string" && stateRecord.host.trim().length > 0
284
- ? stateRecord.host.trim()
285
- : args.host;
286
- const statePort = parsePort(stateRecord?.port);
287
- const port = Number.isFinite(statePort) ? statePort : args.port;
288
- const clientApiKey = readTrimmedString(stateRecord, "clientApiKey");
289
- if (!Number.isInteger(port) || port < 0 || port > 65535) {
290
- throw new Error(
291
- "A valid --port in the range 0-65535 is required for the Codex app runtime router.",
292
- );
293
- }
294
- if (!isLoopbackHost(host)) {
295
- throw new Error(
296
- "Codex app runtime router host must be loopback-only (127.0.0.1, ::1, or localhost).",
297
- );
298
- }
299
- if (!clientApiKey) {
300
- throw new Error(
301
- "Codex app runtime router state is missing its client token.",
302
- );
303
- }
304
-
305
- let proxyServer = null;
306
- const writeCurrentStatus = (state, error) => {
307
- writeStatus(
308
- args.statusPath || stateRecord?.statusPath || "",
309
- createStatusPayload({
310
- state,
311
- proxyServer,
312
- error,
313
- stateRecord,
314
- startedAt: routerStartedAt,
315
- statusPath: args.statusPath || stateRecord?.statusPath || "",
316
- routerScriptPath: stateRecord?.routerScriptPath || process.argv[1],
317
- identityToken:
318
- args.identityToken || stateRecord?.identityToken || "",
319
- }),
320
- );
321
- };
322
-
323
- try {
324
- const proxyModule = await import("../dist/lib/runtime-rotation-proxy.js");
325
- proxyServer = await proxyModule.startRuntimeRotationProxy({
326
- host,
327
- port,
328
- clientApiKey,
329
- });
330
- writeCurrentStatus("running");
331
- const timer = setInterval(() => writeCurrentStatus("running"), 1000);
332
- let cleanupPromise = null;
333
- const cleanup = async (state) => {
334
- clearInterval(timer);
335
- try {
336
- await proxyServer?.close?.();
337
- } finally {
338
- writeCurrentStatus(state);
339
- }
340
- };
341
- const cleanupOnce = (state) => {
342
- cleanupPromise ??= cleanup(state);
343
- return cleanupPromise;
344
- };
345
- process.once("SIGINT", () => {
346
- void cleanupOnce("stopped").finally(() => process.exit(130));
347
- });
348
- process.once("SIGTERM", () => {
349
- void cleanupOnce("stopped").finally(() => process.exit(0));
350
- });
351
- process.once("SIGHUP", () => {
352
- void cleanupOnce("stopped").finally(() => process.exit(0));
353
- });
354
- await new Promise(() => undefined);
355
- } catch (error) {
356
- writeCurrentStatus("error", error);
357
- throw error;
358
- }
359
- }
360
-
361
- main().catch((error) => {
362
- console.error(
363
- `codex-multi-auth app router failed: ${error instanceof Error ? error.message : String(error)}`,
364
- );
365
- process.exitCode = 1;
366
- });
1
+ #!/usr/bin/env node
2
+
3
+ import {
4
+ chmodSync,
5
+ closeSync,
6
+ fstatSync,
7
+ ftruncateSync,
8
+ mkdirSync,
9
+ openSync,
10
+ readFileSync,
11
+ renameSync,
12
+ rmSync,
13
+ statSync,
14
+ truncateSync,
15
+ writeSync,
16
+ writeFileSync,
17
+ } from "node:fs";
18
+ import { basename, dirname, join } from "node:path";
19
+ import process from "node:process";
20
+
21
+ const DEFAULT_MAX_LOG_BYTES = 1024 * 1024;
22
+ const LOG_SIZE_CHECK_INTERVAL_MS = 60_000;
23
+
24
+ function parsePort(value) {
25
+ if (typeof value !== "string" && typeof value !== "number") return Number.NaN;
26
+ const text = String(value).trim();
27
+ if (!/^\d+$/.test(text)) return Number.NaN;
28
+ const port = Number(text);
29
+ return Number.isInteger(port) && port >= 0 && port <= 65535
30
+ ? port
31
+ : Number.NaN;
32
+ }
33
+
34
+ function parseArgs(argv) {
35
+ const result = {
36
+ host: "127.0.0.1",
37
+ port: 0,
38
+ statusPath: "",
39
+ identityToken: "",
40
+ statePath: "",
41
+ logPath: "",
42
+ maxLogBytes: DEFAULT_MAX_LOG_BYTES,
43
+ };
44
+ for (let index = 0; index < argv.length; index += 1) {
45
+ const arg = argv[index];
46
+ const next = argv[index + 1] ?? "";
47
+ if (arg === "--host") {
48
+ result.host = next;
49
+ index += 1;
50
+ continue;
51
+ }
52
+ if (arg === "--port") {
53
+ result.port = parsePort(next);
54
+ index += 1;
55
+ continue;
56
+ }
57
+ if (arg === "--status") {
58
+ result.statusPath = next;
59
+ index += 1;
60
+ continue;
61
+ }
62
+ if (arg === "--identity-token") {
63
+ result.identityToken = next;
64
+ index += 1;
65
+ continue;
66
+ }
67
+ if (arg === "--state") {
68
+ result.statePath = next;
69
+ index += 1;
70
+ continue;
71
+ }
72
+ if (arg === "--max-log-bytes") {
73
+ const parsed = Number.parseInt(next, 10);
74
+ result.maxLogBytes =
75
+ Number.isFinite(parsed) && parsed > 0
76
+ ? parsed
77
+ : DEFAULT_MAX_LOG_BYTES;
78
+ index += 1;
79
+ continue;
80
+ }
81
+ if (arg === "--log") {
82
+ result.logPath = next;
83
+ index += 1;
84
+ }
85
+ }
86
+ return result;
87
+ }
88
+
89
+ function readState(path) {
90
+ if (!path) return null;
91
+ try {
92
+ return JSON.parse(readFileSync(path, "utf8"));
93
+ } catch {
94
+ return null;
95
+ }
96
+ }
97
+
98
+ function readTrimmedString(record, key) {
99
+ const value = record?.[key];
100
+ return typeof value === "string" && value.trim().length > 0
101
+ ? value.trim()
102
+ : undefined;
103
+ }
104
+
105
+ function writeStatus(statusPath, payload) {
106
+ if (!statusPath) return;
107
+ const statusDir = dirname(statusPath);
108
+ const tempPath = join(
109
+ statusDir,
110
+ [
111
+ `.${basename(statusPath)}`,
112
+ String(process.pid),
113
+ String(Date.now()),
114
+ "tmp",
115
+ ].join("."),
116
+ );
117
+ let fd = null;
118
+ try {
119
+ mkdirSync(statusDir, { recursive: true });
120
+ fd = openSync(tempPath, "w", 0o600);
121
+ writeFileSync(fd, `${JSON.stringify(payload, null, 2)}\n`, "utf8");
122
+ closeSync(fd);
123
+ fd = null;
124
+ chmodSync(tempPath, 0o600);
125
+ renameSync(tempPath, statusPath);
126
+ chmodSync(statusPath, 0o600);
127
+ } catch {
128
+ // Status is best-effort. The router should keep serving if telemetry is locked.
129
+ try {
130
+ if (fd !== null) closeSync(fd);
131
+ } catch {
132
+ // Preserve the original status-write failure.
133
+ }
134
+ try {
135
+ rmSync(tempPath, { force: true });
136
+ } catch {
137
+ // Preserve the original status-write failure.
138
+ }
139
+ }
140
+ }
141
+
142
+ function createStatusPayload({
143
+ state,
144
+ proxyServer,
145
+ error,
146
+ stateRecord,
147
+ startedAt,
148
+ statusPath,
149
+ routerScriptPath,
150
+ identityToken,
151
+ }) {
152
+ const proxyStatus =
153
+ typeof proxyServer?.getStatus === "function" ? proxyServer.getStatus() : {};
154
+ const lastAccountIndex = proxyStatus.lastAccountIndex ?? null;
155
+ const lastAccountLabel =
156
+ typeof proxyStatus.lastAccountLabel === "string" &&
157
+ !proxyStatus.lastAccountLabel.includes("@")
158
+ ? proxyStatus.lastAccountLabel
159
+ : typeof lastAccountIndex === "number"
160
+ ? `Account ${lastAccountIndex + 1}`
161
+ : null;
162
+ return {
163
+ version: 1,
164
+ kind: "codex-app-runtime-rotation-router",
165
+ state,
166
+ pid: process.pid,
167
+ startedAt,
168
+ statusPath: statusPath || readTrimmedString(stateRecord, "statusPath") || null,
169
+ identityToken:
170
+ identityToken || readTrimmedString(stateRecord, "identityToken") || null,
171
+ routerScriptPath:
172
+ routerScriptPath ||
173
+ readTrimmedString(stateRecord, "routerScriptPath") ||
174
+ process.argv[1] ||
175
+ null,
176
+ updatedAt: Date.now(),
177
+ baseUrl: proxyServer?.baseUrl ?? stateRecord?.baseUrl ?? null,
178
+ totalRequests: proxyStatus.totalRequests ?? 0,
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,
184
+ retries: proxyStatus.retries ?? 0,
185
+ rotations: proxyStatus.rotations ?? 0,
186
+ lastAccountIndex,
187
+ lastAccountLabel,
188
+ lastAccountId: proxyStatus.lastAccountId ?? null,
189
+ lastRequestedWorkspaceId: proxyStatus.lastRequestedWorkspaceId ?? null,
190
+ lastAccountUpdatedAt: proxyStatus.lastAccountUpdatedAt ?? null,
191
+ lastError: error ? (error instanceof Error ? error.message : String(error)) : proxyStatus.lastError ?? null,
192
+ };
193
+ }
194
+
195
+ function isLoopbackHost(host) {
196
+ if (typeof host !== "string") return false;
197
+ const normalized = host.trim().toLowerCase();
198
+ const unbracketed =
199
+ normalized.startsWith("[") && normalized.endsWith("]")
200
+ ? normalized.slice(1, -1)
201
+ : normalized;
202
+ return (
203
+ unbracketed === "127.0.0.1" ||
204
+ unbracketed === "::1" ||
205
+ unbracketed === "localhost"
206
+ );
207
+ }
208
+
209
+ function truncateLogFdIfTooLarge(fd, maxBytes) {
210
+ if (!Number.isFinite(maxBytes) || maxBytes <= 0) return;
211
+ try {
212
+ const stats = fstatSync(fd);
213
+ if (!stats.isFile() || stats.size <= maxBytes) return;
214
+ ftruncateSync(fd, 0);
215
+ writeSync(
216
+ fd,
217
+ `codex-multi-auth app router log truncated after exceeding ${maxBytes} bytes\n`,
218
+ );
219
+ } catch {
220
+ // stdout/stderr may be pipes or otherwise unavailable; logging must not fail startup.
221
+ }
222
+ }
223
+
224
+ function truncateLogPathIfTooLarge(logPath, maxBytes) {
225
+ if (!logPath || !Number.isFinite(maxBytes) || maxBytes <= 0) return false;
226
+ try {
227
+ const stats = statSync(logPath);
228
+ if (!stats.isFile() || stats.size <= maxBytes) return false;
229
+ truncateSync(logPath, 0);
230
+ return true;
231
+ } catch {
232
+ // Log path may not exist yet or may be locked; fd-level checks can still work.
233
+ return false;
234
+ }
235
+ }
236
+
237
+ function writeLogTruncatedMarker(maxBytes) {
238
+ try {
239
+ writeSync(
240
+ 1,
241
+ `codex-multi-auth app router log truncated after exceeding ${maxBytes} bytes\n`,
242
+ );
243
+ } catch {
244
+ // A closed stdout/stderr should not crash the router while enforcing log bounds.
245
+ }
246
+ }
247
+
248
+ function installLogBounds(maxBytes, logPath) {
249
+ if (truncateLogPathIfTooLarge(logPath, maxBytes)) {
250
+ writeLogTruncatedMarker(maxBytes);
251
+ }
252
+ truncateLogFdIfTooLarge(1, maxBytes);
253
+ truncateLogFdIfTooLarge(2, maxBytes);
254
+ return setInterval(() => {
255
+ if (truncateLogPathIfTooLarge(logPath, maxBytes)) {
256
+ writeLogTruncatedMarker(maxBytes);
257
+ }
258
+ truncateLogFdIfTooLarge(1, maxBytes);
259
+ truncateLogFdIfTooLarge(2, maxBytes);
260
+ }, LOG_SIZE_CHECK_INTERVAL_MS);
261
+ }
262
+
263
+ async function main() {
264
+ const routerStartedAt = Date.now();
265
+ const args = parseArgs(process.argv.slice(2));
266
+ installLogBounds(args.maxLogBytes, args.logPath).unref?.();
267
+ const stateRecord = readState(args.statePath);
268
+ if (args.statePath && stateRecord === null) {
269
+ const error = new Error(
270
+ "Codex app runtime router state is unreadable; refusing to bind an ephemeral port.",
271
+ );
272
+ writeStatus(
273
+ args.statusPath,
274
+ createStatusPayload({
275
+ state: "error",
276
+ proxyServer: null,
277
+ error,
278
+ stateRecord: null,
279
+ startedAt: routerStartedAt,
280
+ statusPath: args.statusPath,
281
+ routerScriptPath: process.argv[1],
282
+ identityToken: args.identityToken,
283
+ }),
284
+ );
285
+ throw error;
286
+ }
287
+ const host =
288
+ typeof stateRecord?.host === "string" && stateRecord.host.trim().length > 0
289
+ ? stateRecord.host.trim()
290
+ : args.host;
291
+ const statePort = parsePort(stateRecord?.port);
292
+ const port = Number.isFinite(statePort) ? statePort : args.port;
293
+ const clientApiKey = readTrimmedString(stateRecord, "clientApiKey");
294
+ if (!Number.isInteger(port) || port < 0 || port > 65535) {
295
+ throw new Error(
296
+ "A valid --port in the range 0-65535 is required for the Codex app runtime router.",
297
+ );
298
+ }
299
+ if (!isLoopbackHost(host)) {
300
+ throw new Error(
301
+ "Codex app runtime router host must be loopback-only (127.0.0.1, ::1, or localhost).",
302
+ );
303
+ }
304
+ if (!clientApiKey) {
305
+ throw new Error(
306
+ "Codex app runtime router state is missing its client token.",
307
+ );
308
+ }
309
+
310
+ let proxyServer = null;
311
+ const writeCurrentStatus = (state, error) => {
312
+ writeStatus(
313
+ args.statusPath || stateRecord?.statusPath || "",
314
+ createStatusPayload({
315
+ state,
316
+ proxyServer,
317
+ error,
318
+ stateRecord,
319
+ startedAt: routerStartedAt,
320
+ statusPath: args.statusPath || stateRecord?.statusPath || "",
321
+ routerScriptPath: stateRecord?.routerScriptPath || process.argv[1],
322
+ identityToken:
323
+ args.identityToken || stateRecord?.identityToken || "",
324
+ }),
325
+ );
326
+ };
327
+
328
+ try {
329
+ const proxyModule = await import("../dist/lib/runtime-rotation-proxy.js");
330
+ proxyServer = await proxyModule.startRuntimeRotationProxy({
331
+ nativeOpenai: stateRecord?.nativeOpenai === true,
332
+ catalogAccount: stateRecord?.catalogAccount,
333
+ host,
334
+ port,
335
+ clientApiKey,
336
+ });
337
+ writeCurrentStatus("running");
338
+ const timer = setInterval(() => writeCurrentStatus("running"), 1000);
339
+ let cleanupPromise = null;
340
+ const cleanup = async (state) => {
341
+ clearInterval(timer);
342
+ try {
343
+ await proxyServer?.close?.();
344
+ } finally {
345
+ writeCurrentStatus(state);
346
+ }
347
+ };
348
+ const cleanupOnce = (state) => {
349
+ cleanupPromise ??= cleanup(state);
350
+ return cleanupPromise;
351
+ };
352
+ process.once("SIGINT", () => {
353
+ void cleanupOnce("stopped").finally(() => process.exit(130));
354
+ });
355
+ process.once("SIGTERM", () => {
356
+ void cleanupOnce("stopped").finally(() => process.exit(0));
357
+ });
358
+ process.once("SIGHUP", () => {
359
+ void cleanupOnce("stopped").finally(() => process.exit(0));
360
+ });
361
+ await new Promise(() => undefined);
362
+ } catch (error) {
363
+ writeCurrentStatus("error", error);
364
+ throw error;
365
+ }
366
+ }
367
+
368
+ main().catch((error) => {
369
+ console.error(
370
+ `codex-multi-auth app router failed: ${error instanceof Error ? error.message : String(error)}`,
371
+ );
372
+ process.exitCode = 1;
373
+ });