codex-multi-auth 2.17.0 → 2.17.3

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 (450) hide show
  1. package/.codex-plugin/plugin.json +9 -9
  2. package/LICENSE +21 -21
  3. package/README.md +142 -484
  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 +0 -1
  11. package/dist/lib/account-policy.d.ts +18 -2
  12. package/dist/lib/account-policy.js +97 -40
  13. package/dist/lib/accounts/rate-limits.d.ts +0 -1
  14. package/dist/lib/accounts.d.ts +1 -8
  15. package/dist/lib/accounts.d.ts.map +1 -1
  16. package/dist/lib/accounts.js +7 -19
  17. package/dist/lib/api-route-store.d.ts +0 -1
  18. package/dist/lib/audit.d.ts +0 -1
  19. package/dist/lib/audit.js +43 -12
  20. package/dist/lib/auth/account-access.d.ts +0 -1
  21. package/dist/lib/auth/account-access.js +5 -1
  22. package/dist/lib/auth/auth.d.ts +4 -3
  23. package/dist/lib/auth/auth.js +220 -28
  24. package/dist/lib/auth/browser.d.ts +0 -1
  25. package/dist/lib/auth/callback-guidance.d.ts +0 -1
  26. package/dist/lib/auth/device-auth.d.ts +0 -1
  27. package/dist/lib/auth/index.d.ts +0 -1
  28. package/dist/lib/auth/org-override.d.ts +0 -1
  29. package/dist/lib/auth/server.d.ts +1 -2
  30. package/dist/lib/auth/server.js +100 -53
  31. package/dist/lib/auth/token-utils.d.ts +0 -1
  32. package/dist/lib/auth-rate-limit.d.ts +0 -1
  33. package/dist/lib/budget-guard.d.ts +16 -2
  34. package/dist/lib/budget-guard.js +123 -43
  35. package/dist/lib/capability-policy.d.ts +0 -1
  36. package/dist/lib/circuit-breaker.d.ts +20 -1
  37. package/dist/lib/circuit-breaker.js +24 -5
  38. package/dist/lib/cli.d.ts +0 -1
  39. package/dist/lib/codex-cli/index.d.ts +0 -1
  40. package/dist/lib/codex-cli/observability.d.ts +0 -1
  41. package/dist/lib/codex-cli/state.d.ts +0 -1
  42. package/dist/lib/codex-cli/sync.d.ts +0 -1
  43. package/dist/lib/codex-cli/writer.d.ts +0 -1
  44. package/dist/lib/codex-manager/account-credentials.d.ts +0 -1
  45. package/dist/lib/codex-manager/account-manager-commands.d.ts +0 -1
  46. package/dist/lib/codex-manager/account-pool-write.d.ts +0 -1
  47. package/dist/lib/codex-manager/active-account-sync.d.ts +6 -0
  48. package/dist/lib/codex-manager/active-account-sync.js +336 -0
  49. package/dist/lib/codex-manager/api-login-menu.d.ts +0 -1
  50. package/dist/lib/codex-manager/backend-category-entry.d.ts +0 -1
  51. package/dist/lib/codex-manager/backend-category-helpers.d.ts +0 -1
  52. package/dist/lib/codex-manager/backend-category-prompt.d.ts +0 -1
  53. package/dist/lib/codex-manager/backend-settings-controller.d.ts +0 -1
  54. package/dist/lib/codex-manager/backend-settings-entry.d.ts +0 -1
  55. package/dist/lib/codex-manager/backend-settings-helpers.d.ts +0 -1
  56. package/dist/lib/codex-manager/backend-settings-prompt.d.ts +0 -1
  57. package/dist/lib/codex-manager/backend-settings-schema.d.ts +0 -1
  58. package/dist/lib/codex-manager/behavior-settings-panel.d.ts +0 -1
  59. package/dist/lib/codex-manager/commands/account.d.ts +8 -3
  60. package/dist/lib/codex-manager/commands/account.js +46 -34
  61. package/dist/lib/codex-manager/commands/best.d.ts +0 -1
  62. package/dist/lib/codex-manager/commands/bridge.d.ts +0 -1
  63. package/dist/lib/codex-manager/commands/budget.d.ts +8 -3
  64. package/dist/lib/codex-manager/commands/budget.js +6 -4
  65. package/dist/lib/codex-manager/commands/check.d.ts +0 -1
  66. package/dist/lib/codex-manager/commands/config-explain.d.ts +0 -1
  67. package/dist/lib/codex-manager/commands/debug-bundle.d.ts +0 -1
  68. package/dist/lib/codex-manager/commands/forecast.d.ts +1 -2
  69. package/dist/lib/codex-manager/commands/forecast.d.ts.map +1 -1
  70. package/dist/lib/codex-manager/commands/forecast.js +2 -2
  71. package/dist/lib/codex-manager/commands/history.d.ts +0 -1
  72. package/dist/lib/codex-manager/commands/init-config.d.ts +0 -1
  73. package/dist/lib/codex-manager/commands/integrations.d.ts +0 -1
  74. package/dist/lib/codex-manager/commands/limits.d.ts +0 -1
  75. package/dist/lib/codex-manager/commands/models.d.ts +0 -1
  76. package/dist/lib/codex-manager/commands/monitor.d.ts +0 -1
  77. package/dist/lib/codex-manager/commands/report.d.ts +0 -1
  78. package/dist/lib/codex-manager/commands/resets.d.ts +0 -1
  79. package/dist/lib/codex-manager/commands/resets.js +9 -1
  80. package/dist/lib/codex-manager/commands/rotation.d.ts +0 -1
  81. package/dist/lib/codex-manager/commands/status.d.ts +0 -1
  82. package/dist/lib/codex-manager/commands/switch.d.ts +0 -1
  83. package/dist/lib/codex-manager/commands/uninstall.d.ts +0 -1
  84. package/dist/lib/codex-manager/commands/unpin.d.ts +0 -1
  85. package/dist/lib/codex-manager/commands/usage.d.ts +0 -1
  86. package/dist/lib/codex-manager/commands/verify.d.ts +0 -1
  87. package/dist/lib/codex-manager/commands/why-selected.d.ts +0 -1
  88. package/dist/lib/codex-manager/commands/workspace.d.ts +0 -1
  89. package/dist/lib/codex-manager/dashboard-display-panel.d.ts +0 -1
  90. package/dist/lib/codex-manager/dashboard-formatters.d.ts +0 -1
  91. package/dist/lib/codex-manager/dashboard-settings-controller.d.ts +0 -1
  92. package/dist/lib/codex-manager/dashboard-settings-data.d.ts +0 -1
  93. package/dist/lib/codex-manager/dashboard-settings-entry.d.ts +0 -1
  94. package/dist/lib/codex-manager/experimental-settings-entry.d.ts +0 -1
  95. package/dist/lib/codex-manager/experimental-settings-prompt.d.ts +0 -1
  96. package/dist/lib/codex-manager/experimental-settings-schema.d.ts +0 -1
  97. package/dist/lib/codex-manager/experimental-sync-target-entry.d.ts +0 -1
  98. package/dist/lib/codex-manager/experimental-sync-target.d.ts +0 -1
  99. package/dist/lib/codex-manager/forecast-report-shared.d.ts +0 -1
  100. package/dist/lib/codex-manager/formatters/account-formatters.d.ts +0 -1
  101. package/dist/lib/codex-manager/formatters/index.d.ts +0 -1
  102. package/dist/lib/codex-manager/formatters/model-formatters.d.ts +0 -1
  103. package/dist/lib/codex-manager/formatters/quota-formatters.d.ts +0 -1
  104. package/dist/lib/codex-manager/formatters/text-style.d.ts +0 -1
  105. package/dist/lib/codex-manager/health-check.d.ts +0 -1
  106. package/dist/lib/codex-manager/health-check.js +1 -1
  107. package/dist/lib/codex-manager/help.d.ts +0 -1
  108. package/dist/lib/codex-manager/login-action-panel.d.ts +0 -1
  109. package/dist/lib/codex-manager/login-flow.d.ts +0 -1
  110. package/dist/lib/codex-manager/login-menu-actions.d.ts +0 -1
  111. package/dist/lib/codex-manager/login-menu-data.d.ts +0 -1
  112. package/dist/lib/codex-manager/login-menu-data.d.ts.map +1 -1
  113. package/dist/lib/codex-manager/login-menu-data.js +7 -3
  114. package/dist/lib/codex-manager/login-oauth.d.ts +0 -1
  115. package/dist/lib/codex-manager/login-workspace-choice.d.ts +0 -1
  116. package/dist/lib/codex-manager/manual-callback.d.ts +0 -1
  117. package/dist/lib/codex-manager/persist-selected-account.d.ts +0 -1
  118. package/dist/lib/codex-manager/quota-cache-helpers.d.ts +7 -2
  119. package/dist/lib/codex-manager/quota-cache-helpers.d.ts.map +1 -1
  120. package/dist/lib/codex-manager/quota-cache-helpers.js +34 -19
  121. package/dist/lib/codex-manager/rate-limit-markers.d.ts +0 -1
  122. package/dist/lib/codex-manager/repair-commands.d.ts +0 -1
  123. package/dist/lib/codex-manager/repair-commands.js +1 -1
  124. package/dist/lib/codex-manager/settings-hub/backend.d.ts +0 -1
  125. package/dist/lib/codex-manager/settings-hub/dashboard.d.ts +0 -1
  126. package/dist/lib/codex-manager/settings-hub/experimental.d.ts +0 -1
  127. package/dist/lib/codex-manager/settings-hub/index.d.ts +0 -1
  128. package/dist/lib/codex-manager/settings-hub/shared.d.ts +0 -1
  129. package/dist/lib/codex-manager/settings-hub-entry.d.ts +0 -1
  130. package/dist/lib/codex-manager/settings-hub-menu.d.ts +0 -1
  131. package/dist/lib/codex-manager/settings-hub-prompt.d.ts +0 -1
  132. package/dist/lib/codex-manager/settings-hub.d.ts +0 -1
  133. package/dist/lib/codex-manager/settings-panels.d.ts +0 -1
  134. package/dist/lib/codex-manager/settings-persist-utils.d.ts +0 -1
  135. package/dist/lib/codex-manager/settings-preview.d.ts +0 -1
  136. package/dist/lib/codex-manager/settings-write-queue.d.ts +0 -1
  137. package/dist/lib/codex-manager/statusline-settings-panel.d.ts +0 -1
  138. package/dist/lib/codex-manager/theme-settings-panel.d.ts +0 -1
  139. package/dist/lib/codex-manager/unified-settings-controller.d.ts +0 -1
  140. package/dist/lib/codex-manager/unified-settings-entry.d.ts +0 -1
  141. package/dist/lib/codex-manager.d.ts +1 -2
  142. package/dist/lib/codex-manager.js +5 -95
  143. package/dist/lib/concurrency.d.ts +0 -1
  144. package/dist/lib/config-schema.d.ts +0 -1
  145. package/dist/lib/config.d.ts +0 -1
  146. package/dist/lib/config.js +46 -241
  147. package/dist/lib/constants.d.ts +0 -1
  148. package/dist/lib/context-budget/model-context-windows.d.ts +0 -1
  149. package/dist/lib/context-budget-guard.d.ts +0 -1
  150. package/dist/lib/context-budget-response.d.ts +0 -1
  151. package/dist/lib/context-budget-response.js +8 -8
  152. package/dist/lib/context-overflow.d.ts +0 -1
  153. package/dist/lib/context-overflow.js +10 -10
  154. package/dist/lib/dashboard-settings.d.ts +0 -1
  155. package/dist/lib/entitlement-cache.d.ts +0 -1
  156. package/dist/lib/env-parsing.d.ts +13 -1
  157. package/dist/lib/env-parsing.js +21 -0
  158. package/dist/lib/errors.d.ts +0 -1
  159. package/dist/lib/forecast.d.ts +0 -1
  160. package/dist/lib/fs-retry.d.ts +0 -1
  161. package/dist/lib/health.d.ts +0 -1
  162. package/dist/lib/index.d.ts +0 -1
  163. package/dist/lib/integration-generators.d.ts +0 -1
  164. package/dist/lib/live-account-sync.d.ts +0 -1
  165. package/dist/lib/local-bridge.d.ts +0 -1
  166. package/dist/lib/local-bridge.js +4 -1
  167. package/dist/lib/local-client-tokens.d.ts +0 -1
  168. package/dist/lib/local-client-tokens.js +125 -30
  169. package/dist/lib/logger.d.ts +0 -1
  170. package/dist/lib/logger.js +11 -1
  171. package/dist/lib/model-capability-matrix.d.ts +0 -1
  172. package/dist/lib/model-route-policy.d.ts +1 -2
  173. package/dist/lib/named-backup-export.d.ts +0 -1
  174. package/dist/lib/oauth-success.html +125 -125
  175. package/dist/lib/oc-chatgpt-import-adapter.d.ts +0 -1
  176. package/dist/lib/oc-chatgpt-orchestrator.d.ts +0 -1
  177. package/dist/lib/oc-chatgpt-target-detection.d.ts +0 -1
  178. package/dist/lib/parallel-probe.d.ts +0 -1
  179. package/dist/lib/policy/runtime-policy-cache.d.ts +80 -0
  180. package/dist/lib/policy/runtime-policy-cache.js +310 -0
  181. package/dist/lib/policy/runtime-policy.d.ts +1 -2
  182. package/dist/lib/policy/runtime-policy.js +46 -19
  183. package/dist/lib/preemptive-quota-scheduler.d.ts +0 -1
  184. package/dist/lib/proactive-refresh.d.ts +0 -1
  185. package/dist/lib/prompts/codex-host-bridge.d.ts +0 -1
  186. package/dist/lib/prompts/codex-host-bridge.js +138 -138
  187. package/dist/lib/prompts/codex.d.ts +0 -1
  188. package/dist/lib/prompts/codex.js +79 -79
  189. package/dist/lib/prompts/fetch-utils.d.ts +0 -1
  190. package/dist/lib/prompts/host-codex-prompt.d.ts +0 -1
  191. package/dist/lib/quota-cache.d.ts +7 -4
  192. package/dist/lib/quota-cache.d.ts.map +1 -1
  193. package/dist/lib/quota-cache.js +117 -61
  194. package/dist/lib/quota-probe.d.ts +0 -1
  195. package/dist/lib/quota-probe.js +5 -2
  196. package/dist/lib/quota-readiness.d.ts +7 -3
  197. package/dist/lib/quota-readiness.d.ts.map +1 -1
  198. package/dist/lib/quota-readiness.js +25 -4
  199. package/dist/lib/recovery/constants.d.ts +0 -1
  200. package/dist/lib/recovery/storage.d.ts +0 -1
  201. package/dist/lib/recovery/types.d.ts +0 -1
  202. package/dist/lib/recovery.d.ts +0 -1
  203. package/dist/lib/redaction.d.ts +0 -1
  204. package/dist/lib/refresh-guardian.d.ts +0 -1
  205. package/dist/lib/refresh-lease.d.ts +0 -1
  206. package/dist/lib/refresh-queue.d.ts +0 -1
  207. package/dist/lib/request/client-cancellation.d.ts +0 -1
  208. package/dist/lib/request/error-classification.d.ts +0 -1
  209. package/dist/lib/request/failover-config.d.ts +0 -1
  210. package/dist/lib/request/failure-policy.d.ts +0 -1
  211. package/dist/lib/request/fetch-helpers.d.ts +0 -1
  212. package/dist/lib/request/headers.d.ts +0 -1
  213. package/dist/lib/request/helpers/input-utils.d.ts +0 -1
  214. package/dist/lib/request/helpers/input-utils.js +88 -34
  215. package/dist/lib/request/helpers/model-map.d.ts +0 -1
  216. package/dist/lib/request/helpers/tool-utils.d.ts +0 -1
  217. package/dist/lib/request/helpers/tool-utils.js +421 -4
  218. package/dist/lib/request/index.d.ts +0 -1
  219. package/dist/lib/request/rate-limit-backoff.d.ts +0 -1
  220. package/dist/lib/request/rate-limit-decision.d.ts +0 -1
  221. package/dist/lib/request/request-attempt-budget.d.ts +0 -1
  222. package/dist/lib/request/request-init.d.ts +0 -1
  223. package/dist/lib/request/request-resilience.d.ts +0 -1
  224. package/dist/lib/request/request-transformer.d.ts +0 -1
  225. package/dist/lib/request/request-transformer.js +50 -25
  226. package/dist/lib/request/response-compaction.d.ts +0 -1
  227. package/dist/lib/request/response-handler.d.ts +0 -1
  228. package/dist/lib/request/response-metadata.d.ts +0 -1
  229. package/dist/lib/request/response-outcome.d.ts +0 -1
  230. package/dist/lib/request/stream-failover-runtime.d.ts +0 -1
  231. package/dist/lib/request/stream-failover.d.ts +0 -1
  232. package/dist/lib/request/stream-failover.js +28 -4
  233. package/dist/lib/request/token-refresh.d.ts +0 -1
  234. package/dist/lib/request/url-rewriting.d.ts +0 -1
  235. package/dist/lib/request/wait-utils.d.ts +0 -1
  236. package/dist/lib/rotation.d.ts +0 -1
  237. package/dist/lib/routing-mutex.d.ts +0 -1
  238. package/dist/lib/routing-profiles.d.ts +16 -2
  239. package/dist/lib/routing-profiles.js +119 -44
  240. package/dist/lib/runtime/account-check-helpers.d.ts +0 -1
  241. package/dist/lib/runtime/account-check-types.d.ts +0 -1
  242. package/dist/lib/runtime/account-check.d.ts +0 -1
  243. package/dist/lib/runtime/account-manager-cache-entry.d.ts +0 -1
  244. package/dist/lib/runtime/account-manager-cache.d.ts +0 -1
  245. package/dist/lib/runtime/account-model-catalog.d.ts +1 -2
  246. package/dist/lib/runtime/account-pool.d.ts +0 -1
  247. package/dist/lib/runtime/account-reset-credits.d.ts +0 -1
  248. package/dist/lib/runtime/account-reset-credits.js +8 -2
  249. package/dist/lib/runtime/account-scope.d.ts +0 -1
  250. package/dist/lib/runtime/account-select-event.d.ts +0 -1
  251. package/dist/lib/runtime/account-selection.d.ts +0 -1
  252. package/dist/lib/runtime/account-state.d.ts +0 -1
  253. package/dist/lib/runtime/account-status.d.ts +0 -1
  254. package/dist/lib/runtime/account-storage-scope-entry.d.ts +0 -1
  255. package/dist/lib/runtime/api-model-capabilities.d.ts +0 -1
  256. package/dist/lib/runtime/api-model-runtime.d.ts +0 -1
  257. package/dist/lib/runtime/app-bind.d.ts +0 -1
  258. package/dist/lib/runtime/app-bind.d.ts.map +1 -1
  259. package/dist/lib/runtime/app-bind.js +10 -2
  260. package/dist/lib/runtime/app-helper-selection.d.ts +0 -1
  261. package/dist/lib/runtime/auth-facade.d.ts +0 -1
  262. package/dist/lib/runtime/automatic-account-checks.d.ts +5 -2
  263. package/dist/lib/runtime/automatic-account-checks.d.ts.map +1 -1
  264. package/dist/lib/runtime/automatic-account-checks.js +29 -2
  265. package/dist/lib/runtime/automatic-subscription-checks.d.ts +1 -2
  266. package/dist/lib/runtime/automatic-subscription-checks.d.ts.map +1 -1
  267. package/dist/lib/runtime/automatic-subscription-checks.js +13 -16
  268. package/dist/lib/runtime/browser-oauth-flow.d.ts +0 -1
  269. package/dist/lib/runtime/capability-boost.d.ts +0 -1
  270. package/dist/lib/runtime/catalog-capabilities.d.ts +0 -1
  271. package/dist/lib/runtime/config-toml.d.ts +0 -1
  272. package/dist/lib/runtime/context-budget-settings.d.ts +0 -1
  273. package/dist/lib/runtime/event-handler.d.ts +0 -1
  274. package/dist/lib/runtime/first-run.d.ts +0 -1
  275. package/dist/lib/runtime/flagged-verify-types.d.ts +0 -1
  276. package/dist/lib/runtime/hydrate-emails.d.ts +0 -1
  277. package/dist/lib/runtime/inference-activity.d.ts +0 -1
  278. package/dist/lib/runtime/live-sync-entry.d.ts +0 -1
  279. package/dist/lib/runtime/live-sync.d.ts +0 -1
  280. package/dist/lib/runtime/loader-setup.d.ts +0 -1
  281. package/dist/lib/runtime/login-menu-accounts.d.ts +0 -1
  282. package/dist/lib/runtime/manual-oauth-flow.d.ts +0 -1
  283. package/dist/lib/runtime/model-discovery-status.d.ts +2 -3
  284. package/dist/lib/runtime/native-account-storage.d.ts +0 -1
  285. package/dist/lib/runtime/native-account-sync.d.ts +0 -1
  286. package/dist/lib/runtime/native-binding-lock.d.ts +0 -1
  287. package/dist/lib/runtime/native-client-auth.d.ts +0 -1
  288. package/dist/lib/runtime/native-provider-config.d.ts +0 -1
  289. package/dist/lib/runtime/native-rate-limits.d.ts +2 -1
  290. package/dist/lib/runtime/native-rate-limits.js +23 -6
  291. package/dist/lib/runtime/preemptive-quota.d.ts +0 -1
  292. package/dist/lib/runtime/quota-headers.d.ts +0 -1
  293. package/dist/lib/runtime/quota-probe.d.ts +0 -1
  294. package/dist/lib/runtime/quota-settings.d.ts +0 -1
  295. package/dist/lib/runtime/refresh-guardian-entry.d.ts +0 -1
  296. package/dist/lib/runtime/refresh-guardian.d.ts +0 -1
  297. package/dist/lib/runtime/request-init.d.ts +0 -1
  298. package/dist/lib/runtime/reset-credit-routing.d.ts +0 -1
  299. package/dist/lib/runtime/reset-credits.d.ts +0 -1
  300. package/dist/lib/runtime/response-output-history.d.ts +0 -1
  301. package/dist/lib/runtime/responses-websocket.d.ts +0 -1
  302. package/dist/lib/runtime/resume-picker.d.ts +0 -1
  303. package/dist/lib/runtime/rotation-account-selection.d.ts +0 -1
  304. package/dist/lib/runtime/rotation-proxy-state.d.ts +0 -1
  305. package/dist/lib/runtime/rotation-server-types.d.ts +0 -1
  306. package/dist/lib/runtime/rotation-storage-meta.d.ts +0 -1
  307. package/dist/lib/runtime/rotation-token-refresh.d.ts +0 -1
  308. package/dist/lib/runtime/runtime-capability-failures.d.ts +0 -1
  309. package/dist/lib/runtime/runtime-current-account.d.ts +0 -1
  310. package/dist/lib/runtime/runtime-observability.d.ts +0 -1
  311. package/dist/lib/runtime/runtime-services.d.ts +0 -1
  312. package/dist/lib/runtime/session-affinity-entry.d.ts +0 -1
  313. package/dist/lib/runtime/session-recovery.d.ts +0 -1
  314. package/dist/lib/runtime/status-marker.d.ts +0 -1
  315. package/dist/lib/runtime/storage-scope.d.ts +0 -1
  316. package/dist/lib/runtime/subscription-first-use.d.ts +0 -1
  317. package/dist/lib/runtime/subscription-quota-event.d.ts +0 -1
  318. package/dist/lib/runtime/subscription-quota-order.d.ts +0 -1
  319. package/dist/lib/runtime/toast.d.ts +0 -1
  320. package/dist/lib/runtime/ui-runtime-entry.d.ts +0 -1
  321. package/dist/lib/runtime/ui-runtime.d.ts +0 -1
  322. package/dist/lib/runtime/verify-flagged.d.ts +0 -1
  323. package/dist/lib/runtime/workspace-model-scopes.d.ts +0 -1
  324. package/dist/lib/runtime-constants.d.ts +0 -1
  325. package/dist/lib/runtime-paths.d.ts +0 -1
  326. package/dist/lib/runtime-rotation-proxy.d.ts +1 -1
  327. package/dist/lib/runtime-rotation-proxy.js +136 -3
  328. package/dist/lib/schemas.d.ts +35 -13
  329. package/dist/lib/schemas.js +19 -2
  330. package/dist/lib/session-affinity.d.ts +0 -1
  331. package/dist/lib/shutdown.d.ts +0 -1
  332. package/dist/lib/storage/account-clear-entry.d.ts +0 -1
  333. package/dist/lib/storage/account-clear.d.ts +0 -1
  334. package/dist/lib/storage/account-match-utils.d.ts +0 -1
  335. package/dist/lib/storage/account-persistence.d.ts +0 -1
  336. package/dist/lib/storage/account-port.d.ts +0 -1
  337. package/dist/lib/storage/account-save-entry.d.ts +0 -1
  338. package/dist/lib/storage/account-save.d.ts +9 -2
  339. package/dist/lib/storage/account-save.js +4 -1
  340. package/dist/lib/storage/account-snapshot.d.ts +0 -1
  341. package/dist/lib/storage/backup-metadata-builder.d.ts +0 -1
  342. package/dist/lib/storage/backup-metadata.d.ts +0 -1
  343. package/dist/lib/storage/backup-paths.d.ts +0 -1
  344. package/dist/lib/storage/backup-restore.d.ts +0 -1
  345. package/dist/lib/storage/cache-artifacts.d.ts +0 -1
  346. package/dist/lib/storage/credential-sidecars.d.ts +0 -1
  347. package/dist/lib/storage/error-hints.d.ts +0 -1
  348. package/dist/lib/storage/file-lock.d.ts +0 -1
  349. package/dist/lib/storage/file-lock.js +33 -1
  350. package/dist/lib/storage/file-paths.d.ts +0 -1
  351. package/dist/lib/storage/fixture-guards.d.ts +0 -1
  352. package/dist/lib/storage/flagged-entry.d.ts +0 -1
  353. package/dist/lib/storage/flagged-load-entry.d.ts +0 -1
  354. package/dist/lib/storage/flagged-save-entry.d.ts +0 -1
  355. package/dist/lib/storage/flagged-storage-file.d.ts +0 -1
  356. package/dist/lib/storage/flagged-storage-io.d.ts +0 -1
  357. package/dist/lib/storage/flagged-storage.d.ts +0 -1
  358. package/dist/lib/storage/gitignore.d.ts +0 -1
  359. package/dist/lib/storage/hash.d.ts +0 -1
  360. package/dist/lib/storage/health.d.ts +0 -1
  361. package/dist/lib/storage/identity.d.ts +0 -1
  362. package/dist/lib/storage/import-export.d.ts +0 -1
  363. package/dist/lib/storage/json-store-lock.d.ts +105 -0
  364. package/dist/lib/storage/json-store-lock.js +259 -0
  365. package/dist/lib/storage/metadata-section.d.ts +0 -1
  366. package/dist/lib/storage/migrations.d.ts +0 -1
  367. package/dist/lib/storage/migrations.js +31 -18
  368. package/dist/lib/storage/named-backup-entry.d.ts +0 -1
  369. package/dist/lib/storage/named-backups-entry.d.ts +0 -1
  370. package/dist/lib/storage/named-backups.d.ts +0 -1
  371. package/dist/lib/storage/path-state.d.ts +0 -1
  372. package/dist/lib/storage/paths.d.ts +0 -1
  373. package/dist/lib/storage/pending-auth.d.ts +10 -3
  374. package/dist/lib/storage/pending-auth.d.ts.map +1 -1
  375. package/dist/lib/storage/pending-auth.js +33 -9
  376. package/dist/lib/storage/project-migration.d.ts +0 -1
  377. package/dist/lib/storage/public-types.d.ts +0 -1
  378. package/dist/lib/storage/record-identity.d.ts +15 -0
  379. package/dist/lib/storage/record-identity.d.ts.map +1 -0
  380. package/dist/lib/storage/record-identity.js +16 -0
  381. package/dist/lib/storage/record-utils.d.ts +0 -1
  382. package/dist/lib/storage/restore-assessment.d.ts +0 -1
  383. package/dist/lib/storage/restore-backup-entry.d.ts +0 -1
  384. package/dist/lib/storage/restore-metadata.d.ts +0 -1
  385. package/dist/lib/storage/save-retry.d.ts +0 -1
  386. package/dist/lib/storage/snapshot-inspectors.d.ts +0 -1
  387. package/dist/lib/storage/snapshot-merge.d.ts +0 -1
  388. package/dist/lib/storage/storage-parser.d.ts +2 -1
  389. package/dist/lib/storage/storage-parser.js +10 -2
  390. package/dist/lib/storage/transactions.d.ts +0 -1
  391. package/dist/lib/storage.d.ts +15 -2
  392. package/dist/lib/storage.js +612 -25
  393. package/dist/lib/synthetic-response.d.ts +0 -1
  394. package/dist/lib/table-formatter.d.ts +0 -1
  395. package/dist/lib/temp-path.d.ts +0 -1
  396. package/dist/lib/tools/hashline-tools.d.ts +0 -1
  397. package/dist/lib/types.d.ts +0 -1
  398. package/dist/lib/ui/ansi.d.ts +0 -1
  399. package/dist/lib/ui/auth-menu-builder.d.ts +0 -1
  400. package/dist/lib/ui/auth-menu.d.ts +0 -1
  401. package/dist/lib/ui/check-progress.d.ts +0 -1
  402. package/dist/lib/ui/confirm.d.ts +0 -1
  403. package/dist/lib/ui/display-width.d.ts +0 -1
  404. package/dist/lib/ui/format.d.ts +0 -1
  405. package/dist/lib/ui/index.d.ts +0 -1
  406. package/dist/lib/ui/runtime.d.ts +0 -1
  407. package/dist/lib/ui/select.d.ts +0 -1
  408. package/dist/lib/ui/theme.d.ts +0 -1
  409. package/dist/lib/ui/ui-copy.d.ts +0 -1
  410. package/dist/lib/unified-settings.d.ts +13 -11
  411. package/dist/lib/unified-settings.js +22 -14
  412. package/dist/lib/update-notice.d.ts +0 -1
  413. package/dist/lib/usage/index.d.ts +0 -1
  414. package/dist/lib/usage/ledger.d.ts +0 -1
  415. package/dist/lib/usage/pricing.d.ts +0 -1
  416. package/dist/lib/usage/redaction.d.ts +0 -1
  417. package/dist/lib/usage/stream-usage-deferral.d.ts +0 -1
  418. package/dist/lib/usage/types.d.ts +0 -1
  419. package/dist/lib/usage/usage-extraction.d.ts +0 -1
  420. package/dist/lib/utils.d.ts +21 -1
  421. package/dist/lib/utils.js +31 -0
  422. package/dist/lib/wsl.d.ts +0 -1
  423. package/node_modules/@codex-ai/plugin/dist/index.d.ts +2 -2
  424. package/node_modules/@codex-ai/plugin/dist/index.js +2 -2
  425. package/node_modules/@codex-ai/plugin/dist/tool.d.ts +42 -42
  426. package/node_modules/@codex-ai/plugin/dist/tool.js +29 -29
  427. package/node_modules/@codex-ai/plugin/package.json +9 -9
  428. package/node_modules/@codex-ai/sdk/dist/index.d.ts +4 -4
  429. package/node_modules/@codex-ai/sdk/dist/index.js +2 -2
  430. package/node_modules/@codex-ai/sdk/package.json +8 -8
  431. package/package.json +206 -200
  432. package/scripts/codex-app-launcher.js +653 -653
  433. package/scripts/codex-app-router.js +373 -373
  434. package/scripts/codex-bin-resolver.js +332 -313
  435. package/scripts/codex-multi-auth.js +65 -59
  436. package/scripts/codex-routing.js +62 -62
  437. package/scripts/codex.js +6923 -6642
  438. package/scripts/install-codex-auth-utils.js +213 -213
  439. package/scripts/mcodex.js +367 -367
  440. package/scripts/postinstall.js +114 -114
  441. package/scripts/preuninstall.js +265 -265
  442. package/skills/codex-auth-setup/SKILL.md +73 -0
  443. package/vendor/codex-ai-plugin/dist/index.d.ts +2 -2
  444. package/vendor/codex-ai-plugin/dist/index.js +2 -2
  445. package/vendor/codex-ai-plugin/dist/tool.d.ts +42 -42
  446. package/vendor/codex-ai-plugin/dist/tool.js +29 -29
  447. package/vendor/codex-ai-plugin/package.json +9 -9
  448. package/vendor/codex-ai-sdk/dist/index.d.ts +4 -4
  449. package/vendor/codex-ai-sdk/dist/index.js +2 -2
  450. package/vendor/codex-ai-sdk/package.json +8 -8
@@ -4,4 +4,3 @@ export declare function ensureCodexGitignoreEntry(params: {
4
4
  logDebug: (message: string, details: Record<string, unknown>) => void;
5
5
  logWarn: (message: string, details: Record<string, unknown>) => void;
6
6
  }): Promise<void>;
7
- //# sourceMappingURL=gitignore.d.ts.map
@@ -1,2 +1 @@
1
1
  export declare function computeSha256(value: string): string;
2
- //# sourceMappingURL=hash.d.ts.map
@@ -19,4 +19,3 @@ export declare function createStorageHealthSummary(params: {
19
19
  schemaErrors?: string[];
20
20
  recoverySource?: "wal";
21
21
  }): StorageHealthSummary;
22
- //# sourceMappingURL=health.d.ts.map
@@ -18,4 +18,3 @@ export declare function toAccountIdentityRef(account: Pick<AccountLike, "account
18
18
  export declare function getAccountIdentityKey(account: Pick<AccountLike, "accountId" | "email" | "refreshToken">): string | undefined;
19
19
  export declare function getRuntimeAccountIdentityKey(account: Pick<RuntimeAccountLike, "accountId" | "email" | "index">): string | number | undefined;
20
20
  export {};
21
- //# sourceMappingURL=identity.d.ts.map
@@ -22,4 +22,3 @@ export declare function mergeImportedAccounts(params: {
22
22
  total: number;
23
23
  skipped: number;
24
24
  };
25
- //# sourceMappingURL=import-export.d.ts.map
@@ -0,0 +1,105 @@
1
+ /**
2
+ * Stamp `updatedAt` for a per-key governance entry with a hybrid logical
3
+ * floor: when the wall clock regressed below the timestamp the entry being
4
+ * overwritten already carries, stamp `prior + 1` instead of `now`. Every
5
+ * upsert-only store merges with `updatedAt >=`, so a backward clock jump
6
+ * would otherwise stamp a semantically-newer write below its own
7
+ * predecessor and the merge would silently drop it. Equal or forward wall
8
+ * times pass through unchanged — ties already resolve to the caller's
9
+ * write under `>=`.
10
+ *
11
+ * `prior` is the entry the writer saw, which can trail the freshest on-disk
12
+ * entry when a concurrent writer lands between the caller's load and its
13
+ * save; baseline-aware save merges re-apply this same floor against the
14
+ * on-disk entry at merge time so the edit still cannot be lost.
15
+ */
16
+ export declare function stampUpdatedAt(now: number, prior: number | undefined): number;
17
+ /**
18
+ * Serialize `task` behind the previous write queued for `path`, so same-file
19
+ * writers inside this process run one at a time in submission order. A failed
20
+ * predecessor never blocks or fails successors. Re-entrant for the same path
21
+ * within one async context.
22
+ *
23
+ * This is the per-path generalization of the module-local `writeQueue`
24
+ * variables the governance stores used to keep by hand.
25
+ */
26
+ export declare function withJsonStoreWriteQueue<T>(path: string, task: () => Promise<T>): Promise<T>;
27
+ /** Test helper: drop queued-write bookkeeping (all paths, or one when given). */
28
+ export declare function resetJsonStoreWriteQueuesForTests(path?: string): void;
29
+ /**
30
+ * Stat `filePath` for its mtime with bounded transient-FS retry (the save
31
+ * path is Windows-sensitive: a single transient EBUSY/EPERM/EAGAIN from an
32
+ * AV/indexer lock must not abort the whole save). ENOENT returns `null`
33
+ * immediately; on exhaustion the last failure surfaces so the caller treats
34
+ * it as a real save error rather than a phantom missing file.
35
+ */
36
+ export declare function getJsonStoreFileMtimeMs(filePath: string): Promise<number | null>;
37
+ /**
38
+ * The `ESTALE` signal used by the CAS retry loop: the file's mtime moved
39
+ * between the caller's stat and its write, so the attempt must re-read and
40
+ * re-merge against the latest on-disk state instead of clobbering it.
41
+ */
42
+ export declare function createJsonStoreStaleError(filePath: string): NodeJS.ErrnoException;
43
+ /**
44
+ * Throw `ESTALE` when `filePath`'s current mtime differs from
45
+ * `expectedMtimeMs` (`null` means "file must still be absent"). Writers that
46
+ * keep their own temp+rename flow call this just before the rename, matching
47
+ * {@link writeJsonStoreFileAtomicWithRetry}'s inline check.
48
+ */
49
+ export declare function assertJsonStoreFileMtimeUnchanged(filePath: string, expectedMtimeMs: number | null): Promise<void>;
50
+ export interface JsonStoreAtomicWriteOptions {
51
+ /**
52
+ * When present (including explicit `null` = "expect the file to be
53
+ * absent"), compare-and-swap guard: abort with `ESTALE` if the target's
54
+ * mtime moved since the caller read it, so the caller can re-read and
55
+ * merge instead of clobbering a concurrent write. Omit the key entirely
56
+ * to skip the check.
57
+ */
58
+ expectedMtimeMs?: number | null;
59
+ /** Temp file mode (and therefore the final file's mode when created). */
60
+ mode?: number;
61
+ /** fsync the temp file before rename so a crash/power-loss cannot leave a truncated store. */
62
+ fsync?: boolean;
63
+ /** Rename retry codes; defaults to EBUSY/EPERM. */
64
+ retryableCodes?: ReadonlySet<string>;
65
+ }
66
+ /**
67
+ * Atomic JSON write: serialize `payload` pretty-printed with a trailing
68
+ * newline to a crypto-random sibling temp file, then rename it over
69
+ * `filePath` with bounded transient-FS retry. Optionally CAS-checks the
70
+ * target mtime first and fsyncs the temp file; on failure the temp is
71
+ * removed best-effort.
72
+ */
73
+ export declare function writeJsonStoreFileAtomicWithRetry(filePath: string, payload: unknown, options?: JsonStoreAtomicWriteOptions): Promise<void>;
74
+ /**
75
+ * Run `task`, retrying `ESTALE` CAS aborts so each attempt can re-read and
76
+ * re-merge against the latest on-disk state (matches the config save loop:
77
+ * 3 attempts, immediate retry, ESTALE-only).
78
+ */
79
+ export declare function withJsonStoreCasRetry<T>(task: () => Promise<T>): Promise<T>;
80
+ export interface JsonStoreFileLockOptions {
81
+ /**
82
+ * How long to wait for a lock held by a LIVE foreign process before
83
+ * failing with `ELOCKTIMEOUT` (default 10s). A crashed holder's lock is
84
+ * reclaimed as soon as its dead PID is observed; a live holder is never
85
+ * evicted — including a reused PID, which fails closed here rather than
86
+ * risking two writers in the critical section.
87
+ */
88
+ waitTimeoutMs?: number;
89
+ }
90
+ /**
91
+ * Cross-process mutex for a JSON store file, delegated to the proven
92
+ * candidate-directory transaction lock in lib/storage/file-lock.ts: each
93
+ * acquirer stages `<path>.write-lock.candidate-*` containing its unique
94
+ * `<host>.<pid>.<uuid>` owner file, then publishes it with a single atomic
95
+ * `rename` (which only succeeds while the lock directory is absent or empty,
96
+ * so there is no ownerless acquisition window). A crashed holder's lock is
97
+ * recovered by unlinking exactly that dead owner's unique filename and
98
+ * removing the directory only while it is still empty — an `rmdir` can never
99
+ * erase a lock that was republished in the meantime, so takeover can never
100
+ * delete another owner's live lock. Waiters on a live holder retry inside
101
+ * `waitTimeoutMs` (default 10s), then this wrapper surfaces the exhaustion
102
+ * as `ELOCKTIMEOUT`. Re-entrant for the same resolved path within one async
103
+ * context.
104
+ */
105
+ export declare function withJsonStoreFileLock<T>(targetPath: string, task: () => Promise<T>, options?: JsonStoreFileLockOptions): Promise<T>;
@@ -0,0 +1,259 @@
1
+ import { AsyncLocalStorage } from "node:async_hooks";
2
+ import { promises as fs } from "node:fs";
3
+ import { dirname } from "node:path";
4
+ import { withRetry } from "../fs-retry.js";
5
+ import { tempPathFor } from "../temp-path.js";
6
+ import { withFileTransactionLock } from "./file-lock.js";
7
+ /**
8
+ * Shared concurrency machinery for the file-backed governance JSON stores
9
+ * (config, unified settings, budget guards, routing profiles, account
10
+ * policies, local client tokens, quota cache).
11
+ *
12
+ * Three cooperating guards, extracted from lib/config.ts's save path so every
13
+ * store gets the same semantics instead of each re-deriving a subset:
14
+ *
15
+ * 1. {@link withJsonStoreWriteQueue} — a per-path in-process promise queue
16
+ * that serializes writers inside this process (replaces each store's
17
+ * hand-rolled `writeQueue` module variable).
18
+ * 2. {@link withJsonStoreFileLock} — a cross-process lock directory
19
+ * (`<path>.write-lock`) delegated to {@link withFileTransactionLock}: a
20
+ * pre-populated candidate directory is published by atomic rename, and a
21
+ * crashed holder's lock is recovered only when its owner PID is dead —
22
+ * live holders are NEVER evicted, so a takeover can never unlink a newly
23
+ * acquired lock (the stale-check→unlink TOCTOU that a single lockfile
24
+ * cannot close: POSIX has no delete-if-unchanged primitive, and renaming
25
+ * the file aside leaves an empty path another `wx` create can claim).
26
+ * The promise queue only serializes THIS process; the lock directory
27
+ * closes the read→check→merge→rename TOCTOU window against OTHER
28
+ * processes. Re-entrant within one async context so a nested write on the
29
+ * same path cannot deadlock itself.
30
+ * 3. mtime compare-and-swap — {@link getJsonStoreFileMtimeMs} /
31
+ * {@link assertJsonStoreFileMtimeUnchanged} /
32
+ * {@link writeJsonStoreFileAtomicWithRetry} plus
33
+ * {@link withJsonStoreCasRetry}: each attempt re-stats, re-reads, and
34
+ * re-merges against the latest on-disk state before writing, aborting with
35
+ * `ESTALE` when another writer moved the file under us. This stays on as a
36
+ * second-line guard for writers that do not take the lockfile.
37
+ *
38
+ * Storage layer: this module sits below the governance stores (which live in
39
+ * lib/ root) and below lib/config.ts; it must only depend on leaf utilities.
40
+ */
41
+ const JSON_STORE_WRITE_RETRY_CODES = new Set(["EBUSY", "EPERM"]);
42
+ const JSON_STORE_READ_RETRY_CODES = new Set(["EBUSY", "EPERM", "EAGAIN"]);
43
+ const JSON_STORE_CAS_MAX_ATTEMPTS = 3;
44
+ /**
45
+ * Stamp `updatedAt` for a per-key governance entry with a hybrid logical
46
+ * floor: when the wall clock regressed below the timestamp the entry being
47
+ * overwritten already carries, stamp `prior + 1` instead of `now`. Every
48
+ * upsert-only store merges with `updatedAt >=`, so a backward clock jump
49
+ * would otherwise stamp a semantically-newer write below its own
50
+ * predecessor and the merge would silently drop it. Equal or forward wall
51
+ * times pass through unchanged — ties already resolve to the caller's
52
+ * write under `>=`.
53
+ *
54
+ * `prior` is the entry the writer saw, which can trail the freshest on-disk
55
+ * entry when a concurrent writer lands between the caller's load and its
56
+ * save; baseline-aware save merges re-apply this same floor against the
57
+ * on-disk entry at merge time so the edit still cannot be lost.
58
+ */
59
+ export function stampUpdatedAt(now, prior) {
60
+ return typeof prior === "number" && Number.isFinite(prior) && now < prior
61
+ ? prior + 1
62
+ : now;
63
+ }
64
+ // ---------------------------------------------------------------------------
65
+ // 1. Per-path in-process write queue
66
+ // ---------------------------------------------------------------------------
67
+ const jsonStoreWriteQueues = new Map();
68
+ // Async-local re-entrancy map for the write queue (keyed by the raw path
69
+ // string, matching the queue key): a nested withJsonStoreWriteQueue on the
70
+ // same path inside one async context runs inside the outer critical section
71
+ // instead of deadlocking on its own queue slot — e.g. config.ts wraps
72
+ // saveUnifiedPluginConfig (which queues on settings.json) in an outer queue
73
+ // for the same path.
74
+ const jsonStoreQueueLeases = new AsyncLocalStorage();
75
+ /**
76
+ * Serialize `task` behind the previous write queued for `path`, so same-file
77
+ * writers inside this process run one at a time in submission order. A failed
78
+ * predecessor never blocks or fails successors. Re-entrant for the same path
79
+ * within one async context.
80
+ *
81
+ * This is the per-path generalization of the module-local `writeQueue`
82
+ * variables the governance stores used to keep by hand.
83
+ */
84
+ export async function withJsonStoreWriteQueue(path, task) {
85
+ const held = jsonStoreQueueLeases.getStore();
86
+ if (held?.get(path)?.active) {
87
+ return task();
88
+ }
89
+ const previous = jsonStoreWriteQueues.get(path) ?? Promise.resolve();
90
+ const lease = { active: true };
91
+ const context = new Map(held);
92
+ context.set(path, lease);
93
+ const queued = previous.catch(() => { }).then(async () => {
94
+ try {
95
+ return await jsonStoreQueueLeases.run(context, task);
96
+ }
97
+ finally {
98
+ lease.active = false;
99
+ }
100
+ });
101
+ // Store the settled (never-rejecting) wrapper so successors chain cleanly;
102
+ // keep the reference for the same-object check below.
103
+ const stored = queued.then(() => undefined, () => undefined);
104
+ jsonStoreWriteQueues.set(path, stored);
105
+ try {
106
+ return await queued;
107
+ }
108
+ finally {
109
+ if (jsonStoreWriteQueues.get(path) === stored) {
110
+ jsonStoreWriteQueues.delete(path);
111
+ }
112
+ }
113
+ }
114
+ /** Test helper: drop queued-write bookkeeping (all paths, or one when given). */
115
+ export function resetJsonStoreWriteQueuesForTests(path) {
116
+ if (path !== undefined) {
117
+ jsonStoreWriteQueues.delete(path);
118
+ return;
119
+ }
120
+ jsonStoreWriteQueues.clear();
121
+ }
122
+ // ---------------------------------------------------------------------------
123
+ // 2. mtime compare-and-swap + atomic JSON write
124
+ // ---------------------------------------------------------------------------
125
+ /**
126
+ * Stat `filePath` for its mtime with bounded transient-FS retry (the save
127
+ * path is Windows-sensitive: a single transient EBUSY/EPERM/EAGAIN from an
128
+ * AV/indexer lock must not abort the whole save). ENOENT returns `null`
129
+ * immediately; on exhaustion the last failure surfaces so the caller treats
130
+ * it as a real save error rather than a phantom missing file.
131
+ */
132
+ export async function getJsonStoreFileMtimeMs(filePath) {
133
+ return withRetry(async () => {
134
+ try {
135
+ return (await fs.stat(filePath)).mtimeMs;
136
+ }
137
+ catch (error) {
138
+ if (error?.code === "ENOENT") {
139
+ return null;
140
+ }
141
+ throw error;
142
+ }
143
+ }, {
144
+ maxAttempts: 5,
145
+ backoffMs: (attempt) => 10 * 2 ** (attempt - 1),
146
+ retryableCodes: JSON_STORE_READ_RETRY_CODES,
147
+ });
148
+ }
149
+ /**
150
+ * The `ESTALE` signal used by the CAS retry loop: the file's mtime moved
151
+ * between the caller's stat and its write, so the attempt must re-read and
152
+ * re-merge against the latest on-disk state instead of clobbering it.
153
+ */
154
+ export function createJsonStoreStaleError(filePath) {
155
+ const staleError = new Error(`JSON store at ${filePath} changed on disk during save; retrying with latest state.`);
156
+ staleError.code = "ESTALE";
157
+ return staleError;
158
+ }
159
+ /**
160
+ * Throw `ESTALE` when `filePath`'s current mtime differs from
161
+ * `expectedMtimeMs` (`null` means "file must still be absent"). Writers that
162
+ * keep their own temp+rename flow call this just before the rename, matching
163
+ * {@link writeJsonStoreFileAtomicWithRetry}'s inline check.
164
+ */
165
+ export async function assertJsonStoreFileMtimeUnchanged(filePath, expectedMtimeMs) {
166
+ const currentMtimeMs = await getJsonStoreFileMtimeMs(filePath);
167
+ if (currentMtimeMs !== expectedMtimeMs) {
168
+ throw createJsonStoreStaleError(filePath);
169
+ }
170
+ }
171
+ /**
172
+ * Atomic JSON write: serialize `payload` pretty-printed with a trailing
173
+ * newline to a crypto-random sibling temp file, then rename it over
174
+ * `filePath` with bounded transient-FS retry. Optionally CAS-checks the
175
+ * target mtime first and fsyncs the temp file; on failure the temp is
176
+ * removed best-effort.
177
+ */
178
+ export async function writeJsonStoreFileAtomicWithRetry(filePath, payload, options) {
179
+ const tempPath = tempPathFor(filePath);
180
+ await fs.mkdir(dirname(filePath), { recursive: true });
181
+ const handle = await fs.open(tempPath, "w", options?.mode);
182
+ try {
183
+ await handle.writeFile(`${JSON.stringify(payload, null, 2)}\n`, "utf8");
184
+ if (options?.fsync) {
185
+ await handle.sync();
186
+ }
187
+ }
188
+ finally {
189
+ await handle.close();
190
+ }
191
+ let renamed = false;
192
+ try {
193
+ if (options && "expectedMtimeMs" in options) {
194
+ await assertJsonStoreFileMtimeUnchanged(filePath, options.expectedMtimeMs ?? null);
195
+ }
196
+ await withRetry(() => fs.rename(tempPath, filePath), {
197
+ maxAttempts: 5,
198
+ backoffMs: (attempt) => 10 * 2 ** (attempt - 1),
199
+ retryableCodes: options?.retryableCodes ?? JSON_STORE_WRITE_RETRY_CODES,
200
+ });
201
+ renamed = true;
202
+ }
203
+ finally {
204
+ if (!renamed) {
205
+ try {
206
+ await fs.unlink(tempPath);
207
+ }
208
+ catch {
209
+ // Best-effort temp cleanup.
210
+ }
211
+ }
212
+ }
213
+ }
214
+ /**
215
+ * Run `task`, retrying `ESTALE` CAS aborts so each attempt can re-read and
216
+ * re-merge against the latest on-disk state (matches the config save loop:
217
+ * 3 attempts, immediate retry, ESTALE-only).
218
+ */
219
+ export async function withJsonStoreCasRetry(task) {
220
+ return withRetry(task, {
221
+ maxAttempts: JSON_STORE_CAS_MAX_ATTEMPTS,
222
+ backoffMs: 0,
223
+ retryableCodes: ["ESTALE"],
224
+ });
225
+ }
226
+ // ---------------------------------------------------------------------------
227
+ // 3. Cross-process lockfile
228
+ // ---------------------------------------------------------------------------
229
+ const JSON_STORE_LOCK_WAIT_TIMEOUT_MS = 10_000;
230
+ /**
231
+ * Cross-process mutex for a JSON store file, delegated to the proven
232
+ * candidate-directory transaction lock in lib/storage/file-lock.ts: each
233
+ * acquirer stages `<path>.write-lock.candidate-*` containing its unique
234
+ * `<host>.<pid>.<uuid>` owner file, then publishes it with a single atomic
235
+ * `rename` (which only succeeds while the lock directory is absent or empty,
236
+ * so there is no ownerless acquisition window). A crashed holder's lock is
237
+ * recovered by unlinking exactly that dead owner's unique filename and
238
+ * removing the directory only while it is still empty — an `rmdir` can never
239
+ * erase a lock that was republished in the meantime, so takeover can never
240
+ * delete another owner's live lock. Waiters on a live holder retry inside
241
+ * `waitTimeoutMs` (default 10s), then this wrapper surfaces the exhaustion
242
+ * as `ELOCKTIMEOUT`. Re-entrant for the same resolved path within one async
243
+ * context.
244
+ */
245
+ export async function withJsonStoreFileLock(targetPath, task, options) {
246
+ try {
247
+ return await withFileTransactionLock(targetPath, task, {
248
+ waitMs: options?.waitTimeoutMs ?? JSON_STORE_LOCK_WAIT_TIMEOUT_MS,
249
+ });
250
+ }
251
+ catch (error) {
252
+ if (error?.code === "ELOCKED") {
253
+ const timeoutError = new Error(`Timed out acquiring JSON store lock at ${targetPath}.`);
254
+ timeoutError.code = "ELOCKTIMEOUT";
255
+ throw timeoutError;
256
+ }
257
+ throw error;
258
+ }
259
+ }
@@ -13,4 +13,3 @@ export declare function buildMetadataSection<TSnapshot extends {
13
13
  validSnapshotCount: number;
14
14
  snapshots: TSnapshot[];
15
15
  };
16
- //# sourceMappingURL=metadata-section.d.ts.map
@@ -33,4 +33,3 @@ export interface AccountStorageV1 {
33
33
  }
34
34
  export declare function migrateV1ToV3(v1: AccountStorageV1): AccountStorageV3;
35
35
  export {};
36
- //# sourceMappingURL=migrations.d.ts.map
@@ -7,38 +7,51 @@
7
7
  * ./public-types.ts.
8
8
  */
9
9
  import { MODEL_FAMILIES } from "../request/helpers/model-map.js";
10
+ import { isRecord } from "./record-utils.js";
10
11
  function nowMs() {
11
12
  return Date.now();
12
13
  }
13
14
  export function migrateV1ToV3(v1) {
14
15
  const now = nowMs();
16
+ const rawActiveIndexByFamily = isRecord(v1.activeIndexByFamily)
17
+ ? v1
18
+ .activeIndexByFamily
19
+ : {};
15
20
  return {
16
21
  version: 3,
17
- accounts: v1.accounts.map((account) => {
22
+ accounts: v1.accounts
23
+ .filter((account) => account !== null && typeof account === "object")
24
+ .map((account) => {
25
+ const { rateLimitResetTime, rateLimitResetTimes: existingResets, ...passthrough } = account;
26
+ // A pre-existing V3 map wins per key; the legacy scalar only fills
27
+ // families the map does not already cover.
18
28
  const rateLimitResetTimes = {};
19
- if (typeof account.rateLimitResetTime === "number" && account.rateLimitResetTime > now) {
29
+ if (isRecord(existingResets)) {
30
+ for (const [family, value] of Object.entries(existingResets)) {
31
+ if (typeof value === "number") {
32
+ rateLimitResetTimes[family] = value;
33
+ }
34
+ }
35
+ }
36
+ if (typeof rateLimitResetTime === "number" && rateLimitResetTime > now) {
20
37
  for (const family of MODEL_FAMILIES) {
21
- rateLimitResetTimes[family] = account.rateLimitResetTime;
38
+ rateLimitResetTimes[family] ??= rateLimitResetTime;
22
39
  }
23
40
  }
24
41
  return {
25
- accountId: account.accountId,
26
- accountIdSource: account.accountIdSource,
27
- accountLabel: account.accountLabel,
28
- email: account.email,
29
- refreshToken: account.refreshToken,
30
- accessToken: account.accessToken,
31
- expiresAt: account.expiresAt,
32
- enabled: account.enabled,
33
- addedAt: account.addedAt,
34
- lastUsed: account.lastUsed,
35
- lastSwitchReason: account.lastSwitchReason,
36
- rateLimitResetTimes: Object.keys(rateLimitResetTimes).length > 0 ? rateLimitResetTimes : undefined,
37
- coolingDownUntil: account.coolingDownUntil,
38
- cooldownReason: account.cooldownReason,
42
+ ...passthrough,
43
+ rateLimitResetTimes: Object.keys(rateLimitResetTimes).length > 0
44
+ ? rateLimitResetTimes
45
+ : undefined,
39
46
  };
40
47
  }),
41
48
  activeIndex: v1.activeIndex,
42
- activeIndexByFamily: Object.fromEntries(MODEL_FAMILIES.map((family) => [family, v1.activeIndex])),
49
+ activeIndexByFamily: Object.fromEntries(MODEL_FAMILIES.map((family) => {
50
+ const perFamily = rawActiveIndexByFamily[family];
51
+ return [
52
+ family,
53
+ typeof perFamily === "number" ? perFamily : v1.activeIndex,
54
+ ];
55
+ })),
43
56
  };
44
57
  }
@@ -12,4 +12,3 @@ export declare function exportNamedBackupEntry(params: {
12
12
  getStoragePath: () => string;
13
13
  exportAccounts: (filePath: string, force?: boolean, beforeCommit?: (resolvedPath: string) => Promise<void> | void) => Promise<void>;
14
14
  }): Promise<string>;
15
- //# sourceMappingURL=named-backup-entry.d.ts.map
@@ -16,4 +16,3 @@ export declare function getNamedBackupsEntry(params: {
16
16
  }>;
17
17
  logDebug: (message: string, details: Record<string, unknown>) => void;
18
18
  }): Promise<NamedBackupSummary[]>;
19
- //# sourceMappingURL=named-backups-entry.d.ts.map
@@ -12,4 +12,3 @@ export declare function collectNamedBackups(storagePath: string, deps: {
12
12
  }>;
13
13
  logDebug: (message: string, details: Record<string, unknown>) => void;
14
14
  }): Promise<NamedBackupSummary[]>;
15
- //# sourceMappingURL=named-backups.d.ts.map
@@ -10,4 +10,3 @@ export declare function setStoragePathDirectState(state: StoragePathState): void
10
10
  export declare function runWithStoragePathState<T>(state: StoragePathState, fn: () => T | Promise<T>): Promise<T>;
11
11
  /** Temporarily use the shared pool without mutating the caller or sibling async scopes. */
12
12
  export declare function runWithGlobalStoragePath<T>(fn: () => T | Promise<T>): Promise<T>;
13
- //# sourceMappingURL=path-state.d.ts.map
@@ -59,4 +59,3 @@ export declare function resolveProjectStorageIdentityRoot(projectRoot: string):
59
59
  export declare function isProjectDirectory(dir: string): boolean;
60
60
  export declare function findProjectRoot(startDir: string): string | null;
61
61
  export declare function resolvePath(filePath: string): string;
62
- //# sourceMappingURL=paths.d.ts.map
@@ -3,6 +3,7 @@ export declare function getPendingAuthPath(storagePath: string): string;
3
3
  /** Record a rotated credential beside the account pool. */
4
4
  export declare function recordPendingAuth(storagePath: string, auth: {
5
5
  priorRefreshToken: string;
6
+ recordId?: string;
6
7
  refreshToken: string;
7
8
  accessToken: string;
8
9
  expiresAt: number;
@@ -10,8 +11,14 @@ export declare function recordPendingAuth(storagePath: string, auth: {
10
11
  }): Promise<void>;
11
12
  /** Overlay pending rotated credentials on rows that still hold the spent token. */
12
13
  export declare function applyPendingAuth(storagePath: string, storage: AccountStorageV3 | null): Promise<AccountStorageV3 | null>;
13
- /** After a save, drop entries whose spent token is no longer on disk (persisted or superseded). */
14
- export declare function prunePendingAuth(storagePath: string, saved: AccountStorageV3): Promise<void>;
14
+ /**
15
+ * After a save, drop entries whose spent token is no longer in any restorable
16
+ * state. `saved` is the primary content just persisted; callers may also
17
+ * supply `restorableRefreshTokens` — refresh tokens still present in recovery
18
+ * sources (rotating/discovered backups, a WAL payload) — since a restore can
19
+ * resurface a spent token, its entry must survive until no source holds it.
20
+ * A scan failure keeps every entry: retention is the safe direction.
21
+ */
22
+ export declare function prunePendingAuth(storagePath: string, saved: AccountStorageV3, restorableRefreshTokens?: () => Promise<Iterable<string>>): Promise<void>;
15
23
  /** Coordinate resets with pending credential writers, including Windows rename locks. */
16
24
  export declare function clearPendingAuth(storagePath: string): Promise<void>;
17
- //# sourceMappingURL=pending-auth.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"pending-auth.d.ts","sourceRoot":"","sources":["../../../lib/storage/pending-auth.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAyB1D,wBAAgB,kBAAkB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAE9D;AAmCD,2DAA2D;AAC3D,wBAAsB,iBAAiB,CACtC,WAAW,EAAE,MAAM,EACnB,IAAI,EAAE;IAAE,iBAAiB,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,GAC3G,OAAO,CAAC,IAAI,CAAC,CA4Bf;AAED,mFAAmF;AACnF,wBAAsB,gBAAgB,CACrC,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,gBAAgB,GAAG,IAAI,GAC9B,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC,CA4BlC;AAED,mGAAmG;AACnG,wBAAsB,gBAAgB,CAAC,WAAW,EAAE,MAAM,EAAE,KAAK,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CAUlG;AAED,yFAAyF;AACzF,wBAAsB,gBAAgB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAGzE"}
1
+ {"version":3,"file":"pending-auth.d.ts","sourceRoot":"","sources":["../../../lib/storage/pending-auth.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AA0B1D,wBAAgB,kBAAkB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAE9D;AAmCD,2DAA2D;AAC3D,wBAAsB,iBAAiB,CACtC,WAAW,EAAE,MAAM,EACnB,IAAI,EAAE;IAAE,iBAAiB,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,GAC9H,OAAO,CAAC,IAAI,CAAC,CA4Bf;AAED,mFAAmF;AACnF,wBAAsB,gBAAgB,CACrC,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,gBAAgB,GAAG,IAAI,GAC9B,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC,CA6BlC;AAED,mGAAmG;AACnG,wBAAsB,gBAAgB,CAAC,WAAW,EAAE,MAAM,EAAE,KAAK,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CAUlG;AAED,yFAAyF;AACzF,wBAAsB,gBAAgB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAGzE"}
@@ -17,6 +17,7 @@ import { getIntentionalResetMarkerPath } from "./backup-paths.js";
17
17
  const entrySchema = z.object({
18
18
  /** sha256 of the spent refresh token: identifies the row without storing it. */
19
19
  prior: z.string().regex(/^[0-9a-f]{64}$/),
20
+ recordId: z.string().trim().min(1).optional(),
20
21
  refreshToken: z.string().min(1),
21
22
  accessToken: z.string().min(1),
22
23
  expiresAt: z.number(),
@@ -78,15 +79,17 @@ export async function recordPendingAuth(storagePath, auth) {
78
79
  }
79
80
  const prior = hash(auth.priorRefreshToken);
80
81
  const entries = (await read(path)).filter((entry) => entry.prior !== prior && entry.prior !== hash(auth.refreshToken));
81
- // Rotating a token that is itself only journaled: the row on disk still holds
82
- // the original spent token, so extend that entry rather than add one that
83
- // no disk row can match.
82
+ // Rotating a token that is itself only journaled: extend that entry to the
83
+ // newest credential, but ALSO keep an entry keyed by the token this
84
+ // rotation just spent. A backup slot or WAL can still hold that
85
+ // intermediate token, and pruning now keeps entries whose spent token any
86
+ // recovery source can surface — a stale-snapshot restore then self-heals
87
+ // straight to the newest credential instead of reviving a spent token.
84
88
  const chained = entries.find((entry) => entry.refreshToken === auth.priorRefreshToken);
85
- const current = chained ?? { prior, refreshToken: auth.refreshToken, accessToken: auth.accessToken, expiresAt: auth.expiresAt, at: auth.at };
86
89
  if (chained)
87
- Object.assign(chained, { refreshToken: auth.refreshToken, accessToken: auth.accessToken, expiresAt: auth.expiresAt, at: auth.at });
88
- else
89
- entries.push(current);
90
+ Object.assign(chained, { recordId: chained.recordId ?? auth.recordId, refreshToken: auth.refreshToken, accessToken: auth.accessToken, expiresAt: auth.expiresAt, at: auth.at });
91
+ const current = { prior, recordId: auth.recordId, refreshToken: auth.refreshToken, accessToken: auth.accessToken, expiresAt: auth.expiresAt, at: auth.at };
92
+ entries.push(current);
90
93
  const excess = entries.length - MAX_ENTRIES;
91
94
  if (excess > 0) {
92
95
  // Drop the oldest other entries, never the credential being recorded now.
@@ -120,6 +123,7 @@ export async function applyPendingAuth(storagePath, storage) {
120
123
  const entry = account.refreshToken ? entries.find((item) => item.prior === hash(account.refreshToken)) : undefined;
121
124
  if (!entry)
122
125
  continue;
126
+ account.recordId ??= entry.recordId;
123
127
  account.refreshToken = entry.refreshToken;
124
128
  account.accessToken = entry.accessToken;
125
129
  account.expiresAt = entry.expiresAt;
@@ -132,14 +136,34 @@ export async function applyPendingAuth(storagePath, storage) {
132
136
  }
133
137
  return storage;
134
138
  }
135
- /** After a save, drop entries whose spent token is no longer on disk (persisted or superseded). */
136
- export async function prunePendingAuth(storagePath, saved) {
139
+ /**
140
+ * After a save, drop entries whose spent token is no longer in any restorable
141
+ * state. `saved` is the primary content just persisted; callers may also
142
+ * supply `restorableRefreshTokens` — refresh tokens still present in recovery
143
+ * sources (rotating/discovered backups, a WAL payload) — since a restore can
144
+ * resurface a spent token, its entry must survive until no source holds it.
145
+ * A scan failure keeps every entry: retention is the safe direction.
146
+ */
147
+ export async function prunePendingAuth(storagePath, saved, restorableRefreshTokens) {
137
148
  const path = getPendingAuthPath(storagePath);
138
149
  const current = await read(path);
139
150
  if (!current.length)
140
151
  return;
141
152
  await withFileTransactionLock(path, async () => {
142
153
  const spent = new Set(saved.accounts.map((account) => hash(account.refreshToken)));
154
+ if (restorableRefreshTokens) {
155
+ try {
156
+ for (const token of await restorableRefreshTokens()) {
157
+ spent.add(hash(token));
158
+ }
159
+ }
160
+ catch (error) {
161
+ log.warn("Recovery-source scan failed; keeping all pending rotated credentials", {
162
+ code: typeof error.code === "string" && /^[A-Z_]{1,40}$/.test(error.code ?? "") ? error.code : "UNKNOWN",
163
+ });
164
+ return;
165
+ }
166
+ }
143
167
  const entries = await read(path);
144
168
  const remaining = entries.filter((entry) => spent.has(entry.prior));
145
169
  if (remaining.length !== entries.length)
@@ -7,4 +7,3 @@ export declare function loadNormalizedStorageFromPath(path: string, label: strin
7
7
  logWarn: (message: string, details: Record<string, unknown>) => void;
8
8
  }): Promise<AccountStorageV3 | null>;
9
9
  export declare function mergeStorageForMigration(current: AccountStorageV3 | null, incoming: AccountStorageV3, normalizeAccountStorage: (value: unknown) => AccountStorageV3 | null, findMatchingAccountIndex: (accounts: AccountStorageV3["accounts"], candidate: AccountStorageV3["accounts"][number]) => number | undefined): AccountStorageV3;
10
- //# sourceMappingURL=project-migration.d.ts.map
@@ -86,4 +86,3 @@ export interface FlaggedAccountStorageV1 {
86
86
  version: 1;
87
87
  accounts: FlaggedAccountMetadataV1[];
88
88
  }
89
- //# sourceMappingURL=public-types.d.ts.map
@@ -0,0 +1,15 @@
1
+ /** Derive a legacy record identity before its first persisted token rotation. */
2
+ export declare function deriveAccountRecordId(account: {
3
+ accountId?: string;
4
+ email?: string;
5
+ refreshToken: string;
6
+ addedAt: number;
7
+ }): string;
8
+ /** Resolve the persisted identity, or derive it for a legacy row. */
9
+ export declare function resolveAccountRecordId(account: {
10
+ recordId?: string;
11
+ accountId?: string;
12
+ email?: string;
13
+ refreshToken: string;
14
+ addedAt: number;
15
+ }): string;
@@ -0,0 +1 @@
1
+ {"version":3,"file":"record-identity.d.ts","sourceRoot":"","sources":["../../../lib/storage/record-identity.ts"],"names":[],"mappings":"AAEA,iFAAiF;AACjF,wBAAgB,qBAAqB,CACpC,OAAO,EAAE;IACR,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,MAAM,CAAC;CAChB,GACC,MAAM,CAQR;AAED,qEAAqE;AACrE,wBAAgB,sBAAsB,CACrC,OAAO,EAAE;IACR,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,MAAM,CAAC;CAChB,GACC,MAAM,CAGR"}