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
@@ -0,0 +1,35 @@
1
+ import { type AccountPolicyStore } from "../account-policy.js";
2
+ import type { AccountMetadataV3, AccountStorageV3 } from "../storage.js";
3
+ export declare const AUTOMATIC_CHECK_INTERVAL_MS: number;
4
+ /** First tick after router start, so a short CLI session still gets its check. */
5
+ export declare const AUTOMATIC_CHECK_INITIAL_DELAY_MS = 5000;
6
+ export interface AutomaticAccountCheckOptions {
7
+ path: string;
8
+ loadAccounts: () => Promise<AccountStorageV3 | null>;
9
+ loadPolicies: () => Promise<AccountPolicyStore>;
10
+ check: (storage: AccountStorageV3, index: number, signal: AbortSignal) => Promise<void>;
11
+ now?: () => number;
12
+ signal?: AbortSignal;
13
+ }
14
+ /** Honor the saved selection; a disabled/invalid selection must not fall back to a sibling. */
15
+ export declare function automaticCheckWorkspaceId(account: AccountMetadataV3): string | undefined;
16
+ /** Policy keys can be shared by organization members; attempt limits must never be. */
17
+ export declare function automaticAccountCheckKey(account: AccountMetadataV3): string;
18
+ /** A durable attempt precedes network I/O, so failures and competing routers cannot double-prime. */
19
+ export declare function runAutomaticAccountChecks(options: AutomaticAccountCheckOptions): Promise<void>;
20
+ /**
21
+ * No overlapping ticks; shutdown cancels the active probe and waits for its cleanup.
22
+ * The first tick runs shortly after start, off the startup path; the durable
23
+ * per-account attempts in runAutomaticAccountChecks keep it from repeating work
24
+ * this or another router did recently, and it does nothing without an opt-in.
25
+ *
26
+ * Each later tick is scheduled one interval after the previous run finishes.
27
+ * A run records its attempts before it finishes, so the next tick is never
28
+ * inside the durable per-account limit. A fixed setInterval ticked just inside
29
+ * it (by the initial delay plus the run's own duration), skipped every
30
+ * account, and stretched the cadence to two intervals.
31
+ */
32
+ export declare function startAutomaticAccountChecks(run: (signal: AbortSignal) => Promise<void>): {
33
+ stop(): Promise<void>;
34
+ };
35
+ //# sourceMappingURL=automatic-account-checks.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"automatic-account-checks.d.ts","sourceRoot":"","sources":["../../../lib/runtime/automatic-account-checks.ts"],"names":[],"mappings":"AAKA,OAAO,EAAuB,KAAK,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AACpF,OAAO,KAAK,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAKzE,eAAO,MAAM,2BAA2B,QAAa,CAAC;AACtD,kFAAkF;AAClF,eAAO,MAAM,gCAAgC,OAAO,CAAC;AAKrD,MAAM,WAAW,4BAA4B;IACzC,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,MAAM,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC,CAAC;IACrD,YAAY,EAAE,MAAM,OAAO,CAAC,kBAAkB,CAAC,CAAC;IAChD,KAAK,EAAE,CAAC,OAAO,EAAE,gBAAgB,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACxF,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,WAAW,CAAC;CACxB;AACD,+FAA+F;AAC/F,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,iBAAiB,GAAG,MAAM,GAAG,SAAS,CAMxF;AAED,uFAAuF;AACvF,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,iBAAiB,GAAG,MAAM,CAE3E;AAkCD,qGAAqG;AACrG,wBAAsB,yBAAyB,CAAC,OAAO,EAAE,4BAA4B,GAAG,OAAO,CAAC,IAAI,CAAC,CAyCpG;AACD;;;;;;;;;;;GAWG;AACH,wBAAgB,2BAA2B,CAAC,GAAG,EAAE,CAAC,MAAM,EAAE,WAAW,KAAK,OAAO,CAAC,IAAI,CAAC;;EAwBtF"}
@@ -0,0 +1,140 @@
1
+ import { createHash } from "node:crypto";
2
+ import { promises as fs } from "node:fs";
3
+ import { z } from "zod";
4
+ import { resolveAccountRecordId } from "../accounts.js";
5
+ import { extractAccountId } from "../auth/token-utils.js";
6
+ import { getAccountPolicyKey } from "../account-policy.js";
7
+ import { withFileTransactionLock } from "../storage/file-lock.js";
8
+ import { withRetry } from "../fs-retry.js";
9
+ import { tempPathFor } from "../temp-path.js";
10
+ import { logWarn } from "../logger.js";
11
+ export const AUTOMATIC_CHECK_INTERVAL_MS = 15 * 60000;
12
+ /** First tick after router start, so a short CLI session still gets its check. */
13
+ export const AUTOMATIC_CHECK_INITIAL_DELAY_MS = 5000;
14
+ /** An attempt stamped further ahead than this predates a backwards clock step: treat it as expired. */
15
+ const FUTURE_SKEW_MS = 5 * 60000;
16
+ const schema = z.record(z.string().regex(/^sha256:[a-f0-9]{64}$/), z.number().finite().nonnegative());
17
+ const retry = { maxAttempts: 6, backoffMs: 25 };
18
+ /** Honor the saved selection; a disabled/invalid selection must not fall back to a sibling. */
19
+ export function automaticCheckWorkspaceId(account) {
20
+ if (account.workspaces?.length) {
21
+ const selected = account.workspaces[account.currentWorkspaceIndex ?? 0];
22
+ return selected?.enabled === false ? undefined : selected?.id.trim() || undefined;
23
+ }
24
+ return account.accountId?.trim() || extractAccountId(account.accessToken) || undefined;
25
+ }
26
+ /** Policy keys can be shared by organization members; attempt limits must never be. */
27
+ export function automaticAccountCheckKey(account) {
28
+ return workspaceAttemptKey(account, automaticCheckWorkspaceId(account) ?? "");
29
+ }
30
+ /** Build the same key for inactive workspaces while pruning the attempt journal. */
31
+ function workspaceAttemptKey(account, workspaceId) {
32
+ return `sha256:${createHash("sha256").update(JSON.stringify([
33
+ "automatic-check-v2", resolveAccountRecordId(account), workspaceId,
34
+ ])).digest("hex")}`;
35
+ }
36
+ /** Reject unreadable or oversized history rather than silently allowing duplicate probes. */
37
+ async function readAttempts(path) {
38
+ try {
39
+ const raw = await withRetry(() => fs.readFile(path, "utf8"), retry);
40
+ if (Buffer.byteLength(raw) > 1024 * 1024)
41
+ throw Error("Automatic-check history exceeds its size limit");
42
+ return schema.parse(JSON.parse(raw));
43
+ }
44
+ catch (error) {
45
+ if (error.code === "ENOENT")
46
+ return {};
47
+ throw error;
48
+ }
49
+ }
50
+ /** Atomically persist attempt timestamps before any billable network request. */
51
+ async function saveAttempts(path, attempts) {
52
+ const temp = tempPathFor(path);
53
+ try {
54
+ await fs.writeFile(temp, JSON.stringify(attempts) + "\n", { mode: 0o600, flag: "wx" });
55
+ await withRetry(() => fs.rename(temp, path), retry);
56
+ }
57
+ finally {
58
+ await withRetry(() => fs.rm(temp, { force: true }), retry);
59
+ }
60
+ }
61
+ /** A durable attempt precedes network I/O, so failures and competing routers cannot double-prime. */
62
+ export async function runAutomaticAccountChecks(options) {
63
+ const signal = options.signal ?? new AbortController().signal;
64
+ if (signal.aborted || !Object.values((await options.loadPolicies()).accounts).some(p => p.autoPrime))
65
+ return;
66
+ await withFileTransactionLock(options.path, async () => {
67
+ const policies = await options.loadPolicies();
68
+ const storage = await options.loadAccounts();
69
+ if (!storage || signal.aborted)
70
+ return;
71
+ const attempts = await readAttempts(options.path);
72
+ // Keep every still-saved workspace's throttle, including temporarily disabled selections.
73
+ const keys = new Set(storage.accounts.flatMap(account => [
74
+ automaticAccountCheckKey(account),
75
+ ...(account.workspaces ?? []).map(workspace => workspaceAttemptKey(account, workspace.id.trim())),
76
+ ]));
77
+ for (const key of Object.keys(attempts))
78
+ if (!keys.has(key))
79
+ delete attempts[key];
80
+ for (let index = 0; index < storage.accounts.length; index++) {
81
+ if (signal.aborted)
82
+ break;
83
+ const account = storage.accounts[index];
84
+ if (!account)
85
+ continue;
86
+ const key = automaticAccountCheckKey(account), policy = policies.accounts[getAccountPolicyKey(account)], now = options.now?.() ?? Date.now();
87
+ if (!policy?.autoPrime || policy.paused || policy.drained || account.enabled === false || account.authInvalidatedAt || (account.coolingDownUntil ?? 0) > now)
88
+ continue;
89
+ const lastAttempt = attempts[key];
90
+ if (lastAttempt !== undefined && lastAttempt <= now + FUTURE_SKEW_MS && now - lastAttempt < AUTOMATIC_CHECK_INTERVAL_MS)
91
+ continue;
92
+ attempts[key] = now;
93
+ await saveAttempts(options.path, attempts);
94
+ try {
95
+ await options.check(storage, index, signal);
96
+ }
97
+ catch {
98
+ if (!signal.aborted)
99
+ logWarn("Automatic subscription check failed; retry deferred until the next interval.");
100
+ }
101
+ }
102
+ }, { waitMs: 0 });
103
+ }
104
+ /**
105
+ * No overlapping ticks; shutdown cancels the active probe and waits for its cleanup.
106
+ * The first tick runs shortly after start, off the startup path; the durable
107
+ * per-account attempts in runAutomaticAccountChecks keep it from repeating work
108
+ * this or another router did recently, and it does nothing without an opt-in.
109
+ *
110
+ * Each later tick is scheduled one interval after the previous run finishes.
111
+ * A run records its attempts before it finishes, so the next tick is never
112
+ * inside the durable per-account limit. A fixed setInterval ticked just inside
113
+ * it (by the initial delay plus the run's own duration), skipped every
114
+ * account, and stretched the cadence to two intervals.
115
+ */
116
+ export function startAutomaticAccountChecks(run) {
117
+ const controller = new AbortController();
118
+ let pending;
119
+ let timer;
120
+ const schedule = (delayMs) => {
121
+ if (controller.signal.aborted)
122
+ return;
123
+ timer = setTimeout(tick, delayMs);
124
+ timer.unref();
125
+ };
126
+ const tick = () => {
127
+ timer = undefined;
128
+ if (controller.signal.aborted)
129
+ return;
130
+ pending = run(controller.signal).catch(() => {
131
+ if (!controller.signal.aborted)
132
+ logWarn("Automatic subscription checks unavailable; no unchecked retry was started.");
133
+ }).finally(() => {
134
+ pending = undefined;
135
+ schedule(AUTOMATIC_CHECK_INTERVAL_MS);
136
+ });
137
+ };
138
+ schedule(AUTOMATIC_CHECK_INITIAL_DELAY_MS);
139
+ return { async stop() { clearTimeout(timer); controller.abort(); await pending; } };
140
+ }
@@ -0,0 +1,7 @@
1
+ import { type AccountMetadataV3 } from "../storage.js";
2
+ import { type CodexQuotaSnapshot } from "../quota-probe.js";
3
+ type Observer = (account: AccountMetadataV3, snapshot: CodexQuotaSnapshot, accounts: AccountMetadataV3[], workspaceId: string) => Promise<void> | void;
4
+ /** Captures this router's pool; reads only verified primary credentials, never API/ZDR entries. */
5
+ export declare function createAutomaticSubscriptionCheck(observe?: Observer): (signal: AbortSignal) => Promise<void>;
6
+ export {};
7
+ //# sourceMappingURL=automatic-subscription-checks.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"automatic-subscription-checks.d.ts","sourceRoot":"","sources":["../../../lib/runtime/automatic-subscription-checks.ts"],"names":[],"mappings":"AAGA,OAAO,EAAkB,KAAK,iBAAiB,EAAE,MAAM,eAAe,CAAC;AACvE,OAAO,EAA2B,KAAK,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAOrF,KAAK,QAAQ,GAAG,CAAC,OAAO,EAAE,iBAAiB,EAAE,QAAQ,EAAE,kBAAkB,EAAE,QAAQ,EAAE,iBAAiB,EAAE,EAAE,WAAW,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;AACvJ,mGAAmG;AACnG,wBAAgB,gCAAgC,CAAC,OAAO,CAAC,EAAE,QAAQ,IASvD,QAAQ,WAAW,mBAgC9B"}
@@ -0,0 +1,54 @@
1
+ import { getStoragePathState, runWithStoragePathState } from "../storage/path-state.js";
2
+ import { AccountManager, resolveAccountRecordId } from "../accounts.js";
3
+ import { getAccountPolicyKey, loadAccountPolicyStore } from "../account-policy.js";
4
+ import { getStoragePath } from "../storage.js";
5
+ import { fetchCodexQuotaSnapshot } from "../quota-probe.js";
6
+ import { loadQuotaCache, saveQuotaCache } from "../quota-cache.js";
7
+ import { updateQuotaCacheForWorkspace } from "../codex-manager/quota-cache-helpers.js";
8
+ import { createNativeAccountStorageReader } from "./native-account-storage.js";
9
+ import { ensureFreshAccessToken } from "./rotation-token-refresh.js";
10
+ import { automaticCheckWorkspaceId, runAutomaticAccountChecks } from "./automatic-account-checks.js";
11
+ import { logWarn } from "../logger.js";
12
+ /** Captures this router's pool; reads only verified primary credentials, never API/ZDR entries. */
13
+ export function createAutomaticSubscriptionCheck(observe) {
14
+ const path = getStoragePath(), storageState = getStoragePathState();
15
+ const read = createNativeAccountStorageReader(undefined, path);
16
+ const onQuota = observe ?? (async (account, snapshot, accounts, workspaceId) => {
17
+ const cache = await loadQuotaCache();
18
+ const baseline = structuredClone(cache);
19
+ updateQuotaCacheForWorkspace(cache, account, workspaceId, snapshot, accounts);
20
+ await saveQuotaCache(cache, baseline);
21
+ });
22
+ return (signal) => runWithStoragePathState(storageState, () => runAutomaticAccountChecks({
23
+ path: `${path}.automatic-checks.json`, signal, loadPolicies: loadAccountPolicyStore,
24
+ loadAccounts: async () => { const snapshot = await read(); return snapshot.verified ? snapshot.storage : null; },
25
+ check: async (storage, index) => {
26
+ const manager = new AccountManager(undefined, storage);
27
+ const account = manager.getAccountByIndex(index);
28
+ const stored = storage.accounts[index];
29
+ const targetId = stored && automaticCheckWorkspaceId(stored);
30
+ if (!account || !targetId || signal.aborted)
31
+ return;
32
+ const fresh = await ensureFreshAccessToken({ accountManager: manager, account, family: "codex", model: null, now: Date.now(), tokenRefreshSkewMs: 60000, tokenInvalidationCooldownMs: 300000 });
33
+ try {
34
+ if (!fresh.ok || signal.aborted)
35
+ return;
36
+ // A refresh is an I/O boundary: revalidate removal, policy, auth and workspace changes.
37
+ const disk = await read();
38
+ const current = disk.verified ? disk.storage?.accounts.find(row => resolveAccountRecordId(row) === resolveAccountRecordId(fresh.account)) : undefined;
39
+ const policy = current ? (await loadAccountPolicyStore()).accounts[getAccountPolicyKey(current)] : undefined;
40
+ if (!disk.storage || !current || current.refreshToken !== fresh.account.refreshToken || current.accessToken !== fresh.accessToken || !policy?.autoPrime || policy.paused || policy.drained || current.enabled === false || current.authInvalidatedAt || (current.coolingDownUntil ?? 0) > Date.now())
41
+ return;
42
+ if (automaticCheckWorkspaceId(current) !== targetId || signal.aborted)
43
+ return;
44
+ const snapshot = await fetchCodexQuotaSnapshot({ accountId: targetId, accessToken: fresh.accessToken, primeUnusedSubscription: true, signal });
45
+ if (snapshot.primingFailure)
46
+ logWarn("Automatic first-use completion was not confirmed; retry deferred until the next check.");
47
+ await onQuota(current, snapshot, disk.storage.accounts, targetId);
48
+ }
49
+ finally {
50
+ await manager.flushPendingSave();
51
+ }
52
+ },
53
+ }));
54
+ }
@@ -0,0 +1,8 @@
1
+ import type { CatalogModel } from "./account-model-catalog.js";
2
+ /** Aggregate complete source records so advertised controls never invent a pair. */
3
+ export declare function mergeCatalogModels(models: readonly CatalogModel[]): CatalogModel | undefined;
4
+ /** Two-source convenience; multi-account callers must retain all original records. */
5
+ export declare function mergeCatalogModel(a: CatalogModel, b: CatalogModel): CatalogModel;
6
+ export declare function clampCatalogContext(a: CatalogModel, b: CatalogModel): CatalogModel;
7
+ export declare function supportsCatalogSettings(model: CatalogModel, effort?: string, tier?: string): boolean;
8
+ //# sourceMappingURL=catalog-capabilities.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"catalog-capabilities.d.ts","sourceRoot":"","sources":["../../../lib/runtime/catalog-capabilities.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAG/D,oFAAoF;AACpF,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,SAAS,YAAY,EAAE,GAAG,YAAY,GAAG,SAAS,CA4B5F;AACD,sFAAsF;AACtF,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,YAAY,EAAE,CAAC,EAAE,YAAY,GAAG,YAAY,CAEhF;AACD,wBAAgB,mBAAmB,CAAC,CAAC,EAAE,YAAY,EAAE,CAAC,EAAE,YAAY,GAAG,YAAY,CAWlF;AACD,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,YAAY,EAAE,MAAM,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO,CAMpG"}
@@ -0,0 +1,61 @@
1
+ import { isRecord } from "../utils.js";
2
+ const contextLimits = ["context_window", "max_context_window", "auto_compact_token_limit"];
3
+ const canonicalTier = (value) => value === "priority" ? "fast" : value;
4
+ /** Aggregate complete source records so advertised controls never invent a pair. */
5
+ export function mergeCatalogModels(models) {
6
+ const first = models[0];
7
+ if (!first)
8
+ return undefined;
9
+ let result = { ...first };
10
+ for (const [field, key] of [["supported_reasoning_levels", "effort"], ["service_tiers", "id"]]) {
11
+ const options = new Map();
12
+ for (const model of models)
13
+ for (const option of Array.isArray(model[field]) ? model[field] : []) {
14
+ if (isRecord(option) && typeof option[key] === "string")
15
+ options.set(field === "service_tiers" ? canonicalTier(option[key]) : option[key], option);
16
+ }
17
+ if (options.size)
18
+ result[field] = [...options.values()];
19
+ }
20
+ const efforts = Array.isArray(result.supported_reasoning_levels)
21
+ ? result.supported_reasoning_levels.flatMap(level => isRecord(level) && typeof level.effort === "string" ? [level.effort] : []) : [];
22
+ if (Array.isArray(result.service_tiers)) {
23
+ // Native clients expose independent effort/speed controls, not a pair matrix.
24
+ // Every selectable pair therefore needs a witness in an original catalog.
25
+ result.service_tiers = result.service_tiers.filter(tier => {
26
+ if (!isRecord(tier) || typeof tier.id !== "string")
27
+ return false;
28
+ const id = tier.id;
29
+ return (efforts.length ? efforts : [undefined]).every(effort => models.some(model => supportsCatalogSettings(model, effort, id)));
30
+ });
31
+ }
32
+ if (typeof result.default_service_tier === "string" && !["default", "auto"].includes(result.default_service_tier) &&
33
+ !supportsCatalogSettings(result, undefined, result.default_service_tier))
34
+ result.default_service_tier = "default";
35
+ for (const model of models.slice(1))
36
+ result = clampCatalogContext(result, model);
37
+ return result;
38
+ }
39
+ /** Two-source convenience; multi-account callers must retain all original records. */
40
+ export function mergeCatalogModel(a, b) {
41
+ return mergeCatalogModels([a, b]) ?? a;
42
+ }
43
+ export function clampCatalogContext(a, b) {
44
+ const result = { ...a };
45
+ // Context is not a selectable setting sent on requests. Advertise the safe
46
+ // shared limit instead of letting the first account overstate another's limit.
47
+ for (const field of contextLimits) {
48
+ if (typeof a[field] === "number" && typeof b[field] === "number")
49
+ result[field] = Math.min(a[field], b[field]);
50
+ else
51
+ delete result[field];
52
+ }
53
+ return result;
54
+ }
55
+ export function supportsCatalogSettings(model, effort, tier) {
56
+ if (effort && (!Array.isArray(model.supported_reasoning_levels) || !model.supported_reasoning_levels.some(level => isRecord(level) && level.effort === effort)))
57
+ return false;
58
+ if (tier && tier !== "default" && tier !== "auto" && (!Array.isArray(model.service_tiers) || !model.service_tiers.some(level => isRecord(level) && typeof level.id === "string" && canonicalTier(level.id) === canonicalTier(tier))))
59
+ return false;
60
+ return true;
61
+ }
@@ -0,0 +1,15 @@
1
+ import { getAccountIdentityKey } from "../storage/identity.js";
2
+ export declare function inferenceAccountKey(account: Parameters<typeof getAccountIdentityKey>[0]): string;
3
+ /** Separate from shared diagnostic snapshots: only inference dispatches write these files. */
4
+ export declare function saveInferenceRequestTime(key: string, at: number): Promise<void>;
5
+ /**
6
+ * Per-request dispatches only need the latest time per key on disk. Keep the
7
+ * newest pending time per key and write them together after a short debounce,
8
+ * instead of chaining one mkdir/read/write/rename per request.
9
+ */
10
+ export declare function createInferenceActivityWriter(save?: (key: string, at: number) => Promise<void>, delayMs?: number, onError?: (error: unknown) => void): {
11
+ record(key: string, at: number): void;
12
+ flush(): Promise<void>;
13
+ };
14
+ export declare function loadInferenceRequestTimes(keys: string[]): Promise<Record<string, number>>;
15
+ //# sourceMappingURL=inference-activity.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inference-activity.d.ts","sourceRoot":"","sources":["../../../lib/runtime/inference-activity.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAC;AAS/D,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,UAAU,CAAC,OAAO,qBAAqB,CAAC,CAAC,CAAC,CAAC,GAAG,MAAM,CAEhG;AAmBD,8FAA8F;AAC9F,wBAAsB,wBAAwB,CAAC,GAAG,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAgBrF;AACD;;;;GAIG;AACH,wBAAgB,6BAA6B,CAC5C,IAAI,GAAE,CAAC,GAAG,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAA4B,EAC3E,OAAO,SAAO,EACd,OAAO,GAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAsB,GACjD;IAAE,MAAM,CAAC,GAAG,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;CAAE,CAwBnE;AACD,wBAAsB,yBAAyB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAG/F"}
@@ -0,0 +1,95 @@
1
+ import { createHash } from "node:crypto";
2
+ import { getAccountIdentityKey } from "../storage/identity.js";
3
+ import { promises as fs } from "node:fs";
4
+ import { join } from "node:path";
5
+ import { getCodexMultiAuthDir } from "../runtime-paths.js";
6
+ import { tempPathFor } from "../temp-path.js";
7
+ import { withRetry } from "../fs-retry.js";
8
+ import { withFileTransactionLock } from "../storage/file-lock.js";
9
+ import { mapWithConcurrency } from "../concurrency.js";
10
+ export function inferenceAccountKey(account) {
11
+ return `sha256:${createHash("sha256").update(getAccountIdentityKey(account) ?? "unknown").digest("hex")}`;
12
+ }
13
+ const validKey = (key) => /^sha256:[a-f0-9]{64}$/.test(key);
14
+ function activityPath(key) {
15
+ return join(getCodexMultiAuthDir(), "inference-activity", `${key.slice(7)}.json`);
16
+ }
17
+ async function readTimestamp(key) {
18
+ try {
19
+ const handle = await fs.open(activityPath(key), "r");
20
+ try {
21
+ const bytes = Buffer.alloc(64);
22
+ const { bytesRead } = await handle.read(bytes, 0, bytes.length, 0);
23
+ if (bytesRead === bytes.length)
24
+ return null;
25
+ const value = JSON.parse(bytes.subarray(0, bytesRead).toString("utf8"));
26
+ return typeof value === "number" && Number.isFinite(value) && value > 0 ? value : null;
27
+ }
28
+ finally {
29
+ await handle.close();
30
+ }
31
+ }
32
+ catch {
33
+ return null;
34
+ }
35
+ }
36
+ /** Separate from shared diagnostic snapshots: only inference dispatches write these files. */
37
+ export async function saveInferenceRequestTime(key, at) {
38
+ if (!validKey(key) || !Number.isFinite(at) || at <= 0)
39
+ return;
40
+ const path = activityPath(key);
41
+ await fs.mkdir(join(getCodexMultiAuthDir(), "inference-activity"), { recursive: true, mode: 0o700 });
42
+ // Read-max-write under the cross-process lock, so a concurrent writer (app
43
+ // router and a wrapper proxy) cannot replace a newer time with an older one.
44
+ await withFileTransactionLock(path, async () => {
45
+ const temp = tempPathFor(path);
46
+ const timestamp = Math.max(at, await readTimestamp(key) ?? 0);
47
+ try {
48
+ await fs.writeFile(temp, JSON.stringify(timestamp) + "\n", { mode: 0o600, flag: "wx" });
49
+ await withRetry(() => fs.rename(temp, path), { maxAttempts: 6, backoffMs: 25 });
50
+ }
51
+ finally {
52
+ await withRetry(() => fs.unlink(temp), { maxAttempts: 6, backoffMs: 25 }).catch(error => { if (error.code !== "ENOENT")
53
+ throw error; });
54
+ }
55
+ });
56
+ }
57
+ /**
58
+ * Per-request dispatches only need the latest time per key on disk. Keep the
59
+ * newest pending time per key and write them together after a short debounce,
60
+ * instead of chaining one mkdir/read/write/rename per request.
61
+ */
62
+ export function createInferenceActivityWriter(save = saveInferenceRequestTime, delayMs = 1000, onError = () => undefined) {
63
+ const pending = new Map();
64
+ let timer;
65
+ let flushing = Promise.resolve();
66
+ const flush = () => {
67
+ if (timer) {
68
+ clearTimeout(timer);
69
+ timer = undefined;
70
+ }
71
+ const batch = [...pending];
72
+ pending.clear();
73
+ flushing = flushing.then(async () => {
74
+ for (const [key, at] of batch)
75
+ await save(key, at).catch(onError);
76
+ });
77
+ return flushing;
78
+ };
79
+ return {
80
+ record(key, at) {
81
+ if (!validKey(key) || !Number.isFinite(at) || at <= 0)
82
+ return;
83
+ pending.set(key, Math.max(pending.get(key) ?? 0, at));
84
+ if (!timer) {
85
+ timer = setTimeout(() => void flush(), delayMs);
86
+ timer.unref?.();
87
+ }
88
+ },
89
+ flush,
90
+ };
91
+ }
92
+ export async function loadInferenceRequestTimes(keys) {
93
+ const entries = await mapWithConcurrency([...new Set(keys)].filter(validKey).slice(0, 1000), 4, async (key) => ({ key, at: await readTimestamp(key) }));
94
+ return Object.fromEntries(entries.flatMap(entry => entry.at === null ? [] : [[entry.key, entry.at]]));
95
+ }
@@ -0,0 +1,100 @@
1
+ import { z } from "zod";
2
+ import { type AccountStorageV3 } from "../storage.js";
3
+ import { type ApiRouteCredential, updateApiModelDiscovery } from "../api-route-store.js";
4
+ declare const schema: z.ZodObject<{
5
+ apiConfigurationUnavailable: z.ZodOptional<z.ZodBoolean>;
6
+ version: z.ZodLiteral<1>;
7
+ checkedAt: z.ZodNumber;
8
+ clientVersion: z.ZodOptional<z.ZodString>;
9
+ entries: z.ZodArray<z.ZodObject<{
10
+ id: z.ZodOptional<z.ZodString>;
11
+ routable: z.ZodOptional<z.ZodBoolean>;
12
+ bound: z.ZodOptional<z.ZodBoolean>;
13
+ selected: z.ZodOptional<z.ZodBoolean>;
14
+ changes: z.ZodOptional<z.ZodObject<{
15
+ observedAt: z.ZodNumber;
16
+ added: z.ZodArray<z.ZodString>;
17
+ removed: z.ZodArray<z.ZodString>;
18
+ capabilities: z.ZodArray<z.ZodString>;
19
+ }, z.core.$strip>>;
20
+ lastSuccessful: z.ZodOptional<z.ZodObject<{
21
+ models: z.ZodArray<z.ZodString>;
22
+ entitlements: z.ZodOptional<z.ZodArray<z.ZodObject<{
23
+ model: z.ZodString;
24
+ checkedAt: z.ZodOptional<z.ZodNumber>;
25
+ probes: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodEnum<{
26
+ unsupported: "unsupported";
27
+ verified: "verified";
28
+ unverified: "unverified";
29
+ downgraded: "downgraded";
30
+ }>>>;
31
+ serviceTiers: z.ZodArray<z.ZodObject<{
32
+ id: z.ZodString;
33
+ name: z.ZodString;
34
+ }, z.core.$strip>>;
35
+ reasoningLevels: z.ZodArray<z.ZodString>;
36
+ accessPrograms: z.ZodArray<z.ZodString>;
37
+ }, z.core.$strip>>>;
38
+ }, z.core.$strip>>;
39
+ label: z.ZodString;
40
+ kind: z.ZodEnum<{
41
+ oauth: "oauth";
42
+ api: "api";
43
+ zdr: "zdr";
44
+ }>;
45
+ enabled: z.ZodBoolean;
46
+ checkedAt: z.ZodNumber;
47
+ error: z.ZodBoolean;
48
+ models: z.ZodArray<z.ZodString>;
49
+ visibleModels: z.ZodArray<z.ZodString>;
50
+ entitlements: z.ZodOptional<z.ZodArray<z.ZodObject<{
51
+ model: z.ZodString;
52
+ checkedAt: z.ZodOptional<z.ZodNumber>;
53
+ probes: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodEnum<{
54
+ unsupported: "unsupported";
55
+ verified: "verified";
56
+ unverified: "unverified";
57
+ downgraded: "downgraded";
58
+ }>>>;
59
+ serviceTiers: z.ZodArray<z.ZodObject<{
60
+ id: z.ZodString;
61
+ name: z.ZodString;
62
+ }, z.core.$strip>>;
63
+ reasoningLevels: z.ZodArray<z.ZodString>;
64
+ accessPrograms: z.ZodArray<z.ZodString>;
65
+ }, z.core.$strip>>>;
66
+ }, z.core.$strip>>;
67
+ }, z.core.$strip>;
68
+ export type ModelInventory = z.infer<typeof schema>;
69
+ export declare function discoverModelInventory(storage: AccountStorageV3 | null, routes: ApiRouteCredential[], options?: {
70
+ fetchImpl?: typeof fetch;
71
+ now?: () => number;
72
+ clientVersion?: string;
73
+ updateApiDiscovery?: typeof updateApiModelDiscovery;
74
+ /** Send billable API probes even when a result is inside the 15-minute cache. */
75
+ forceProbes?: boolean;
76
+ /** Share probe results with later CLI processes through the multi-auth directory. */
77
+ persistProbes?: boolean;
78
+ }): Promise<ModelInventory>;
79
+ export declare function loadModelInventory(): Promise<ModelInventory | null>;
80
+ export declare function saveModelInventory(value: ModelInventory): Promise<void>;
81
+ export declare function formatModelInventory(inventory: ModelInventory | null, now?: number): string[];
82
+ export declare function refreshAndPrintModelInventory(log: (message: string) => void, deps?: {
83
+ getBinding?: () => Promise<{
84
+ running: boolean;
85
+ state: {
86
+ nativeOpenai?: boolean;
87
+ baseUrl: string;
88
+ clientApiKey: string;
89
+ } | null;
90
+ }>;
91
+ fetchImpl?: typeof fetch;
92
+ loadInventory?: typeof loadModelInventory;
93
+ now?: () => number;
94
+ /** Only an explicit `check capabilities` bypasses the 15-minute probe cache. */
95
+ forceProbes?: boolean;
96
+ }): Promise<boolean>;
97
+ /** Compare stable credential/workspace scopes, keeping the last successful baseline through outages. */
98
+ export declare function withInventoryChanges(current: ModelInventory, previous: ModelInventory | null): ModelInventory;
99
+ export {};
100
+ //# sourceMappingURL=model-discovery-status.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"model-discovery-status.d.ts","sourceRoot":"","sources":["../../../lib/runtime/model-discovery-status.ts"],"names":[],"mappings":"AASA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,OAAO,EAAE,KAAK,gBAAgB,EAAgB,MAAM,eAAe,CAAC;AACpE,OAAO,EACN,KAAK,kBAAkB,EAEvB,uBAAuB,EACvB,MAAM,uBAAuB,CAAC;AAgC/B,QAAA,MAAM,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAUV,CAAC;AACH,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,MAAM,CAAC,CAAC;AAkBpD,wBAAsB,sBAAsB,CAC3C,OAAO,EAAE,gBAAgB,GAAG,IAAI,EAChC,MAAM,EAAE,kBAAkB,EAAE,EAC5B,OAAO,GAAE;IACR,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;IACzB,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,kBAAkB,CAAC,EAAE,OAAO,uBAAuB,CAAC;IACpD,iFAAiF;IACjF,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,qFAAqF;IACrF,aAAa,CAAC,EAAE,OAAO,CAAC;CACnB,GACJ,OAAO,CAAC,cAAc,CAAC,CAuGzB;AAID,wBAAsB,kBAAkB,IAAI,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC,CAgBzE;AAED,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAOvE;AA2BD,wBAAgB,oBAAoB,CACnC,SAAS,EAAE,cAAc,GAAG,IAAI,EAChC,GAAG,SAAa,GACd,MAAM,EAAE,CAyBV;AACD,wBAAsB,6BAA6B,CAClD,GAAG,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,EAC9B,IAAI,GAAE;IACL,UAAU,CAAC,EAAE,MAAM,OAAO,CAAC;QAC1B,OAAO,EAAE,OAAO,CAAC;QACjB,KAAK,EAAE;YACN,YAAY,CAAC,EAAE,OAAO,CAAC;YACvB,OAAO,EAAE,MAAM,CAAC;YAChB,YAAY,EAAE,MAAM,CAAC;SACrB,GAAG,IAAI,CAAC;KACT,CAAC,CAAC;IACH,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;IACzB,aAAa,CAAC,EAAE,OAAO,kBAAkB,CAAC;IAC1C,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;IACnB,gFAAgF;IAChF,WAAW,CAAC,EAAE,OAAO,CAAC;CACjB,GACJ,OAAO,CAAC,OAAO,CAAC,CAwElB;AAUD,wGAAwG;AACxG,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,cAAc,EAAE,QAAQ,EAAE,cAAc,GAAG,IAAI,GAAG,cAAc,CAmB7G"}