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,16 @@
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;
16
+ //# sourceMappingURL=record-identity.d.ts.map
@@ -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"}
@@ -0,0 +1,16 @@
1
+ import { createHash } from "node:crypto";
2
+ /** Derive a legacy record identity before its first persisted token rotation. */
3
+ export function deriveAccountRecordId(account) {
4
+ const seed = [
5
+ account.addedAt,
6
+ account.accountId?.trim() ?? "",
7
+ account.email?.trim().toLowerCase() ?? "",
8
+ account.refreshToken.trim(),
9
+ ].join("\u0000");
10
+ return `record:${createHash("sha256").update(seed).digest("hex")}`;
11
+ }
12
+ /** Resolve the persisted identity, or derive it for a legacy row. */
13
+ export function resolveAccountRecordId(account) {
14
+ const stored = account.recordId?.trim();
15
+ return stored || deriveAccountRecordId(account);
16
+ }
@@ -0,0 +1,16 @@
1
+ import type { AccountMetadataV3, AccountStorageV3 } from "./public-types.js";
2
+ type CooldownRow = Pick<AccountMetadataV3, "coolingDownUntil" | "cooldownReason" | "refreshToken">;
3
+ /**
4
+ * Preserve concurrent cooldown observations while allowing an unchanged blocker to clear.
5
+ * An auth-failure cooldown belongs to the credential it was recorded against: once
6
+ * the merge keeps a different refresh token (e.g. we won a single-use refresh the
7
+ * other process lost with invalid_grant), that side's auth blocker is obsolete.
8
+ * Other cooldown reasons are observations about the account and are kept.
9
+ */
10
+ export declare function mergeAccountCooldown(base: CooldownRow, disk: CooldownRow, local: CooldownRow): Pick<AccountMetadataV3, "coolingDownUntil" | "cooldownReason">;
11
+ /** Three-way persistence under the file transaction lock. Disk deletions win over stale runtime state. */
12
+ export declare function mergeAccountSnapshot(base: AccountStorageV3 | null, current: AccountStorageV3 | null, local: AccountStorageV3): AccountStorageV3;
13
+ /** Save observations independently of unresolved user-edit conflicts. Inventory stays disk-owned. */
14
+ export declare function mergeAccountRuntimeObservations(base: AccountStorageV3, current: AccountStorageV3, local: AccountStorageV3): AccountStorageV3;
15
+ export {};
16
+ //# sourceMappingURL=snapshot-merge.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"snapshot-merge.d.ts","sourceRoot":"","sources":["../../../lib/storage/snapshot-merge.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AA8D7E,KAAK,WAAW,GAAG,IAAI,CAAC,iBAAiB,EAAE,kBAAkB,GAAG,gBAAgB,GAAG,cAAc,CAAC,CAAC;AACnG;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,WAAW,EAAE,KAAK,EAAE,WAAW,GAAG,IAAI,CAAC,iBAAiB,EAAE,kBAAkB,GAAG,gBAAgB,CAAC,CAW7J;AAqBD,0GAA0G;AAC1G,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,gBAAgB,GAAG,IAAI,EAAE,OAAO,EAAE,gBAAgB,GAAG,IAAI,EAAE,KAAK,EAAE,gBAAgB,GAAG,gBAAgB,CA0E/I;AAED,qGAAqG;AACrG,wBAAgB,+BAA+B,CAAC,IAAI,EAAE,gBAAgB,EAAE,OAAO,EAAE,gBAAgB,EAAE,KAAK,EAAE,gBAAgB,GAAG,gBAAgB,CAmB5I"}
@@ -0,0 +1,206 @@
1
+ import { getAccountIdentityKey } from "./identity.js";
2
+ import { isRecord } from "../utils.js";
3
+ const equal = (a, b) => JSON.stringify(a) === JSON.stringify(b);
4
+ function conflict() {
5
+ throw Object.assign(Error("Account storage changed concurrently; reload before saving."), { code: "ESTALE" });
6
+ }
7
+ function mergeValue(base, disk, local) {
8
+ if (equal(base, local) || equal(disk, local))
9
+ return structuredClone(disk);
10
+ if (equal(base, disk))
11
+ return structuredClone(local);
12
+ if (base === undefined && isRecord(disk) && isRecord(local))
13
+ base = {};
14
+ if (isRecord(base) && isRecord(disk) && isRecord(local)) {
15
+ const result = Object.create(null);
16
+ for (const key of new Set([...Object.keys(base), ...Object.keys(disk), ...Object.keys(local)])) {
17
+ const value = mergeValue(base[key], disk[key], local[key]);
18
+ if (value !== undefined)
19
+ result[key] = value;
20
+ }
21
+ return result;
22
+ }
23
+ return conflict();
24
+ }
25
+ const byId = (rows) => new Map((rows ?? []).map(row => [row.id, row]));
26
+ /**
27
+ * Merge workspaces by id, never by array position. Fields changed on one side
28
+ * win; enabled/disabledAt move as one unit, and when both sides changed it an
29
+ * intentional re-enable wins over a disable. Other two-sided edits conflict.
30
+ * Removal follows the account rule: a record removed on either side stays
31
+ * removed.
32
+ */
33
+ function mergeWorkspaces(base, disk, local) {
34
+ const before = byId(base.workspaces), onDisk = byId(disk.workspaces), next = byId(local.workspaces);
35
+ const ids = [...onDisk.keys(), ...[...next.keys()].filter(id => !onDisk.has(id) && !before.has(id))];
36
+ const workspaces = [];
37
+ for (const id of ids) {
38
+ const b = before.get(id), d = onDisk.get(id), l = next.get(id);
39
+ if (!d || !l) {
40
+ // Present on one side only: an addition survives, a removal wins.
41
+ const added = d ?? l;
42
+ if (!b && added)
43
+ workspaces.push(structuredClone(added));
44
+ continue;
45
+ }
46
+ const state = (row) => ({ enabled: row?.enabled, disabledAt: row?.disabledAt });
47
+ const stateSource = equal(state(b), state(l)) ? d : equal(state(b), state(d)) ? l : d.enabled !== false ? d : l.enabled !== false ? l : (d.disabledAt ?? 0) >= (l.disabledAt ?? 0) ? d : l;
48
+ const pick = (row) => ({ ...row, enabled: stateSource.enabled, disabledAt: stateSource.disabledAt });
49
+ const merged = mergeValue(b ? pick(b) : undefined, pick(d), pick(l));
50
+ if (merged.disabledAt === undefined)
51
+ delete merged.disabledAt;
52
+ workspaces.push(merged);
53
+ }
54
+ const currentId = (row) => row.workspaces?.[row.currentWorkspaceIndex ?? 0]?.id;
55
+ const chosen = currentId(local) !== currentId(base) ? currentId(local) : currentId(disk);
56
+ let index = workspaces.findIndex(row => row.id === chosen);
57
+ if (index < 0 || workspaces[index]?.enabled === false) {
58
+ const enabled = workspaces.findIndex(row => row.enabled !== false);
59
+ index = enabled >= 0 ? enabled : Math.max(index, 0);
60
+ }
61
+ const untracked = [base, disk, local].every(row => row.currentWorkspaceIndex === undefined);
62
+ return { workspaces, currentWorkspaceIndex: untracked && index === 0 ? undefined : index };
63
+ }
64
+ /**
65
+ * Preserve concurrent cooldown observations while allowing an unchanged blocker to clear.
66
+ * An auth-failure cooldown belongs to the credential it was recorded against: once
67
+ * the merge keeps a different refresh token (e.g. we won a single-use refresh the
68
+ * other process lost with invalid_grant), that side's auth blocker is obsolete.
69
+ * Other cooldown reasons are observations about the account and are kept.
70
+ */
71
+ export function mergeAccountCooldown(base, disk, local) {
72
+ const keptToken = local.refreshToken === base.refreshToken ? disk.refreshToken : local.refreshToken;
73
+ const current = (row) => row.cooldownReason === "auth-failure" && row.refreshToken !== keptToken
74
+ ? { ...row, coolingDownUntil: undefined, cooldownReason: undefined } : row;
75
+ disk = current(disk);
76
+ local = current(local);
77
+ const cleared = base.coolingDownUntil !== undefined && ((disk.coolingDownUntil === undefined && (local.coolingDownUntil === undefined || local.coolingDownUntil === base.coolingDownUntil)) ||
78
+ (local.coolingDownUntil === undefined && disk.coolingDownUntil === base.coolingDownUntil));
79
+ const cooldown = (disk.coolingDownUntil ?? 0) >= (local.coolingDownUntil ?? 0) ? disk : local;
80
+ return { coolingDownUntil: cleared ? undefined : cooldown.coolingDownUntil, cooldownReason: cleared ? undefined : cooldown.cooldownReason };
81
+ }
82
+ /** Runtime observations commute; user-owned edits retain conflict detection. */
83
+ function mergeRuntimeAccount(base, disk, local) {
84
+ const limits = {};
85
+ for (const key of new Set([...Object.keys(disk.rateLimitResetTimes ?? {}), ...Object.keys(local.rateLimitResetTimes ?? {})])) {
86
+ const before = base.rateLimitResetTimes?.[key], a = disk.rateLimitResetTimes?.[key], b = local.rateLimitResetTimes?.[key];
87
+ // An explicit clear is an operation, not a new observation.
88
+ const clear = before !== undefined && ((a === undefined && b === before) || (b === undefined && a === before) || (a === undefined && b === undefined));
89
+ const value = clear ? undefined : Math.max(a ?? 0, b ?? 0);
90
+ if (value !== undefined)
91
+ limits[key] = value;
92
+ }
93
+ const runtime = {
94
+ rateLimitResetTimes: Object.keys(limits).length ? limits : undefined,
95
+ ...mergeAccountCooldown(base, disk, local),
96
+ lastSwitchReason: local.lastSwitchReason ?? disk.lastSwitchReason,
97
+ ...(disk.workspaces || local.workspaces ? mergeWorkspaces(base, disk, local) : {}),
98
+ };
99
+ // Omitted and true both mean enabled; serialization does not express a user edit.
100
+ const normalized = (row) => ({ ...row, enabled: row.enabled === false ? false : undefined });
101
+ return mergeValue(normalized(base), { ...normalized(disk), ...runtime }, { ...normalized(local), ...runtime });
102
+ }
103
+ /** Three-way persistence under the file transaction lock. Disk deletions win over stale runtime state. */
104
+ export function mergeAccountSnapshot(base, current, local) {
105
+ if (!base) {
106
+ if (!current)
107
+ return structuredClone(local);
108
+ // An unavailable initial read is not authority to replace the inventory.
109
+ base = { version: 3, accounts: [], activeIndex: 0 };
110
+ }
111
+ if (!current && base.accounts.length === 0 && "restoreReason" in base && base.restoreReason === "missing-storage")
112
+ current = { version: 3, accounts: [], activeIndex: 0 };
113
+ if (!current)
114
+ return conflict();
115
+ const aliases = new Map();
116
+ for (const row of [...base.accounts, ...current.accounts, ...local.accounts]) {
117
+ const key = getAccountIdentityKey(row);
118
+ if (!key || !row.recordId)
119
+ continue;
120
+ const ids = aliases.get(key) ?? new Set();
121
+ ids.add(row.recordId);
122
+ aliases.set(key, ids);
123
+ }
124
+ const identity = (row) => {
125
+ if (row.recordId)
126
+ return row.recordId;
127
+ const key = getAccountIdentityKey(row), ids = key ? aliases.get(key) : undefined;
128
+ return ids?.size === 1 ? [...ids][0] : key;
129
+ };
130
+ const index = (rows) => {
131
+ const map = new Map();
132
+ for (const row of rows) {
133
+ const key = identity(row);
134
+ if (!key || map.has(key))
135
+ return conflict();
136
+ map.set(key, row);
137
+ }
138
+ return map;
139
+ };
140
+ const old = index(base.accounts), disk = index(current.accounts), proposed = index(local.accounts);
141
+ const accounts = [];
142
+ for (const [key, row] of disk) {
143
+ const prior = old.get(key), next = proposed.get(key);
144
+ if (prior && !next)
145
+ continue; // Explicit local removal of a previously known record.
146
+ if (!prior) {
147
+ if (next && !equal(row, next))
148
+ conflict();
149
+ accounts.push(structuredClone(row));
150
+ continue;
151
+ }
152
+ if (!next)
153
+ continue;
154
+ const lastUsed = Math.max(row.lastUsed, next.lastUsed);
155
+ const merged = mergeRuntimeAccount(prior, { ...row, lastUsed }, { ...next, lastUsed });
156
+ accounts.push(merged);
157
+ }
158
+ for (const [key, row] of proposed)
159
+ if (!old.has(key) && !disk.has(key))
160
+ accounts.push(structuredClone(row));
161
+ const pointer = (storage, value) => { const row = value === undefined ? undefined : storage.accounts[value]; return row ? identity(row) : undefined; };
162
+ const position = (id) => id === undefined ? undefined : accounts.findIndex(row => identity(row) === id);
163
+ const pick = (before, onDisk, next) => {
164
+ const oldId = pointer(base, before), diskId = pointer(current, onDisk), localId = pointer(local, next);
165
+ return position(localId !== oldId ? localId : diskId);
166
+ };
167
+ // Pointer metadata must be compared by identity, never by mutable list positions.
168
+ const fields = (storage) => Object.fromEntries(Object.entries(storage).filter(([key]) => !["accounts", "activeIndex", "activeIndexByFamily", "pinnedAccountIndex", "restoreEligible", "restoreReason"].includes(key)));
169
+ const result = { ...mergeValue(fields(base), fields(current), fields(local)), accounts, activeIndex: Math.max(0, pick(base.activeIndex, current.activeIndex, local.activeIndex) ?? 0) };
170
+ result.activeIndexByFamily = {};
171
+ for (const family of new Set([...Object.keys(base.activeIndexByFamily ?? {}), ...Object.keys(current.activeIndexByFamily ?? {}), ...Object.keys(local.activeIndexByFamily ?? {})])) {
172
+ const f = family;
173
+ result.activeIndexByFamily[f] = Math.max(0, pick(base.activeIndexByFamily?.[f], current.activeIndexByFamily?.[f], local.activeIndexByFamily?.[f]) ?? 0);
174
+ }
175
+ const pinned = pick(base.pinnedAccountIndex, current.pinnedAccountIndex, local.pinnedAccountIndex);
176
+ if (pinned !== undefined && pinned >= 0)
177
+ result.pinnedAccountIndex = pinned;
178
+ return result;
179
+ }
180
+ /** Save observations independently of unresolved user-edit conflicts. Inventory stays disk-owned. */
181
+ export function mergeAccountRuntimeObservations(base, current, local) {
182
+ const observations = structuredClone(base);
183
+ const matches = (a, b) => a.recordId && b.recordId
184
+ ? a.recordId === b.recordId : getAccountIdentityKey(a) === getAccountIdentityKey(b);
185
+ for (const prior of observations.accounts) {
186
+ const next = local.accounts.find(row => matches(prior, row));
187
+ if (!next)
188
+ continue;
189
+ prior.lastUsed = Math.max(prior.lastUsed, next.lastUsed);
190
+ for (const field of ["rateLimitResetTimes", "coolingDownUntil", "cooldownReason", "lastSwitchReason"]) {
191
+ if (next[field] === undefined)
192
+ delete prior[field];
193
+ else
194
+ Object.assign(prior, { [field]: structuredClone(next[field]) });
195
+ }
196
+ // Preserve runtime workspace disables without committing labels or workspace selection.
197
+ for (const workspace of prior.workspaces ?? []) {
198
+ const updated = next.workspaces?.find(row => row.id === workspace.id);
199
+ if (updated) {
200
+ workspace.enabled = updated.enabled;
201
+ workspace.disabledAt = updated.disabledAt;
202
+ }
203
+ }
204
+ }
205
+ return mergeAccountSnapshot(base, current, observations);
206
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"transactions.d.ts","sourceRoot":"","sources":["../../../lib/storage/transactions.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,uBAAuB,EAAE,MAAM,mBAAmB,CAAC;AAEnF,MAAM,MAAM,wBAAwB,GAAG;IACtC,QAAQ,EAAE,gBAAgB,GAAG,IAAI,CAAC;IAClC,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,OAAO,CAAC;CAChB,CAAC;AAOF;;;;;;GAMG;AACH,wBAAgB,iBAAiB,IAAI,OAAO,CAE3C;AAED,wBAAgB,2BAA2B,IACxC,wBAAwB,GACxB,SAAS,CAEX;AAED,wBAAgB,+BAA+B,CAAC,CAAC,EAChD,KAAK,EAAE,wBAAwB,EAC/B,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAClB,OAAO,CAAC,CAAC,CAAC,CAEZ;AAED,wBAAgB,eAAe,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CASnE;AAED,wBAAsB,6BAA6B,CAAC,CAAC,EACpD,OAAO,EAAE,CACR,OAAO,EAAE,gBAAgB,GAAG,IAAI,EAChC,OAAO,EAAE,CAAC,OAAO,EAAE,gBAAgB,KAAK,OAAO,CAAC,IAAI,CAAC,KACjD,OAAO,CAAC,CAAC,CAAC,EACf,IAAI,EAAE;IACL,cAAc,EAAE,MAAM,MAAM,CAAC;IAC7B,WAAW,EAAE,MAAM,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC,CAAC;IACpD,YAAY,EAAE,CAAC,OAAO,EAAE,gBAAgB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CAC3D,GACC,OAAO,CAAC,CAAC,CAAC,CAgBZ;AAED,wBAAsB,uCAAuC,CAAC,CAAC,EAC9D,OAAO,EAAE,CACR,OAAO,EAAE,gBAAgB,GAAG,IAAI,EAChC,OAAO,EAAE,CACR,cAAc,EAAE,gBAAgB,EAChC,cAAc,EAAE,uBAAuB,KACnC,OAAO,CAAC,IAAI,CAAC,EAClB,cAAc,EAAE,uBAAuB,KACnC,OAAO,CAAC,CAAC,CAAC,EACf,IAAI,EAAE;IACL,cAAc,EAAE,MAAM,MAAM,CAAC;IAC7B,WAAW,EAAE,MAAM,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC,CAAC;IACpD,kBAAkB,CAAC,EAAE,MAAM,OAAO,CAAC,uBAAuB,CAAC,CAAC;IAC5D,YAAY,EAAE,CAAC,OAAO,EAAE,gBAAgB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3D,mBAAmB,EAAE,CAAC,OAAO,EAAE,uBAAuB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACzE,iCAAiC,EAAE,CAClC,OAAO,EAAE,gBAAgB,GAAG,IAAI,GAAG,SAAS,KACxC,gBAAgB,CAAC;IACtB,gBAAgB,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,aAAa,EAAE,OAAO,KAAK,IAAI,CAAC;CACnE,GACC,OAAO,CAAC,CAAC,CAAC,CA6CZ"}
1
+ {"version":3,"file":"transactions.d.ts","sourceRoot":"","sources":["../../../lib/storage/transactions.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,uBAAuB,EAAE,MAAM,mBAAmB,CAAC;AAGnF,MAAM,MAAM,wBAAwB,GAAG;IACtC,QAAQ,EAAE,gBAAgB,GAAG,IAAI,CAAC;IAClC,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,OAAO,CAAC;CAChB,CAAC;AAOF;;;;;;GAMG;AACH,wBAAgB,iBAAiB,IAAI,OAAO,CAE3C;AAED,wBAAgB,2BAA2B,IACxC,wBAAwB,GACxB,SAAS,CAEX;AAED,wBAAgB,+BAA+B,CAAC,CAAC,EAChD,KAAK,EAAE,wBAAwB,EAC/B,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAClB,OAAO,CAAC,CAAC,CAAC,CAEZ;AAED,wBAAgB,eAAe,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CASnE;AAED,wBAAsB,6BAA6B,CAAC,CAAC,EACpD,OAAO,EAAE,CACR,OAAO,EAAE,gBAAgB,GAAG,IAAI,EAChC,OAAO,EAAE,CAAC,OAAO,EAAE,gBAAgB,KAAK,OAAO,CAAC,IAAI,CAAC,KACjD,OAAO,CAAC,CAAC,CAAC,EACf,IAAI,EAAE;IACL,cAAc,EAAE,MAAM,MAAM,CAAC;IAC7B,WAAW,EAAE,MAAM,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC,CAAC;IACpD,YAAY,EAAE,CAAC,OAAO,EAAE,gBAAgB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CAC3D,GACC,OAAO,CAAC,CAAC,CAAC,CAgBZ;AAED,wBAAsB,uCAAuC,CAAC,CAAC,EAC9D,OAAO,EAAE,CACR,OAAO,EAAE,gBAAgB,GAAG,IAAI,EAChC,OAAO,EAAE,CACR,cAAc,EAAE,gBAAgB,EAChC,cAAc,EAAE,uBAAuB,KACnC,OAAO,CAAC,IAAI,CAAC,EAClB,cAAc,EAAE,uBAAuB,KACnC,OAAO,CAAC,CAAC,CAAC,EACf,IAAI,EAAE;IACL,cAAc,EAAE,MAAM,MAAM,CAAC;IAC7B,WAAW,EAAE,MAAM,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC,CAAC;IACpD,kBAAkB,CAAC,EAAE,MAAM,OAAO,CAAC,uBAAuB,CAAC,CAAC;IAC5D,YAAY,EAAE,CAAC,OAAO,EAAE,gBAAgB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3D,mBAAmB,EAAE,CAAC,OAAO,EAAE,uBAAuB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACzE,iCAAiC,EAAE,CAClC,OAAO,EAAE,gBAAgB,GAAG,IAAI,GAAG,SAAS,KACxC,gBAAgB,CAAC;IACtB,gBAAgB,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,aAAa,EAAE,OAAO,KAAK,IAAI,CAAC;CACnE,GACC,OAAO,CAAC,CAAC,CAAC,CA6CZ"}
@@ -1,4 +1,5 @@
1
1
  import { AsyncLocalStorage } from "node:async_hooks";
2
+ import { withFileTransactionLock } from "./file-lock.js";
2
3
  let storageMutex = Promise.resolve();
3
4
  const transactionSnapshotContext = new AsyncLocalStorage();
4
5
  const storageLockHeldContext = new AsyncLocalStorage();
@@ -29,7 +30,7 @@ export function withStorageLock(fn) {
29
30
  .finally(() => releaseLock());
30
31
  }
31
32
  export async function withAccountStorageTransaction(handler, deps) {
32
- return withStorageLock(async () => {
33
+ return withStorageLock(() => withFileTransactionLock(deps.getStoragePath(), async () => {
33
34
  const state = {
34
35
  snapshot: await deps.loadCurrent(),
35
36
  storagePath: deps.getStoragePath(),
@@ -41,10 +42,10 @@ export async function withAccountStorageTransaction(handler, deps) {
41
42
  state.snapshot = storage;
42
43
  };
43
44
  return transactionSnapshotContext.run(state, () => handler(current, persist));
44
- });
45
+ }));
45
46
  }
46
47
  export async function withAccountAndFlaggedStorageTransaction(handler, deps) {
47
- return withStorageLock(async () => {
48
+ return withStorageLock(() => withFileTransactionLock(deps.getStoragePath(), async () => {
48
49
  const state = {
49
50
  snapshot: await deps.loadCurrent(),
50
51
  storagePath: deps.getStoragePath(),
@@ -78,5 +79,5 @@ export async function withAccountAndFlaggedStorageTransaction(handler, deps) {
78
79
  }
79
80
  };
80
81
  return transactionSnapshotContext.run(state, () => handler(current, persist, currentFlagged));
81
- });
82
+ }));
82
83
  }
@@ -5,6 +5,8 @@ export { formatStorageErrorHint, toStorageError, } from "./storage/error-hints.j
5
5
  export { getAccountIdentityKey, normalizeEmailKey, } from "./storage/identity.js";
6
6
  import type { AccountMetadataV3, AccountStorageV3, CooldownReason, FlaggedAccountMetadataV1, FlaggedAccountStorageV1, RateLimitStateV3 } from "./storage/public-types.js";
7
7
  import { type NamedBackupSummary } from "./storage/named-backups.js";
8
+ import { recordPendingAuth } from "./storage/pending-auth.js";
9
+ export { recordPendingAuth };
8
10
  export type { StorageHealthSummary, CooldownReason, RateLimitStateV3, AccountMetadataV3, AccountStorageV3, FlaggedAccountMetadataV1, FlaggedAccountStorageV1, BackupMetadata, RestoreAssessment, NamedBackupSummary, };
9
11
  type AccountLike = {
10
12
  accountId?: string;
@@ -142,6 +144,8 @@ export declare function loadAccounts(): Promise<AccountStorageV3 | null>;
142
144
  export declare function getBackupMetadata(): Promise<BackupMetadata>;
143
145
  export declare function getRestoreAssessment(): Promise<RestoreAssessment>;
144
146
  export declare function inspectStorageHealth(): Promise<StorageHealthSummary>;
147
+ /** Code for a merge base that cannot be read; distinct from an ESTALE edit conflict. */
148
+ export declare const ACCOUNT_STORAGE_UNREADABLE = "EACCOUNTSUNREADABLE";
145
149
  export declare function withAccountStorageTransaction<T>(handler: (current: AccountStorageV3 | null, persist: (storage: AccountStorageV3) => Promise<void>) => Promise<T>): Promise<T>;
146
150
  export declare function withAccountAndFlaggedStorageTransaction<T>(handler: (current: AccountStorageV3 | null, persist: (accountStorage: AccountStorageV3, flaggedStorage: FlaggedAccountStorageV1) => Promise<void>, currentFlagged: FlaggedAccountStorageV1) => Promise<T>): Promise<T>;
147
151
  export declare function withFlaggedStorageTransaction<T>(handler: (current: FlaggedAccountStorageV1, persist: (storage: FlaggedAccountStorageV1) => Promise<void>) => Promise<T>): Promise<T>;
@@ -152,6 +156,8 @@ export declare function withFlaggedStorageTransaction<T>(handler: (current: Flag
152
156
  * @param storage - Account storage data to save
153
157
  * @throws StorageError with platform-aware hints on failure
154
158
  */
159
+ /** Clone a loaded working snapshot without losing its optimistic-concurrency baseline. */
160
+ export declare function cloneTrackedAccountStorage(storage: AccountStorageV3): AccountStorageV3;
155
161
  export declare function saveAccounts(storage: AccountStorageV3): Promise<void>;
156
162
  /**
157
163
  * Deletes the account storage file from disk.
@@ -1 +1 @@
1
- {"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../../lib/storage.ts"],"names":[],"mappings":"AA+BA,OAAO,EACN,KAAK,cAAc,EAGnB,KAAK,iBAAiB,EAEtB,MAAM,8BAA8B,CAAC;AAkBtC,OAAO,EAEN,KAAK,oBAAoB,EACzB,MAAM,qBAAqB,CAAC;AAe7B,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EACN,sBAAsB,EACtB,cAAc,GACd,MAAM,0BAA0B,CAAC;AAClC,OAAO,EACN,qBAAqB,EACrB,iBAAiB,GACjB,MAAM,uBAAuB,CAAC;AAa/B,OAAO,KAAK,EACX,iBAAiB,EACjB,gBAAgB,EAChB,cAAc,EACd,wBAAwB,EACxB,uBAAuB,EACvB,gBAAgB,EAChB,MAAM,2BAA2B,CAAC;AAEnC,OAAO,EAEN,KAAK,kBAAkB,EACvB,MAAM,4BAA4B,CAAC;AA2CpC,YAAY,EACX,oBAAoB,EACpB,cAAc,EACd,gBAAgB,EAChB,iBAAiB,EACjB,gBAAgB,EAChB,wBAAwB,EACxB,uBAAuB,EACvB,cAAc,EACd,iBAAiB,EACjB,kBAAkB,GAClB,CAAC;AAcF,KAAK,WAAW,GAAG;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;CAClB,CAAC;AAiBF,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAE9D;AAuWD,wBAAgB,4BAA4B,IAAI,MAAM,CAErD;AAED,wBAAgB,cAAc,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CA4C/D;AAED,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAO9D;AAED;;;GAGG;AACH,wBAAgB,cAAc,IAAI,MAAM,CAMvC;AAED,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEzD;AAED,wBAAsB,eAAe,IAAI,OAAO,CAAC,kBAAkB,EAAE,CAAC,CAarE;AAED,wBAAsB,yBAAyB,CAC9C,IAAI,EAAE,MAAM,EACZ,OAAO,CAAC,EAAE;IAAE,OAAO,CAAC,EAAE,OAAO,CAAA;CAAE,GAC7B,OAAO,CAAC,gBAAgB,CAAC,CAe3B;AAED,wBAAsB,iBAAiB,CACtC,IAAI,EAAE,MAAM,EACZ,OAAO,CAAC,EAAE;IAAE,KAAK,CAAC,EAAE,OAAO,CAAA;CAAE,GAC3B,OAAO,CAAC,MAAM,CAAC,CAQjB;AAED,wBAAgB,sBAAsB,IAAI,MAAM,CAE/C;AA6LD,KAAK,mBAAmB,GAAG;IAC1B,wCAAwC,CAAC,EAAE,OAAO,CAAC;CACnD,CAAC;AA8IF,wBAAgB,wBAAwB,CACvC,CAAC,SAAS,IAAI,CAAC,WAAW,EAAE,WAAW,GAAG,OAAO,GAAG,cAAc,CAAC,EAEnE,QAAQ,EAAE,SAAS,CAAC,EAAE,EACtB,SAAS,EAAE,IAAI,CAAC,WAAW,EAAE,WAAW,GAAG,OAAO,GAAG,cAAc,CAAC,EACpE,OAAO,GAAE,mBAAwB,GAC/B,MAAM,GAAG,SAAS,CAkBpB;AAED;;;;;;;;GAQG;AACH,wBAAgB,2BAA2B,CAC1C,aAAa,EACV,IAAI,CAAC,WAAW,EAAE,WAAW,GAAG,OAAO,GAAG,cAAc,CAAC,GACzD,SAAS,EACZ,YAAY,EAAE,SAAS,IAAI,CAC1B,WAAW,EACX,WAAW,GAAG,OAAO,GAAG,cAAc,CACtC,EAAE,GACD,MAAM,GAAG,SAAS,CAGpB;AAED,wBAAgB,4BAA4B,CAC3C,CAAC,SAAS,IAAI,CAAC,WAAW,EAAE,WAAW,GAAG,OAAO,GAAG,cAAc,CAAC,EAEnE,QAAQ,EAAE,SAAS,CAAC,EAAE,EACtB,SAAS,EAAE,IAAI,CAAC,WAAW,EAAE,WAAW,GAAG,OAAO,GAAG,cAAc,CAAC,EACpE,aAAa,SAAI,GACf,MAAM,CAOR;AAsCD;;;GAGG;AACH,wBAAgB,mBAAmB,CAClC,CAAC,SAAS;IACT,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;CACjB,EACA,QAAQ,EAAE,CAAC,EAAE,GAAG,CAAC,EAAE,CAEpB;AAED,wBAAgB,0BAA0B,CACzC,CAAC,SAAS;IACT,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;CACjB,EACA,QAAQ,EAAE,CAAC,EAAE,GAAG,CAAC,EAAE,CAEpB;AAoBD;;;;;GAKG;AACH,wBAAgB,uBAAuB,CACtC,IAAI,EAAE,OAAO,GACX,gBAAgB,GAAG,IAAI,CAqJzB;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,8BAA8B,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAwBnE;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,6BAA6B,CAC5C,OAAO,EAAE;IAAE,kBAAkB,CAAC,EAAE,MAAM,CAAA;CAAE,EACxC,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,GACzB,MAAM,CAmBR;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,qBAAqB,CACpC,IAAI,EAAE,MAAM,EACZ,OAAO,CAAC,EAAE;IAAE,MAAM,CAAC,EAAE,OAAO,CAAA;CAAE,GAC5B;IACF,kBAAkB,EAAE,MAAM,GAAG,SAAS,CAAC;IACvC,kBAAkB,EAAE,MAAM,CAAC;CAC3B,CA6CA;AAED;;;;GAIG;AACH,wBAAsB,YAAY,IAAI,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC,CAErE;AAED,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,cAAc,CAAC,CAajE;AAED,wBAAsB,oBAAoB,IAAI,OAAO,CAAC,iBAAiB,CAAC,CASvE;AAED,wBAAsB,oBAAoB,IAAI,OAAO,CAAC,oBAAoB,CAAC,CAiG1E;AAyaD,wBAAsB,6BAA6B,CAAC,CAAC,EACpD,OAAO,EAAE,CACR,OAAO,EAAE,gBAAgB,GAAG,IAAI,EAChC,OAAO,EAAE,CAAC,OAAO,EAAE,gBAAgB,KAAK,OAAO,CAAC,IAAI,CAAC,KACjD,OAAO,CAAC,CAAC,CAAC,GACb,OAAO,CAAC,CAAC,CAAC,CAMZ;AAED,wBAAsB,uCAAuC,CAAC,CAAC,EAC9D,OAAO,EAAE,CACR,OAAO,EAAE,gBAAgB,GAAG,IAAI,EAChC,OAAO,EAAE,CACR,cAAc,EAAE,gBAAgB,EAChC,cAAc,EAAE,uBAAuB,KACnC,OAAO,CAAC,IAAI,CAAC,EAClB,cAAc,EAAE,uBAAuB,KACnC,OAAO,CAAC,CAAC,CAAC,GACb,OAAO,CAAC,CAAC,CAAC,CAgDZ;AAED,wBAAsB,6BAA6B,CAAC,CAAC,EACpD,OAAO,EAAE,CACR,OAAO,EAAE,uBAAuB,EAChC,OAAO,EAAE,CAAC,OAAO,EAAE,uBAAuB,KAAK,OAAO,CAAC,IAAI,CAAC,KACxD,OAAO,CAAC,CAAC,CAAC,GACb,OAAO,CAAC,CAAC,CAAC,CAiCZ;AAED;;;;;;GAMG;AACH,wBAAsB,YAAY,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CAM3E;AAED;;;GAGG;AACH,wBAAsB,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC,CAcnD;AAED,wBAAsB,mBAAmB,IAAI,OAAO,CAAC,uBAAuB,CAAC,CAgD5E;AAyBD,wBAAsB,mBAAmB,CACxC,OAAO,EAAE,uBAAuB,GAC9B,OAAO,CAAC,IAAI,CAAC,CAMf;AAED,wBAAsB,oBAAoB,IAAI,OAAO,CAAC,IAAI,CAAC,CAa1D;AAED;;;;;GAKG;AACH,wBAAsB,cAAc,CACnC,QAAQ,EAAE,MAAM,EAChB,KAAK,UAAO,EACZ,YAAY,CAAC,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,GAC3D,OAAO,CAAC,IAAI,CAAC,CAgBf;AAED;;;;;GAKG;AACH,wBAAsB,cAAc,CACnC,QAAQ,EAAE,MAAM,GACd,OAAO,CAAC;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC,CAe/D"}
1
+ {"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../../lib/storage.ts"],"names":[],"mappings":"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"}
@@ -50,7 +50,16 @@ import { buildRestoreAssessment } from "./storage/restore-assessment.js";
50
50
  import { restoreAccountsFromBackupEntry } from "./storage/restore-backup-entry.js";
51
51
  import { createEmptyStorageWithRestoreMetadata as createEmptyStorageWithMetadata, withRestoreMetadata, } from "./storage/restore-metadata.js";
52
52
  import { loadAccountsFromPath, parseAndNormalizeStorage, } from "./storage/storage-parser.js";
53
- import { getTransactionSnapshotState, isStorageLockHeld, runInTransactionSnapshotContext, withAccountStorageTransaction as runWithAccountStorageTransaction, withStorageLock, } from "./storage/transactions.js";
53
+ import { getTransactionSnapshotState, isStorageLockHeld, runInTransactionSnapshotContext, withAccountStorageTransaction as runWithAccountStorageTransaction, withStorageLock as withProcessStorageLock, } from "./storage/transactions.js";
54
+ import { withFileTransactionLock } from "./storage/file-lock.js";
55
+ import { mergeAccountSnapshot } from "./storage/snapshot-merge.js";
56
+ import { applyPendingAuth, clearPendingAuth, prunePendingAuth, recordPendingAuth } from "./storage/pending-auth.js";
57
+ export { recordPendingAuth };
58
+ const loadedAccountSnapshots = new WeakMap();
59
+ function withStorageLock(action) {
60
+ const path = getStoragePath();
61
+ return withProcessStorageLock(() => withFileTransactionLock(path, action));
62
+ }
54
63
  const log = createLogger("storage");
55
64
  const ACCOUNTS_FILE_NAME = "openai-codex-accounts.json";
56
65
  const FLAGGED_ACCOUNTS_FILE_NAME = "openai-codex-flagged-accounts.json";
@@ -1069,7 +1078,10 @@ export function readPinAndGenFromDisk(path, options) {
1069
1078
  * @returns AccountStorageV3 if file exists and is valid, null otherwise
1070
1079
  */
1071
1080
  export async function loadAccounts() {
1072
- return loadAccountsInternal(saveAccounts);
1081
+ const storage = await applyPendingAuth(getStoragePath(), await loadAccountsInternal(saveAccounts));
1082
+ if (storage)
1083
+ loadedAccountSnapshots.set(storage, structuredClone(storage));
1084
+ return storage;
1073
1085
  }
1074
1086
  export async function getBackupMetadata() {
1075
1087
  const storagePath = getStoragePath();
@@ -1456,6 +1468,13 @@ async function loadAccountsForExport() {
1456
1468
  }
1457
1469
  }
1458
1470
  async function saveAccountsUnlocked(storage) {
1471
+ await saveAccountsUnlockedToDisk(storage);
1472
+ // A persisted (or superseded) pending rotated credential is no longer needed.
1473
+ await prunePendingAuth(getStoragePath(), storage).catch((error) => {
1474
+ log.warn("Failed to prune pending rotated credentials", { code: typeof error.code === "string" && /^[A-Z_]{1,40}$/.test(error.code ?? "") ? error.code : "INVALID_PENDING_AUTH" });
1475
+ });
1476
+ }
1477
+ async function saveAccountsUnlockedToDisk(storage) {
1459
1478
  const path = getStoragePath();
1460
1479
  const resetMarkerPath = getIntentionalResetMarkerPath(path);
1461
1480
  const walPath = getAccountsWalPath(path);
@@ -1577,10 +1596,40 @@ function cloneFlaggedStorageForPersistence(storage) {
1577
1596
  accounts: structuredClone(storage?.accounts ?? []),
1578
1597
  };
1579
1598
  }
1599
+ /** Code for a merge base that cannot be read; distinct from an ESTALE edit conflict. */
1600
+ export const ACCOUNT_STORAGE_UNREADABLE = "EACCOUNTSUNREADABLE";
1601
+ async function loadPrimaryAccountsForMerge() {
1602
+ const path = getStoragePath();
1603
+ if (existsSync(getIntentionalResetMarkerPath(path))) {
1604
+ return createEmptyStorageWithMetadata(false, "intentional-reset");
1605
+ }
1606
+ try {
1607
+ const { normalized } = await loadAccountsFromPath(path, {
1608
+ normalizeAccountStorage,
1609
+ isRecord,
1610
+ });
1611
+ if (!normalized)
1612
+ throw new Error("Invalid primary account storage");
1613
+ // The merge base must carry pending rotated credentials too, or a merge
1614
+ // would keep the spent token that is still on disk.
1615
+ return applyPendingAuth(path, normalized);
1616
+ }
1617
+ catch (cause) {
1618
+ const code = cause.code;
1619
+ // The journal is written before the primary and removed after it, so a
1620
+ // journal beside a missing primary is the newest state, not a stale
1621
+ // backup. Without one, the deletion is authoritative.
1622
+ if (code === "ENOENT")
1623
+ return applyPendingAuth(path, await loadAccountsFromJournal(path, { silent: true }));
1624
+ // A locked or torn primary may hold newer state than any backup, so it is
1625
+ // never replaced by a recovered copy here.
1626
+ throw Object.assign(new Error(`Account storage could not be read${typeof code === "string" ? ` (${code})` : ""}; nothing was saved.`), { code: ACCOUNT_STORAGE_UNREADABLE, cause });
1627
+ }
1628
+ }
1580
1629
  export async function withAccountStorageTransaction(handler) {
1581
1630
  return runWithAccountStorageTransaction(handler, {
1582
1631
  getStoragePath,
1583
- loadCurrent: () => loadAccountsInternal(saveAccountsUnlocked),
1632
+ loadCurrent: loadPrimaryAccountsForMerge,
1584
1633
  saveAccounts: saveAccountsUnlocked,
1585
1634
  });
1586
1635
  }
@@ -1588,7 +1637,7 @@ export async function withAccountAndFlaggedStorageTransaction(handler) {
1588
1637
  return withStorageLock(async () => {
1589
1638
  const storagePath = getStoragePath();
1590
1639
  const state = {
1591
- snapshot: await loadAccountsInternal(saveAccountsUnlocked),
1640
+ snapshot: await loadPrimaryAccountsForMerge(),
1592
1641
  storagePath,
1593
1642
  active: true,
1594
1643
  };
@@ -1596,7 +1645,8 @@ export async function withAccountAndFlaggedStorageTransaction(handler) {
1596
1645
  const currentFlagged = await loadFlaggedAccounts();
1597
1646
  const persist = async (accountStorage, flaggedStorage) => {
1598
1647
  const previousAccounts = cloneAccountStorageForPersistence(state.snapshot);
1599
- const nextAccounts = cloneAccountStorageForPersistence(accountStorage);
1648
+ const baseline = loadedAccountSnapshots.get(accountStorage);
1649
+ const nextAccounts = cloneAccountStorageForPersistence(baseline ? mergeAccountSnapshot(baseline, state.snapshot, accountStorage) : accountStorage);
1600
1650
  const nextFlagged = cloneFlaggedStorageForPersistence(flaggedStorage);
1601
1651
  await saveAccountsUnlocked(nextAccounts);
1602
1652
  try {
@@ -1659,11 +1709,29 @@ export async function withFlaggedStorageTransaction(handler) {
1659
1709
  * @param storage - Account storage data to save
1660
1710
  * @throws StorageError with platform-aware hints on failure
1661
1711
  */
1712
+ /** Clone a loaded working snapshot without losing its optimistic-concurrency baseline. */
1713
+ export function cloneTrackedAccountStorage(storage) {
1714
+ const clone = structuredClone(storage);
1715
+ const baseline = loadedAccountSnapshots.get(storage);
1716
+ if (baseline)
1717
+ loadedAccountSnapshots.set(clone, structuredClone(baseline));
1718
+ return clone;
1719
+ }
1662
1720
  export async function saveAccounts(storage) {
1663
1721
  return saveAccountsEntry({
1664
1722
  storage,
1665
1723
  withStorageLock,
1666
- saveUnlocked: saveAccountsUnlocked,
1724
+ saveUnlocked: async (proposed) => {
1725
+ const baseline = loadedAccountSnapshots.get(proposed);
1726
+ const snapshot = baseline ? mergeAccountSnapshot(baseline, await loadPrimaryAccountsForMerge(), proposed) : proposed;
1727
+ await saveAccountsUnlocked(snapshot);
1728
+ if (baseline) {
1729
+ for (const key of Object.keys(proposed))
1730
+ Reflect.deleteProperty(proposed, key);
1731
+ Object.assign(proposed, structuredClone(snapshot));
1732
+ loadedAccountSnapshots.set(proposed, structuredClone(snapshot));
1733
+ }
1734
+ },
1667
1735
  });
1668
1736
  }
1669
1737
  /**
@@ -1672,7 +1740,7 @@ export async function saveAccounts(storage) {
1672
1740
  */
1673
1741
  export async function clearAccounts() {
1674
1742
  const path = getStoragePath();
1675
- return clearAccountsEntry({
1743
+ await clearAccountsEntry({
1676
1744
  path,
1677
1745
  withStorageLock,
1678
1746
  resetMarkerPath: getIntentionalResetMarkerPath(path),
@@ -1683,6 +1751,8 @@ export async function clearAccounts() {
1683
1751
  log.error(message, details);
1684
1752
  },
1685
1753
  });
1754
+ // Pending rotated credentials belong to the cleared pool.
1755
+ await clearPendingAuth(path);
1686
1756
  }
1687
1757
  export async function loadFlaggedAccounts() {
1688
1758
  return loadFlaggedAccountsEntry({
@@ -47,6 +47,8 @@ export type AuthMenuAction = {
47
47
  type: "fix";
48
48
  } | {
49
49
  type: "settings";
50
+ } | {
51
+ type: "api-models";
50
52
  } | {
51
53
  type: "fresh";
52
54
  } | {
@@ -1 +1 @@
1
- {"version":3,"file":"auth-menu-builder.d.ts","sourceRoot":"","sources":["../../../lib/ui/auth-menu-builder.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"auth-menu-builder.d.ts","sourceRoot":"","sources":["../../../lib/ui/auth-menu-builder.ts"],"names":[],"mappings":"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"}
@@ -362,6 +362,7 @@ export function authMenuFocusKey(action) {
362
362
  case "add":
363
363
  case "forecast":
364
364
  case "fix":
365
+ case "api-models":
365
366
  case "settings":
366
367
  case "fresh":
367
368
  case "check":
@@ -1 +1 @@
1
- {"version":3,"file":"auth-menu.d.ts","sourceRoot":"","sources":["../../../lib/ui/auth-menu.ts"],"names":[],"mappings":"AAEA,OAAO,EAAQ,KAAK,EAAE,MAAM,WAAW,CAAC;AAMxC,OAAO,EAWN,KAAK,aAAa,EAClB,KAAK,WAAW,EAChB,KAAK,cAAc,EACnB,KAAK,eAAe,EACpB,MAAM,wBAAwB,CAAC;AAEhC,YAAY,EACX,aAAa,EACb,WAAW,EACX,aAAa,EACb,cAAc,EACd,eAAe,GACf,MAAM,wBAAwB,CAAC;AAiBhC,wBAAsB,YAAY,CACjC,QAAQ,EAAE,WAAW,EAAE,EACvB,OAAO,GAAE,eAAoB,GAC3B,OAAO,CAAC,cAAc,CAAC,CAyLzB;AAED,wBAAsB,kBAAkB,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,aAAa,CAAC,CAmErF;AAED,OAAO,EAAE,KAAK,EAAE,CAAC"}
1
+ {"version":3,"file":"auth-menu.d.ts","sourceRoot":"","sources":["../../../lib/ui/auth-menu.ts"],"names":[],"mappings":"AAEA,OAAO,EAAQ,KAAK,EAAE,MAAM,WAAW,CAAC;AAMxC,OAAO,EAWN,KAAK,aAAa,EAClB,KAAK,WAAW,EAChB,KAAK,cAAc,EACnB,KAAK,eAAe,EACpB,MAAM,wBAAwB,CAAC;AAEhC,YAAY,EACX,aAAa,EACb,WAAW,EACX,aAAa,EACb,cAAc,EACd,eAAe,GACf,MAAM,wBAAwB,CAAC;AAiBhC,wBAAsB,YAAY,CACjC,QAAQ,EAAE,WAAW,EAAE,EACvB,OAAO,GAAE,eAAoB,GAC3B,OAAO,CAAC,cAAc,CAAC,CA0LzB;AAED,wBAAsB,kBAAkB,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,aAAa,CAAC,CAmErF;AAED,OAAO,EAAE,KAAK,EAAE,CAAC"}
@@ -49,6 +49,7 @@ export async function showAuthMenu(accounts, options = {}) {
49
49
  { label: UI_COPY.mainMenu.checkAccounts, value: { type: "check" }, color: "green" },
50
50
  { label: UI_COPY.mainMenu.bestAccount, value: { type: "forecast" }, color: "green" },
51
51
  { label: UI_COPY.mainMenu.fixIssues, value: { type: "fix" }, color: "green" },
52
+ { label: "API credentials and models", value: { type: "api-models" }, color: "green" },
52
53
  { label: UI_COPY.mainMenu.settings, value: { type: "settings" }, color: "green" },
53
54
  { label: "", value: { type: "cancel" }, separator: true },
54
55
  { label: UI_COPY.mainMenu.moreChecks, value: { type: "cancel" }, kind: "heading" },
@@ -0,0 +1,8 @@
1
+ type ProgressOutput = {
2
+ isTTY?: boolean;
3
+ write: (text: string) => unknown;
4
+ };
5
+ /** Indeterminate progress: elapsed time is real; no guessed completion percentage. */
6
+ export declare function withCheckProgress<T>(label: string | (() => string), operation: () => Promise<T>, log?: (message: string) => void, output?: ProgressOutput): Promise<T>;
7
+ export {};
8
+ //# sourceMappingURL=check-progress.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"check-progress.d.ts","sourceRoot":"","sources":["../../../lib/ui/check-progress.ts"],"names":[],"mappings":"AAEA,KAAK,cAAc,GAAG;IAAE,KAAK,CAAC,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAA;CAAE,CAAC;AAE5E,sFAAsF;AACtF,wBAAsB,iBAAiB,CAAC,CAAC,EACxC,KAAK,EAAE,MAAM,GAAG,CAAC,MAAM,MAAM,CAAC,EAC9B,SAAS,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EAC3B,GAAG,GAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAA2D,EACrF,MAAM,GAAE,cAA+B,GACrC,OAAO,CAAC,CAAC,CAAC,CAqBZ"}
@@ -0,0 +1,30 @@
1
+ import { ANSI } from "./ansi.js";
2
+ /** Indeterminate progress: elapsed time is real; no guessed completion percentage. */
3
+ export async function withCheckProgress(label, operation, log = message => { process.stdout.write(`${message}\n`); }, output = process.stdout) {
4
+ const message = () => typeof label === "function" ? label() : label;
5
+ const started = Date.now();
6
+ const interactive = output.isTTY === true;
7
+ const frames = ["|", "/", "-", "\\"];
8
+ let frame = 0;
9
+ const elapsed = () => Math.floor((Date.now() - started) / 1000);
10
+ const render = () => {
11
+ if (interactive)
12
+ output.write(`\r${ANSI.clearLine}${frames[frame++ % frames.length]} ${message()} (${elapsed()}s)`);
13
+ else
14
+ log(`${message()}... ${elapsed()}s elapsed`);
15
+ };
16
+ if (interactive)
17
+ render();
18
+ else
19
+ log(`${message()}...`);
20
+ const timer = setInterval(render, interactive ? 120 : 5000);
21
+ timer.unref?.();
22
+ try {
23
+ return await operation();
24
+ }
25
+ finally {
26
+ clearInterval(timer);
27
+ if (interactive)
28
+ output.write(`\r${ANSI.clearLine}`);
29
+ }
30
+ }
@@ -1,4 +1,4 @@
1
- import type { UiRuntimeOptions } from "./runtime.js";
1
+ import { type UiRuntimeOptions } from "./runtime.js";
2
2
  export type UiTextTone = "primary" | "heading" | "accent" | "muted" | "success" | "warning" | "danger" | "normal";
3
3
  /**
4
4
  * Colorize a text string according to the UI theme and tone.
@@ -59,4 +59,6 @@ export declare function formatUiBadge(ui: UiRuntimeOptions, label: string, tone?
59
59
  * Token redaction: does not handle or emit sensitive tokens.
60
60
  */
61
61
  export declare function quotaToneFromLeftPercent(leftPercent: number): Extract<UiTextTone, "success" | "warning" | "danger">;
62
+ /** Style human-readable reports; JSON callers must bypass this presentation helper. */
63
+ export declare function styleReportText(text: string, tone?: UiTextTone): string;
62
64
  //# sourceMappingURL=format.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"format.d.ts","sourceRoot":"","sources":["../../../lib/ui/format.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAErD,MAAM,MAAM,UAAU,GACnB,SAAS,GACT,SAAS,GACT,QAAQ,GACR,OAAO,GACP,SAAS,GACT,SAAS,GACT,QAAQ,GACR,QAAQ,CAAC;AAuGZ;;;;;;;;;;;;;GAaG;AACH,wBAAgB,WAAW,CAAC,EAAE,EAAE,gBAAgB,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,GAAE,UAAqB,GAAG,MAAM,CAKnG;AAED,wBAAgB,cAAc,CAAC,EAAE,EAAE,gBAAgB,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAO5E;AAED,wBAAgB,eAAe,CAAC,EAAE,EAAE,gBAAgB,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAG7E;AAED,wBAAgB,YAAY,CAC3B,EAAE,EAAE,gBAAgB,EACpB,IAAI,EAAE,MAAM,EACZ,IAAI,GAAE,UAAqB,GACzB,MAAM,CAIR;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,gBAAgB,CAC/B,EAAE,EAAE,gBAAgB,EACpB,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,MAAM,EACb,SAAS,GAAE,UAAqB,GAC9B,MAAM,CAKR;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,aAAa,CAC5B,EAAE,EAAE,gBAAgB,EACpB,KAAK,EAAE,MAAM,EACb,IAAI,GAAE,OAAO,CAAC,UAAU,EAAE,QAAQ,GAAG,SAAS,CAAY,GACxD,MAAM,CAKR;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,wBAAwB,CACvC,WAAW,EAAE,MAAM,GACjB,OAAO,CAAC,UAAU,EAAE,SAAS,GAAG,SAAS,GAAG,QAAQ,CAAC,CAIvD"}
1
+ {"version":3,"file":"format.d.ts","sourceRoot":"","sources":["../../../lib/ui/format.ts"],"names":[],"mappings":"AAAA,OAAO,EAAuB,KAAK,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAG1E,MAAM,MAAM,UAAU,GACnB,SAAS,GACT,SAAS,GACT,QAAQ,GACR,OAAO,GACP,SAAS,GACT,SAAS,GACT,QAAQ,GACR,QAAQ,CAAC;AAuGZ;;;;;;;;;;;;;GAaG;AACH,wBAAgB,WAAW,CAAC,EAAE,EAAE,gBAAgB,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,GAAE,UAAqB,GAAG,MAAM,CAKnG;AAED,wBAAgB,cAAc,CAAC,EAAE,EAAE,gBAAgB,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAO5E;AAED,wBAAgB,eAAe,CAAC,EAAE,EAAE,gBAAgB,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAG7E;AAED,wBAAgB,YAAY,CAC3B,EAAE,EAAE,gBAAgB,EACpB,IAAI,EAAE,MAAM,EACZ,IAAI,GAAE,UAAqB,GACzB,MAAM,CAIR;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,gBAAgB,CAC/B,EAAE,EAAE,gBAAgB,EACpB,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,MAAM,EACb,SAAS,GAAE,UAAqB,GAC9B,MAAM,CAKR;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,aAAa,CAC5B,EAAE,EAAE,gBAAgB,EACpB,KAAK,EAAE,MAAM,EACb,IAAI,GAAE,OAAO,CAAC,UAAU,EAAE,QAAQ,GAAG,SAAS,CAAY,GACxD,MAAM,CAKR;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,wBAAwB,CACvC,WAAW,EAAE,MAAM,GACjB,OAAO,CAAC,UAAU,EAAE,SAAS,GAAG,SAAS,GAAG,QAAQ,CAAC,CAIvD;AAED,uFAAuF;AACvF,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,GAAE,UAAqB,GAAG,MAAM,CAGjF"}