@cortexkit/opencode-antigravity-auth 1.1.0 → 2.0.1

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 (379) hide show
  1. package/README.md +225 -569
  2. package/dist/cli.js +4017 -0
  3. package/dist/cli.js.map +7 -0
  4. package/dist/index.d.ts +1 -3
  5. package/dist/index.d.ts.map +1 -1
  6. package/dist/index.js +20742 -14586
  7. package/dist/index.js.map +4 -4
  8. package/dist/src/antigravity/oauth.d.ts +1 -1
  9. package/dist/src/antigravity/oauth.js +1 -1
  10. package/dist/src/cli.d.ts +21 -0
  11. package/dist/src/cli.d.ts.map +1 -0
  12. package/dist/src/cli.js +237 -0
  13. package/dist/src/cli.js.map +1 -0
  14. package/dist/src/constants.d.ts +1 -1
  15. package/dist/src/constants.js +1 -1
  16. package/dist/src/hooks/auto-update-checker/cache.d.ts.map +1 -1
  17. package/dist/src/hooks/auto-update-checker/cache.js +13 -13
  18. package/dist/src/hooks/auto-update-checker/cache.js.map +1 -1
  19. package/dist/src/hooks/auto-update-checker/checker.d.ts +1 -1
  20. package/dist/src/hooks/auto-update-checker/checker.d.ts.map +1 -1
  21. package/dist/src/hooks/auto-update-checker/checker.js +75 -51
  22. package/dist/src/hooks/auto-update-checker/checker.js.map +1 -1
  23. package/dist/src/hooks/auto-update-checker/constants.d.ts.map +1 -1
  24. package/dist/src/hooks/auto-update-checker/constants.js +12 -12
  25. package/dist/src/hooks/auto-update-checker/constants.js.map +1 -1
  26. package/dist/src/hooks/auto-update-checker/index.d.ts +6 -6
  27. package/dist/src/hooks/auto-update-checker/index.d.ts.map +1 -1
  28. package/dist/src/hooks/auto-update-checker/index.js +17 -17
  29. package/dist/src/hooks/auto-update-checker/index.js.map +1 -1
  30. package/dist/src/hooks/auto-update-checker/logging.js +2 -2
  31. package/dist/src/hooks/auto-update-checker/logging.js.map +1 -1
  32. package/dist/src/hooks/auto-update-checker/types.d.ts.map +1 -1
  33. package/dist/src/plugin/account-access.d.ts +99 -0
  34. package/dist/src/plugin/account-access.d.ts.map +1 -0
  35. package/dist/src/plugin/account-access.js +480 -0
  36. package/dist/src/plugin/account-access.js.map +1 -0
  37. package/dist/src/plugin/account-command-oauth.d.ts +34 -0
  38. package/dist/src/plugin/account-command-oauth.d.ts.map +1 -0
  39. package/dist/src/plugin/account-command-oauth.js +156 -0
  40. package/dist/src/plugin/account-command-oauth.js.map +1 -0
  41. package/dist/src/plugin/accounts.d.ts +7 -256
  42. package/dist/src/plugin/accounts.d.ts.map +1 -1
  43. package/dist/src/plugin/accounts.js +31 -1367
  44. package/dist/src/plugin/accounts.js.map +1 -1
  45. package/dist/src/plugin/agy-request-metadata.d.ts +1 -1
  46. package/dist/src/plugin/agy-request-metadata.js +1 -1
  47. package/dist/src/plugin/agy-transport.d.ts +1 -1
  48. package/dist/src/plugin/agy-transport.js +1 -1
  49. package/dist/src/plugin/auth-doctor.d.ts +6 -6
  50. package/dist/src/plugin/auth-doctor.d.ts.map +1 -1
  51. package/dist/src/plugin/auth-doctor.js +74 -66
  52. package/dist/src/plugin/auth-doctor.js.map +1 -1
  53. package/dist/src/plugin/auth-drift.d.ts +4 -4
  54. package/dist/src/plugin/auth-drift.d.ts.map +1 -1
  55. package/dist/src/plugin/auth-drift.js +15 -15
  56. package/dist/src/plugin/auth-drift.js.map +1 -1
  57. package/dist/src/plugin/auth-loader.d.ts +50 -0
  58. package/dist/src/plugin/auth-loader.d.ts.map +1 -0
  59. package/dist/src/plugin/auth-loader.js +225 -0
  60. package/dist/src/plugin/auth-loader.js.map +1 -0
  61. package/dist/src/plugin/auth.d.ts +1 -1
  62. package/dist/src/plugin/auth.js +1 -1
  63. package/dist/src/plugin/background-quota-refresh.d.ts +146 -0
  64. package/dist/src/plugin/background-quota-refresh.d.ts.map +1 -0
  65. package/dist/src/plugin/background-quota-refresh.js +347 -0
  66. package/dist/src/plugin/background-quota-refresh.js.map +1 -0
  67. package/dist/src/plugin/cache/index.d.ts +1 -1
  68. package/dist/src/plugin/cache/index.d.ts.map +1 -1
  69. package/dist/src/plugin/cache/index.js +1 -1
  70. package/dist/src/plugin/cache/index.js.map +1 -1
  71. package/dist/src/plugin/cache/signature-cache.d.ts +1 -1
  72. package/dist/src/plugin/cache/signature-cache.d.ts.map +1 -1
  73. package/dist/src/plugin/cache/signature-cache.js +23 -24
  74. package/dist/src/plugin/cache/signature-cache.js.map +1 -1
  75. package/dist/src/plugin/cache.d.ts +6 -5
  76. package/dist/src/plugin/cache.d.ts.map +1 -1
  77. package/dist/src/plugin/cache.js +21 -7
  78. package/dist/src/plugin/cache.js.map +1 -1
  79. package/dist/src/plugin/catalog.d.ts +23 -0
  80. package/dist/src/plugin/catalog.d.ts.map +1 -0
  81. package/dist/src/plugin/catalog.js +60 -0
  82. package/dist/src/plugin/catalog.js.map +1 -0
  83. package/dist/src/plugin/cli.d.ts +7 -7
  84. package/dist/src/plugin/cli.d.ts.map +1 -1
  85. package/dist/src/plugin/cli.js +62 -55
  86. package/dist/src/plugin/cli.js.map +1 -1
  87. package/dist/src/plugin/command-data.d.ts +329 -0
  88. package/dist/src/plugin/command-data.d.ts.map +1 -0
  89. package/dist/src/plugin/command-data.js +517 -0
  90. package/dist/src/plugin/command-data.js.map +1 -0
  91. package/dist/src/plugin/commands.d.ts +154 -0
  92. package/dist/src/plugin/commands.d.ts.map +1 -0
  93. package/dist/src/plugin/commands.js +746 -0
  94. package/dist/src/plugin/commands.js.map +1 -0
  95. package/dist/src/plugin/config/index.d.ts +2 -2
  96. package/dist/src/plugin/config/index.d.ts.map +1 -1
  97. package/dist/src/plugin/config/index.js +2 -2
  98. package/dist/src/plugin/config/index.js.map +1 -1
  99. package/dist/src/plugin/config/loader.d.ts +1 -1
  100. package/dist/src/plugin/config/loader.d.ts.map +1 -1
  101. package/dist/src/plugin/config/loader.js +18 -16
  102. package/dist/src/plugin/config/loader.js.map +1 -1
  103. package/dist/src/plugin/config/models.d.ts +2 -2
  104. package/dist/src/plugin/config/models.d.ts.map +1 -1
  105. package/dist/src/plugin/config/models.js +1 -1
  106. package/dist/src/plugin/config/models.js.map +1 -1
  107. package/dist/src/plugin/config/operator-settings-schema.d.ts +29 -0
  108. package/dist/src/plugin/config/operator-settings-schema.d.ts.map +1 -0
  109. package/dist/src/plugin/config/operator-settings-schema.js +28 -0
  110. package/dist/src/plugin/config/operator-settings-schema.js.map +1 -0
  111. package/dist/src/plugin/config/schema.d.ts +23 -2
  112. package/dist/src/plugin/config/schema.d.ts.map +1 -1
  113. package/dist/src/plugin/config/schema.js +109 -25
  114. package/dist/src/plugin/config/schema.js.map +1 -1
  115. package/dist/src/plugin/config/updater.d.ts.map +1 -1
  116. package/dist/src/plugin/config/updater.js +15 -15
  117. package/dist/src/plugin/config/updater.js.map +1 -1
  118. package/dist/src/plugin/config/writer.d.ts +34 -0
  119. package/dist/src/plugin/config/writer.d.ts.map +1 -0
  120. package/dist/src/plugin/config/writer.js +81 -0
  121. package/dist/src/plugin/config/writer.js.map +1 -0
  122. package/dist/src/plugin/core/streaming/index.d.ts +1 -1
  123. package/dist/src/plugin/core/streaming/index.d.ts.map +1 -1
  124. package/dist/src/plugin/core/streaming/index.js +1 -1
  125. package/dist/src/plugin/core/streaming/index.js.map +1 -1
  126. package/dist/src/plugin/core/streaming/transformer.d.ts.map +1 -1
  127. package/dist/src/plugin/core/streaming/transformer.js +85 -44
  128. package/dist/src/plugin/core/streaming/transformer.js.map +1 -1
  129. package/dist/src/plugin/core/streaming/types.d.ts.map +1 -1
  130. package/dist/src/plugin/debug.d.ts +10 -3
  131. package/dist/src/plugin/debug.d.ts.map +1 -1
  132. package/dist/src/plugin/debug.js +110 -47
  133. package/dist/src/plugin/debug.js.map +1 -1
  134. package/dist/src/plugin/dependencies.d.ts +129 -0
  135. package/dist/src/plugin/dependencies.d.ts.map +1 -0
  136. package/dist/src/plugin/dependencies.js +107 -0
  137. package/dist/src/plugin/dependencies.js.map +1 -0
  138. package/dist/src/plugin/errors.d.ts +27 -0
  139. package/dist/src/plugin/errors.d.ts.map +1 -1
  140. package/dist/src/plugin/errors.js +29 -3
  141. package/dist/src/plugin/errors.js.map +1 -1
  142. package/dist/src/plugin/event-handler.d.ts +53 -0
  143. package/dist/src/plugin/event-handler.d.ts.map +1 -0
  144. package/dist/src/plugin/event-handler.js +101 -0
  145. package/dist/src/plugin/event-handler.js.map +1 -0
  146. package/dist/src/plugin/fetch/retry-state.d.ts +61 -0
  147. package/dist/src/plugin/fetch/retry-state.d.ts.map +1 -0
  148. package/dist/src/plugin/fetch/retry-state.js +248 -0
  149. package/dist/src/plugin/fetch/retry-state.js.map +1 -0
  150. package/dist/src/plugin/fetch/warmup.d.ts +30 -0
  151. package/dist/src/plugin/fetch/warmup.d.ts.map +1 -0
  152. package/dist/src/plugin/fetch/warmup.js +76 -0
  153. package/dist/src/plugin/fetch/warmup.js.map +1 -0
  154. package/dist/src/plugin/fetch-interceptor.d.ts +59 -0
  155. package/dist/src/plugin/fetch-interceptor.d.ts.map +1 -0
  156. package/dist/src/plugin/fetch-interceptor.js +1399 -0
  157. package/dist/src/plugin/fetch-interceptor.js.map +1 -0
  158. package/dist/src/plugin/fetch-routing.d.ts +26 -0
  159. package/dist/src/plugin/fetch-routing.d.ts.map +1 -0
  160. package/dist/src/plugin/fetch-routing.js +99 -0
  161. package/dist/src/plugin/fetch-routing.js.map +1 -0
  162. package/dist/src/plugin/fingerprint.d.ts +1 -1
  163. package/dist/src/plugin/fingerprint.js +1 -1
  164. package/dist/src/plugin/gemini-dump.d.ts +5 -5
  165. package/dist/src/plugin/gemini-dump.d.ts.map +1 -1
  166. package/dist/src/plugin/gemini-dump.js +109 -55
  167. package/dist/src/plugin/gemini-dump.js.map +1 -1
  168. package/dist/src/plugin/google-search-tool.d.ts +9 -0
  169. package/dist/src/plugin/google-search-tool.d.ts.map +1 -0
  170. package/dist/src/plugin/google-search-tool.js +56 -0
  171. package/dist/src/plugin/google-search-tool.js.map +1 -0
  172. package/dist/src/plugin/image-saver.d.ts.map +1 -1
  173. package/dist/src/plugin/image-saver.js +16 -16
  174. package/dist/src/plugin/image-saver.js.map +1 -1
  175. package/dist/src/plugin/index.d.ts +30 -0
  176. package/dist/src/plugin/index.d.ts.map +1 -0
  177. package/dist/src/plugin/index.js +411 -0
  178. package/dist/src/plugin/index.js.map +1 -0
  179. package/dist/src/plugin/killswitch.d.ts +94 -0
  180. package/dist/src/plugin/killswitch.d.ts.map +1 -0
  181. package/dist/src/plugin/killswitch.js +197 -0
  182. package/dist/src/plugin/killswitch.js.map +1 -0
  183. package/dist/src/plugin/lifecycle.d.ts +40 -0
  184. package/dist/src/plugin/lifecycle.d.ts.map +1 -0
  185. package/dist/src/plugin/lifecycle.js +73 -0
  186. package/dist/src/plugin/lifecycle.js.map +1 -0
  187. package/dist/src/plugin/logger.d.ts +10 -1
  188. package/dist/src/plugin/logger.d.ts.map +1 -1
  189. package/dist/src/plugin/logger.js +38 -12
  190. package/dist/src/plugin/logger.js.map +1 -1
  191. package/dist/src/plugin/logging-utils.d.ts +35 -1
  192. package/dist/src/plugin/logging-utils.d.ts.map +1 -1
  193. package/dist/src/plugin/logging-utils.js +98 -15
  194. package/dist/src/plugin/logging-utils.js.map +1 -1
  195. package/dist/src/plugin/model-registry.d.ts +1 -1
  196. package/dist/src/plugin/model-registry.js +1 -1
  197. package/dist/src/plugin/oauth-login.d.ts +22 -0
  198. package/dist/src/plugin/oauth-login.d.ts.map +1 -0
  199. package/dist/src/plugin/oauth-login.js +37 -0
  200. package/dist/src/plugin/oauth-login.js.map +1 -0
  201. package/dist/src/plugin/oauth-methods.d.ts +42 -0
  202. package/dist/src/plugin/oauth-methods.d.ts.map +1 -0
  203. package/dist/src/plugin/oauth-methods.js +1276 -0
  204. package/dist/src/plugin/oauth-methods.js.map +1 -0
  205. package/dist/src/plugin/operator-settings.d.ts +40 -0
  206. package/dist/src/plugin/operator-settings.d.ts.map +1 -0
  207. package/dist/src/plugin/operator-settings.js +148 -0
  208. package/dist/src/plugin/operator-settings.js.map +1 -0
  209. package/dist/src/plugin/persist-account-pool.d.ts +37 -0
  210. package/dist/src/plugin/persist-account-pool.d.ts.map +1 -0
  211. package/dist/src/plugin/persist-account-pool.js +142 -0
  212. package/dist/src/plugin/persist-account-pool.js.map +1 -0
  213. package/dist/src/plugin/project.d.ts +1 -1
  214. package/dist/src/plugin/project.js +1 -1
  215. package/dist/src/plugin/prompt-context.d.ts.map +1 -1
  216. package/dist/src/plugin/prompt-context.js +11 -11
  217. package/dist/src/plugin/prompt-context.js.map +1 -1
  218. package/dist/src/plugin/quota.d.ts +138 -41
  219. package/dist/src/plugin/quota.d.ts.map +1 -1
  220. package/dist/src/plugin/quota.js +417 -285
  221. package/dist/src/plugin/quota.js.map +1 -1
  222. package/dist/src/plugin/recovery/constants.d.ts.map +1 -1
  223. package/dist/src/plugin/recovery/constants.js +24 -15
  224. package/dist/src/plugin/recovery/constants.js.map +1 -1
  225. package/dist/src/plugin/recovery/index.d.ts +3 -3
  226. package/dist/src/plugin/recovery/index.d.ts.map +1 -1
  227. package/dist/src/plugin/recovery/index.js +3 -3
  228. package/dist/src/plugin/recovery/index.js.map +1 -1
  229. package/dist/src/plugin/recovery/storage.d.ts +1 -1
  230. package/dist/src/plugin/recovery/storage.d.ts.map +1 -1
  231. package/dist/src/plugin/recovery/storage.js +31 -39
  232. package/dist/src/plugin/recovery/storage.js.map +1 -1
  233. package/dist/src/plugin/recovery/types.d.ts +12 -12
  234. package/dist/src/plugin/recovery/types.d.ts.map +1 -1
  235. package/dist/src/plugin/recovery.d.ts +3 -3
  236. package/dist/src/plugin/recovery.d.ts.map +1 -1
  237. package/dist/src/plugin/recovery.js +62 -58
  238. package/dist/src/plugin/recovery.js.map +1 -1
  239. package/dist/src/plugin/refresh-queue.d.ts +5 -2
  240. package/dist/src/plugin/refresh-queue.d.ts.map +1 -1
  241. package/dist/src/plugin/refresh-queue.js +37 -15
  242. package/dist/src/plugin/refresh-queue.js.map +1 -1
  243. package/dist/src/plugin/request-helpers.d.ts +1 -1
  244. package/dist/src/plugin/request-helpers.d.ts.map +1 -1
  245. package/dist/src/plugin/request-helpers.js +451 -352
  246. package/dist/src/plugin/request-helpers.js.map +1 -1
  247. package/dist/src/plugin/request.d.ts +7 -7
  248. package/dist/src/plugin/request.d.ts.map +1 -1
  249. package/dist/src/plugin/request.js +622 -384
  250. package/dist/src/plugin/request.js.map +1 -1
  251. package/dist/src/plugin/rotation.d.ts +1 -168
  252. package/dist/src/plugin/rotation.d.ts.map +1 -1
  253. package/dist/src/plugin/rotation.js +1 -327
  254. package/dist/src/plugin/rotation.js.map +1 -1
  255. package/dist/src/plugin/search.d.ts.map +1 -1
  256. package/dist/src/plugin/search.js +39 -35
  257. package/dist/src/plugin/search.js.map +1 -1
  258. package/dist/src/plugin/server.d.ts +1 -1
  259. package/dist/src/plugin/server.d.ts.map +1 -1
  260. package/dist/src/plugin/server.js +42 -37
  261. package/dist/src/plugin/server.js.map +1 -1
  262. package/dist/src/plugin/session-context.d.ts +2 -1
  263. package/dist/src/plugin/session-context.d.ts.map +1 -1
  264. package/dist/src/plugin/session-context.js +11 -7
  265. package/dist/src/plugin/session-context.js.map +1 -1
  266. package/dist/src/plugin/storage.d.ts +59 -120
  267. package/dist/src/plugin/storage.d.ts.map +1 -1
  268. package/dist/src/plugin/storage.js +140 -485
  269. package/dist/src/plugin/storage.js.map +1 -1
  270. package/dist/src/plugin/stores/signature-store.d.ts.map +1 -1
  271. package/dist/src/plugin/stores/signature-store.js.map +1 -1
  272. package/dist/src/plugin/thinking-recovery.d.ts.map +1 -1
  273. package/dist/src/plugin/thinking-recovery.js +35 -33
  274. package/dist/src/plugin/thinking-recovery.js.map +1 -1
  275. package/dist/src/plugin/token.d.ts +2 -2
  276. package/dist/src/plugin/token.d.ts.map +1 -1
  277. package/dist/src/plugin/token.js +30 -21
  278. package/dist/src/plugin/token.js.map +1 -1
  279. package/dist/src/plugin/transform/cross-model-sanitizer.d.ts +1 -1
  280. package/dist/src/plugin/transform/cross-model-sanitizer.js +1 -1
  281. package/dist/src/plugin/transform/index.d.ts +1 -1
  282. package/dist/src/plugin/transform/index.js +1 -1
  283. package/dist/src/plugin/transform/model-resolver.d.ts +1 -1
  284. package/dist/src/plugin/transform/model-resolver.js +1 -1
  285. package/dist/src/plugin/transform/types.d.ts +1 -1
  286. package/dist/src/plugin/transform/types.js +1 -1
  287. package/dist/src/plugin/types.d.ts +25 -69
  288. package/dist/src/plugin/types.d.ts.map +1 -1
  289. package/dist/src/plugin/ui/ansi.d.ts.map +1 -1
  290. package/dist/src/plugin/ui/ansi.js.map +1 -1
  291. package/dist/src/plugin/ui/auth-menu.d.ts +1 -1
  292. package/dist/src/plugin/ui/auth-menu.d.ts.map +1 -1
  293. package/dist/src/plugin/ui/auth-menu.js +84 -35
  294. package/dist/src/plugin/ui/auth-menu.js.map +1 -1
  295. package/dist/src/plugin/ui/confirm.d.ts.map +1 -1
  296. package/dist/src/plugin/ui/confirm.js.map +1 -1
  297. package/dist/src/plugin/ui/model-status.d.ts +3 -3
  298. package/dist/src/plugin/ui/model-status.d.ts.map +1 -1
  299. package/dist/src/plugin/ui/model-status.js +3 -3
  300. package/dist/src/plugin/ui/model-status.js.map +1 -1
  301. package/dist/src/plugin/ui/quota-status.d.ts +4 -4
  302. package/dist/src/plugin/ui/quota-status.d.ts.map +1 -1
  303. package/dist/src/plugin/ui/quota-status.js +49 -49
  304. package/dist/src/plugin/ui/quota-status.js.map +1 -1
  305. package/dist/src/plugin/ui/select.d.ts.map +1 -1
  306. package/dist/src/plugin/ui/select.js +22 -12
  307. package/dist/src/plugin/ui/select.js.map +1 -1
  308. package/dist/src/plugin/version.d.ts +1 -1
  309. package/dist/src/plugin/version.js +1 -1
  310. package/dist/src/rpc/notifications.d.ts +6 -0
  311. package/dist/src/rpc/notifications.d.ts.map +1 -0
  312. package/dist/src/rpc/notifications.js +46 -0
  313. package/dist/src/rpc/notifications.js.map +1 -0
  314. package/dist/src/rpc/port-file.d.ts +13 -0
  315. package/dist/src/rpc/port-file.d.ts.map +1 -0
  316. package/dist/src/rpc/port-file.js +109 -0
  317. package/dist/src/rpc/port-file.js.map +1 -0
  318. package/dist/src/rpc/protocol.d.ts +22 -0
  319. package/dist/src/rpc/protocol.d.ts.map +1 -0
  320. package/dist/src/rpc/protocol.js +1 -0
  321. package/dist/src/rpc/protocol.js.map +1 -0
  322. package/dist/src/rpc/rpc-client.d.ts +10 -0
  323. package/dist/src/rpc/rpc-client.d.ts.map +1 -0
  324. package/dist/src/rpc/rpc-client.js +58 -0
  325. package/dist/src/rpc/rpc-client.js.map +1 -0
  326. package/dist/src/rpc/rpc-dir.d.ts +4 -0
  327. package/dist/src/rpc/rpc-dir.d.ts.map +1 -0
  328. package/dist/src/rpc/rpc-dir.js +19 -0
  329. package/dist/src/rpc/rpc-dir.js.map +1 -0
  330. package/dist/src/rpc/rpc-server.d.ts +13 -0
  331. package/dist/src/rpc/rpc-server.d.ts.map +1 -0
  332. package/dist/src/rpc/rpc-server.js +231 -0
  333. package/dist/src/rpc/rpc-server.js.map +1 -0
  334. package/dist/src/sidebar-state.d.ts +357 -0
  335. package/dist/src/sidebar-state.d.ts.map +1 -0
  336. package/dist/src/sidebar-state.js +680 -0
  337. package/dist/src/sidebar-state.js.map +1 -0
  338. package/dist/src/tui/command-dialogs.d.ts +61 -0
  339. package/dist/src/tui/command-dialogs.d.ts.map +1 -0
  340. package/dist/src/tui/command-dialogs.js +595 -0
  341. package/dist/src/tui/command-dialogs.js.map +1 -0
  342. package/dist/src/tui/file-logger.d.ts +41 -0
  343. package/dist/src/tui/file-logger.d.ts.map +1 -0
  344. package/dist/src/tui/file-logger.js +114 -0
  345. package/dist/src/tui/file-logger.js.map +1 -0
  346. package/dist/src/tui-preferences.d.ts +40 -0
  347. package/dist/src/tui-preferences.d.ts.map +1 -0
  348. package/dist/src/tui-preferences.js +328 -0
  349. package/dist/src/tui-preferences.js.map +1 -0
  350. package/dist/src/tui.d.ts +68 -0
  351. package/dist/src/tui.d.ts.map +1 -0
  352. package/dist/src/tui.js +697 -0
  353. package/dist/src/tui.js.map +1 -0
  354. package/package.json +46 -22
  355. package/src/plugin/command-data.ts +931 -0
  356. package/src/rpc/port-file.ts +143 -0
  357. package/src/rpc/protocol.ts +31 -0
  358. package/src/rpc/rpc-client.ts +102 -0
  359. package/src/rpc/rpc-dir.ts +24 -0
  360. package/src/sidebar-state.ts +991 -0
  361. package/src/tui/command-dialogs.tsx +832 -0
  362. package/src/tui/entry.mjs +74 -0
  363. package/src/tui/file-logger.ts +145 -0
  364. package/src/tui-compiled/plugin/command-data.ts +931 -0
  365. package/src/tui-compiled/rpc/port-file.ts +143 -0
  366. package/src/tui-compiled/rpc/protocol.ts +31 -0
  367. package/src/tui-compiled/rpc/rpc-client.ts +102 -0
  368. package/src/tui-compiled/rpc/rpc-dir.ts +24 -0
  369. package/src/tui-compiled/sidebar-state.ts +991 -0
  370. package/src/tui-compiled/tui/command-dialogs.tsx +779 -0
  371. package/src/tui-compiled/tui/file-logger.ts +145 -0
  372. package/src/tui-compiled/tui-preferences.ts +416 -0
  373. package/src/tui-compiled/tui.tsx +1193 -0
  374. package/src/tui-preferences.ts +416 -0
  375. package/src/tui.tsx +1171 -0
  376. package/dist/src/plugin.d.ts +0 -48
  377. package/dist/src/plugin.d.ts.map +0 -1
  378. package/dist/src/plugin.js +0 -3311
  379. package/dist/src/plugin.js.map +0 -1
@@ -1,38 +1,53 @@
1
- import { promises as fs } from "node:fs";
2
- import { existsSync, readFileSync, writeFileSync, appendFileSync, mkdirSync, renameSync, copyFileSync, unlinkSync, } from "node:fs";
3
- import { dirname, join } from "node:path";
4
- import { homedir } from "node:os";
5
- import { randomBytes } from "node:crypto";
6
- let _cachedLock;
7
- async function getLockFunction() {
8
- if (_cachedLock)
9
- return _cachedLock;
10
- const mod = await import("proper-lockfile");
11
- const fn = (typeof mod.lock === "function" ? mod.lock : undefined)
12
- || (mod.default && typeof mod.default.lock === "function"
13
- ? mod.default.lock : undefined);
14
- if (typeof fn !== "function") {
15
- // Never silently degrade to a no-op lock — that would let concurrent
16
- // processes corrupt the account file. Fail loudly so the caller's
17
- // try/catch surfaces it instead of writing unlocked.
18
- throw new Error("proper-lockfile did not expose a lock() function; cannot acquire account file lock");
19
- }
20
- _cachedLock = fn;
21
- return _cachedLock;
22
- }
23
- const lockfile = { lock: (path, options) => getLockFunction().then(fn => fn(path, options)) };
24
- import { createLogger } from "./logger";
25
- const log = createLogger("storage");
1
+ /**
2
+ * Host-path adapter for account storage.
3
+ *
4
+ * Resolves the on-disk path for the OpenCode config directory, handles
5
+ * the legacy Windows migration, and keeps the .gitignore in sync. All
6
+ * data operations are delegated to `@cortexkit/antigravity-auth-core`'s
7
+ * lock-held account-storage engine.
8
+ *
9
+ * The split keeps this module harness-specific (it knows about
10
+ * `OPENCODE_CONFIG_DIR`, `%APPDATA%`, and OpenCode-specific gitignore
11
+ * entries) while the schema, migrations, and lock semantics live in
12
+ * core.
13
+ */
14
+ import { appendFileSync, copyFileSync, existsSync, promises as fs, mkdirSync, readFileSync, renameSync, unlinkSync, writeFileSync, } from 'node:fs';
15
+ import { homedir } from 'node:os';
16
+ import { dirname, join } from 'node:path';
17
+ import { AccountStorageUnreadableError, clearAccountStorage as coreClearAccountStorage, deduplicateAccountsByEmail as coreDeduplicateAccountsByEmail, loadAccountStorage as coreLoadAccountStorage, mergeAccountStorage as coreMergeAccountStorage, migrateV2ToV3 as coreMigrateV2ToV3, mutateAccountStorage as coreMutateAccountStorage, saveAccountStorage as coreSaveAccountStorage, saveAccountStorageReplace as coreSaveAccountStorageReplace, } from '@cortexkit/antigravity-auth-core';
18
+ import { createLogger } from './logger';
19
+ const log = createLogger('storage');
20
+ /**
21
+ * Re-export the typed unreadable-storage error so consumers can
22
+ * `instanceof`-check without pulling core into their own dependency
23
+ * graph. When the on-disk accounts file exists but cannot be parsed
24
+ * as a valid v4 (corrupt JSON, schema mismatch, unknown version, or
25
+ * an I/O error other than ENOENT), every read/write here throws this
26
+ * — never silently overwrites the user's data.
27
+ */
28
+ export { AccountStorageUnreadableError };
29
+ /**
30
+ * Backward-compat re-exports for harnesses still importing
31
+ * `deduplicateAccountsByEmail` / `mergeAccountStorage` / `migrateV2ToV3`
32
+ * from `./storage`. The definitions live in core; the adapter exposes
33
+ * them so legacy test files compile without modification.
34
+ */
35
+ export const deduplicateAccountsByEmail = coreDeduplicateAccountsByEmail;
36
+ export const mergeAccountStorage = coreMergeAccountStorage;
37
+ export const migrateV2ToV3 = coreMigrateV2ToV3;
38
+ export const mutateAccountStorage = coreMutateAccountStorage;
26
39
  /**
27
40
  * Files/directories that should be gitignored in the config directory.
28
41
  * These contain sensitive data or machine-specific state.
29
42
  */
43
+ // NOTE: deliberately no ".gitignore" self-ignore entry — users who track their
44
+ // config dir as a git repo (with .gitignore committed) get endless working-tree
45
+ // drift from re-appending it, and for a tracked file the entry is a no-op anyway.
30
46
  export const GITIGNORE_ENTRIES = [
31
- ".gitignore",
32
- "antigravity-accounts.json",
33
- "antigravity-accounts.json.*.tmp",
34
- "antigravity-signature-cache.json",
35
- "antigravity-logs/",
47
+ 'antigravity-accounts.json',
48
+ 'antigravity-accounts.json.*.tmp',
49
+ 'antigravity-signature-cache.json',
50
+ 'antigravity-logs/',
36
51
  ];
37
52
  /**
38
53
  * Ensures a .gitignore file exists in the config directory with entries
@@ -40,38 +55,38 @@ export const GITIGNORE_ENTRIES = [
40
55
  * entries if it already exists.
41
56
  */
42
57
  export async function ensureGitignore(configDir) {
43
- const gitignorePath = join(configDir, ".gitignore");
58
+ const gitignorePath = join(configDir, '.gitignore');
44
59
  try {
45
60
  let content;
46
61
  let existingLines = [];
47
62
  try {
48
- content = await fs.readFile(gitignorePath, "utf-8");
49
- existingLines = content.split("\n").map((line) => line.trim());
63
+ content = await fs.readFile(gitignorePath, 'utf-8');
64
+ existingLines = content.split('\n').map((line) => line.trim());
50
65
  }
51
66
  catch (error) {
52
- if (error.code !== "ENOENT") {
67
+ if (error.code !== 'ENOENT') {
53
68
  return;
54
69
  }
55
- content = "";
70
+ content = '';
56
71
  }
57
72
  const missingEntries = GITIGNORE_ENTRIES.filter((entry) => !existingLines.includes(entry));
58
73
  if (missingEntries.length === 0) {
59
74
  return;
60
75
  }
61
- if (content === "") {
62
- await fs.writeFile(gitignorePath, missingEntries.join("\n") + "\n", "utf-8");
63
- log.info("Created .gitignore in config directory");
76
+ if (content === '') {
77
+ await fs.writeFile(gitignorePath, `${missingEntries.join('\n')}\n`, 'utf-8');
78
+ log.info('Created .gitignore in config directory');
64
79
  }
65
80
  else {
66
- const suffix = content.endsWith("\n") ? "" : "\n";
67
- await fs.appendFile(gitignorePath, suffix + missingEntries.join("\n") + "\n", "utf-8");
68
- log.info("Updated .gitignore with missing entries", {
81
+ const suffix = content.endsWith('\n') ? '' : '\n';
82
+ await fs.appendFile(gitignorePath, `${suffix + missingEntries.join('\n')}\n`, 'utf-8');
83
+ log.info('Updated .gitignore with missing entries', {
69
84
  added: missingEntries,
70
85
  });
71
86
  }
72
87
  }
73
88
  catch (error) {
74
- log.warn("Failed to update .gitignore with account storage entries", {
89
+ log.warn('Failed to update .gitignore with account storage entries', {
75
90
  error: String(error),
76
91
  });
77
92
  }
@@ -80,35 +95,35 @@ export async function ensureGitignore(configDir) {
80
95
  * Synchronous version of ensureGitignore for use in sync code paths.
81
96
  */
82
97
  export function ensureGitignoreSync(configDir) {
83
- const gitignorePath = join(configDir, ".gitignore");
98
+ const gitignorePath = join(configDir, '.gitignore');
84
99
  try {
85
100
  let content;
86
101
  let existingLines = [];
87
102
  if (existsSync(gitignorePath)) {
88
- content = readFileSync(gitignorePath, "utf-8");
89
- existingLines = content.split("\n").map((line) => line.trim());
103
+ content = readFileSync(gitignorePath, 'utf-8');
104
+ existingLines = content.split('\n').map((line) => line.trim());
90
105
  }
91
106
  else {
92
- content = "";
107
+ content = '';
93
108
  }
94
109
  const missingEntries = GITIGNORE_ENTRIES.filter((entry) => !existingLines.includes(entry));
95
110
  if (missingEntries.length === 0) {
96
111
  return;
97
112
  }
98
- if (content === "") {
99
- writeFileSync(gitignorePath, missingEntries.join("\n") + "\n", "utf-8");
100
- log.info("Created .gitignore in config directory");
113
+ if (content === '') {
114
+ writeFileSync(gitignorePath, `${missingEntries.join('\n')}\n`, 'utf-8');
115
+ log.info('Created .gitignore in config directory');
101
116
  }
102
117
  else {
103
- const suffix = content.endsWith("\n") ? "" : "\n";
104
- appendFileSync(gitignorePath, suffix + missingEntries.join("\n") + "\n", "utf-8");
105
- log.info("Updated .gitignore with missing entries", {
118
+ const suffix = content.endsWith('\n') ? '' : '\n';
119
+ appendFileSync(gitignorePath, `${suffix + missingEntries.join('\n')}\n`, 'utf-8');
120
+ log.info('Updated .gitignore with missing entries', {
106
121
  added: missingEntries,
107
122
  });
108
123
  }
109
124
  }
110
125
  catch (error) {
111
- log.warn("Failed to update .gitignore with account storage entries", {
126
+ log.warn('Failed to update .gitignore with account storage entries', {
112
127
  error: String(error),
113
128
  });
114
129
  }
@@ -118,7 +133,7 @@ export function ensureGitignoreSync(configDir) {
118
133
  * Used for migration from older plugin versions.
119
134
  */
120
135
  function getLegacyWindowsConfigDir() {
121
- return join(process.env.APPDATA || join(homedir(), "AppData", "Roaming"), "opencode");
136
+ return join(process.env.APPDATA || join(homedir(), 'AppData', 'Roaming'), 'opencode');
122
137
  }
123
138
  /**
124
139
  * Gets the config directory path, with the following precedence:
@@ -128,13 +143,11 @@ function getLegacyWindowsConfigDir() {
128
143
  * On Windows, also checks for legacy %APPDATA%\opencode path for migration.
129
144
  */
130
145
  function getConfigDir() {
131
- // 1. Check for explicit override via env var
132
146
  if (process.env.OPENCODE_CONFIG_DIR) {
133
147
  return process.env.OPENCODE_CONFIG_DIR;
134
148
  }
135
- // 2. Use ~/.config/opencode on all platforms (including Windows)
136
- const xdgConfig = process.env.XDG_CONFIG_HOME || join(homedir(), ".config");
137
- return join(xdgConfig, "opencode");
149
+ const xdgConfig = process.env.XDG_CONFIG_HOME || join(homedir(), '.config');
150
+ return join(xdgConfig, 'opencode');
138
151
  }
139
152
  /**
140
153
  * Migrates config from legacy Windows location to the new path.
@@ -142,34 +155,36 @@ function getConfigDir() {
142
155
  * Returns true if migration was performed.
143
156
  */
144
157
  function migrateLegacyWindowsConfig() {
145
- if (process.platform !== "win32") {
158
+ if (process.platform !== 'win32') {
146
159
  return false;
147
160
  }
148
- const newPath = join(getConfigDir(), "antigravity-accounts.json");
149
- const legacyPath = join(getLegacyWindowsConfigDir(), "antigravity-accounts.json");
150
- // Only migrate if legacy exists and new doesn't
161
+ const newPath = join(getConfigDir(), 'antigravity-accounts.json');
162
+ const legacyPath = join(getLegacyWindowsConfigDir(), 'antigravity-accounts.json');
151
163
  if (!existsSync(legacyPath) || existsSync(newPath)) {
152
164
  return false;
153
165
  }
154
166
  try {
155
- // Ensure new config directory exists
156
167
  const newConfigDir = getConfigDir();
157
168
  mkdirSync(newConfigDir, { recursive: true });
158
- // Try rename first (atomic, but fails across filesystems)
159
169
  try {
160
170
  renameSync(legacyPath, newPath);
161
- log.info("Migrated Windows config via rename", { from: legacyPath, to: newPath });
171
+ log.info('Migrated Windows config via rename', {
172
+ from: legacyPath,
173
+ to: newPath,
174
+ });
162
175
  }
163
176
  catch {
164
- // Fallback: copy then delete (for cross-filesystem moves)
165
177
  copyFileSync(legacyPath, newPath);
166
178
  unlinkSync(legacyPath);
167
- log.info("Migrated Windows config via copy+delete", { from: legacyPath, to: newPath });
179
+ log.info('Migrated Windows config via copy+delete', {
180
+ from: legacyPath,
181
+ to: newPath,
182
+ });
168
183
  }
169
184
  return true;
170
185
  }
171
186
  catch (error) {
172
- log.warn("Failed to migrate legacy Windows config, will use legacy path", {
187
+ log.warn('Failed to migrate legacy Windows config, will use legacy path', {
173
188
  legacyPath,
174
189
  newPath,
175
190
  error: String(error),
@@ -182,15 +197,13 @@ function migrateLegacyWindowsConfig() {
182
197
  * On Windows, attempts to move legacy config to new path for alignment.
183
198
  */
184
199
  function getStoragePathWithMigration() {
185
- const newPath = join(getConfigDir(), "antigravity-accounts.json");
186
- // On Windows, attempt to migrate legacy config to new location
187
- if (process.platform === "win32") {
200
+ const newPath = join(getConfigDir(), 'antigravity-accounts.json');
201
+ if (process.platform === 'win32') {
188
202
  migrateLegacyWindowsConfig();
189
- // If migration failed and legacy still exists, fall back to it
190
203
  if (!existsSync(newPath)) {
191
- const legacyPath = join(getLegacyWindowsConfigDir(), "antigravity-accounts.json");
204
+ const legacyPath = join(getLegacyWindowsConfigDir(), 'antigravity-accounts.json');
192
205
  if (existsSync(legacyPath)) {
193
- log.info("Using legacy Windows config path (migration failed)", {
206
+ log.info('Using legacy Windows config path (migration failed)', {
194
207
  legacyPath,
195
208
  newPath,
196
209
  });
@@ -207,443 +220,85 @@ export function getStoragePath() {
207
220
  * Gets the config directory path. Exported for use by other modules.
208
221
  */
209
222
  export { getConfigDir };
210
- const LOCK_OPTIONS = {
211
- stale: 10000,
212
- retries: {
213
- retries: 5,
214
- minTimeout: 100,
215
- maxTimeout: 1000,
216
- factor: 2,
217
- },
218
- };
219
- /**
220
- * Ensures the file has secure permissions (0600) on POSIX systems.
221
- * This is a best-effort operation and ignores errors on Windows/unsupported FS.
222
- */
223
- async function ensureSecurePermissions(path) {
224
- try {
225
- await fs.chmod(path, 0o600);
226
- }
227
- catch {
228
- // Ignore errors (e.g. Windows, file doesn't exist, FS doesn't support chmod)
229
- }
230
- }
231
- async function ensureFileExists(path) {
232
- try {
233
- await fs.access(path);
234
- }
235
- catch {
236
- await fs.mkdir(dirname(path), { recursive: true });
237
- await fs.writeFile(path, JSON.stringify({ version: 4, accounts: [], activeIndex: 0 }, null, 2), { encoding: "utf-8", mode: 0o600 });
238
- }
239
- }
240
- async function withFileLock(path, fn) {
241
- await ensureFileExists(path);
242
- let release = null;
243
- try {
244
- release = await lockfile.lock(path, LOCK_OPTIONS);
245
- return await fn();
246
- }
247
- finally {
248
- if (release) {
249
- try {
250
- await release();
251
- }
252
- catch (unlockError) {
253
- log.warn("Failed to release lock", { error: String(unlockError) });
254
- }
255
- }
256
- }
257
- }
258
- export function mergeAccountStorage(existing, incoming) {
259
- const accountMap = new Map();
260
- for (const acc of existing.accounts) {
261
- if (acc.refreshToken) {
262
- accountMap.set(acc.refreshToken, acc);
263
- }
264
- }
265
- for (const acc of incoming.accounts) {
266
- if (acc.refreshToken) {
267
- const existingAcc = accountMap.get(acc.refreshToken);
268
- if (existingAcc) {
269
- const eligibilitySource = (acc.eligibilityStateUpdatedAt ?? 0) >= (existingAcc.eligibilityStateUpdatedAt ?? 0)
270
- ? acc
271
- : existingAcc;
272
- const merged = {
273
- ...existingAcc,
274
- ...acc,
275
- // Preserve manually configured projectId/managedProjectId if not in incoming
276
- projectId: acc.projectId ?? existingAcc.projectId,
277
- managedProjectId: acc.managedProjectId ?? existingAcc.managedProjectId,
278
- rateLimitResetTimes: {
279
- ...existingAcc.rateLimitResetTimes,
280
- ...acc.rateLimitResetTimes,
281
- },
282
- lastUsed: Math.max(existingAcc.lastUsed || 0, acc.lastUsed || 0),
283
- accountIneligible: eligibilitySource.accountIneligible,
284
- accountIneligibleAt: eligibilitySource.accountIneligibleAt,
285
- accountIneligibleReason: eligibilitySource.accountIneligibleReason,
286
- eligibilityStateUpdatedAt: eligibilitySource.eligibilityStateUpdatedAt,
287
- };
288
- if (merged.accountIneligible) {
289
- merged.enabled = false;
290
- }
291
- accountMap.set(acc.refreshToken, merged);
292
- }
293
- else {
294
- accountMap.set(acc.refreshToken, acc);
295
- }
296
- }
297
- }
298
- return {
299
- version: 4,
300
- accounts: Array.from(accountMap.values()),
301
- activeIndex: incoming.activeIndex,
302
- activeIndexByFamily: incoming.activeIndexByFamily,
303
- };
304
- }
305
- export function deduplicateAccountsByEmail(accounts) {
306
- const emailToNewestIndex = new Map();
307
- const indicesToKeep = new Set();
308
- // First pass: find the newest account for each email (by lastUsed, then addedAt)
309
- for (let i = 0; i < accounts.length; i++) {
310
- const acc = accounts[i];
311
- if (!acc)
312
- continue;
313
- if (!acc.email) {
314
- // No email - keep this account (can't deduplicate without email)
315
- indicesToKeep.add(i);
316
- continue;
317
- }
318
- const existingIndex = emailToNewestIndex.get(acc.email);
319
- if (existingIndex === undefined) {
320
- emailToNewestIndex.set(acc.email, i);
321
- continue;
322
- }
323
- // Compare to find which is newer
324
- const existing = accounts[existingIndex];
325
- if (!existing) {
326
- emailToNewestIndex.set(acc.email, i);
327
- continue;
328
- }
329
- // Prefer higher lastUsed, then higher addedAt
330
- // Compare fields separately to avoid integer overflow with large timestamps
331
- const currLastUsed = acc.lastUsed || 0;
332
- const existLastUsed = existing.lastUsed || 0;
333
- const currAddedAt = acc.addedAt || 0;
334
- const existAddedAt = existing.addedAt || 0;
335
- const isNewer = currLastUsed > existLastUsed ||
336
- (currLastUsed === existLastUsed && currAddedAt > existAddedAt);
337
- if (isNewer) {
338
- emailToNewestIndex.set(acc.email, i);
339
- }
340
- }
341
- // Add all the newest email-based indices to the keep set
342
- for (const idx of emailToNewestIndex.values()) {
343
- indicesToKeep.add(idx);
344
- }
345
- // Build the deduplicated list, preserving original order for kept items
346
- const result = [];
347
- for (let i = 0; i < accounts.length; i++) {
348
- if (indicesToKeep.has(i)) {
349
- const acc = accounts[i];
350
- if (acc) {
351
- result.push(acc);
352
- }
353
- }
354
- }
355
- return result;
356
- }
357
- function migrateV1ToV2(v1) {
358
- return {
359
- version: 2,
360
- accounts: v1.accounts.map((acc) => {
361
- const rateLimitResetTimes = {};
362
- if (acc.isRateLimited &&
363
- acc.rateLimitResetTime &&
364
- acc.rateLimitResetTime > Date.now()) {
365
- rateLimitResetTimes.claude = acc.rateLimitResetTime;
366
- rateLimitResetTimes.gemini = acc.rateLimitResetTime;
367
- }
368
- return {
369
- email: acc.email,
370
- refreshToken: acc.refreshToken,
371
- projectId: acc.projectId,
372
- managedProjectId: acc.managedProjectId,
373
- addedAt: acc.addedAt,
374
- lastUsed: acc.lastUsed,
375
- lastSwitchReason: acc.lastSwitchReason,
376
- rateLimitResetTimes: Object.keys(rateLimitResetTimes).length > 0
377
- ? rateLimitResetTimes
378
- : undefined,
379
- };
380
- }),
381
- activeIndex: v1.activeIndex,
382
- };
383
- }
384
- export function migrateV2ToV3(v2) {
385
- return {
386
- version: 3,
387
- accounts: v2.accounts.map((acc) => {
388
- const rateLimitResetTimes = {};
389
- if (acc.rateLimitResetTimes?.claude &&
390
- acc.rateLimitResetTimes.claude > Date.now()) {
391
- rateLimitResetTimes.claude = acc.rateLimitResetTimes.claude;
392
- }
393
- if (acc.rateLimitResetTimes?.gemini &&
394
- acc.rateLimitResetTimes.gemini > Date.now()) {
395
- rateLimitResetTimes["gemini-antigravity"] =
396
- acc.rateLimitResetTimes.gemini;
397
- }
398
- return {
399
- email: acc.email,
400
- refreshToken: acc.refreshToken,
401
- projectId: acc.projectId,
402
- managedProjectId: acc.managedProjectId,
403
- addedAt: acc.addedAt,
404
- lastUsed: acc.lastUsed,
405
- lastSwitchReason: acc.lastSwitchReason,
406
- rateLimitResetTimes: Object.keys(rateLimitResetTimes).length > 0
407
- ? rateLimitResetTimes
408
- : undefined,
409
- };
410
- }),
411
- activeIndex: v2.activeIndex,
412
- };
413
- }
414
- export function migrateV3ToV4(v3) {
415
- return {
416
- version: 4,
417
- accounts: v3.accounts.map((acc) => ({
418
- ...acc,
419
- fingerprint: undefined,
420
- fingerprintHistory: undefined,
421
- })),
422
- activeIndex: v3.activeIndex,
423
- activeIndexByFamily: v3.activeIndexByFamily,
424
- };
425
- }
223
+ // ============================================================================
224
+ // Host path delegation. Each of these resolves the on-disk path via the
225
+ // adapter above and hands it to the core lock-held engine. Callers that
226
+ // want to run their own mutator (e.g. persist-account-pool) should
227
+ // import from `@cortexkit/antigravity-auth-core` directly and pass
228
+ // `getStoragePath()` as the path argument.
229
+ // ============================================================================
426
230
  export async function loadAccounts() {
427
- try {
428
- const path = getStoragePath();
429
- // Ensure permissions are correct on load (fixes existing files)
430
- await ensureSecurePermissions(path);
431
- const content = await fs.readFile(path, "utf-8");
432
- const data = JSON.parse(content);
433
- if (!Array.isArray(data.accounts)) {
434
- log.warn("Invalid storage format, ignoring");
435
- return null;
436
- }
437
- let storage;
438
- if (data.version === 1) {
439
- log.info("Migrating account storage from v1 to v4");
440
- const v2 = migrateV1ToV2(data);
441
- const v3 = migrateV2ToV3(v2);
442
- storage = migrateV3ToV4(v3);
443
- try {
444
- await saveAccounts(storage);
445
- log.info("Migration to v4 complete");
446
- }
447
- catch (saveError) {
448
- log.warn("Failed to persist migrated storage", {
449
- error: String(saveError),
450
- });
451
- }
452
- }
453
- else if (data.version === 2) {
454
- log.info("Migrating account storage from v2 to v4");
455
- const v3 = migrateV2ToV3(data);
456
- storage = migrateV3ToV4(v3);
457
- try {
458
- await saveAccounts(storage);
459
- log.info("Migration to v4 complete");
460
- }
461
- catch (saveError) {
462
- log.warn("Failed to persist migrated storage", {
463
- error: String(saveError),
464
- });
465
- }
466
- }
467
- else if (data.version === 3) {
468
- log.info("Migrating account storage from v3 to v4");
469
- storage = migrateV3ToV4(data);
470
- try {
471
- await saveAccounts(storage);
472
- log.info("Migration to v4 complete");
473
- }
474
- catch (saveError) {
475
- log.warn("Failed to persist migrated storage", {
476
- error: String(saveError),
477
- });
478
- }
479
- }
480
- else if (data.version === 4) {
481
- storage = data;
482
- }
483
- else {
484
- log.warn("Unknown storage version, ignoring", {
485
- version: data.version,
486
- });
487
- return null;
488
- }
489
- // Validate accounts have required fields
490
- const validAccounts = storage.accounts.filter((a) => {
491
- return (!!a &&
492
- typeof a === "object" &&
493
- typeof a.refreshToken === "string");
494
- });
495
- // Deduplicate accounts by email (keeps newest entry for each email)
496
- const deduplicatedAccounts = deduplicateAccountsByEmail(validAccounts);
497
- // Clamp activeIndex to valid range after deduplication
498
- let activeIndex = typeof storage.activeIndex === "number" &&
499
- Number.isFinite(storage.activeIndex)
500
- ? storage.activeIndex
501
- : 0;
502
- if (deduplicatedAccounts.length > 0) {
503
- activeIndex = Math.min(activeIndex, deduplicatedAccounts.length - 1);
504
- activeIndex = Math.max(activeIndex, 0);
505
- }
506
- else {
507
- activeIndex = 0;
508
- }
509
- return {
510
- version: 4,
511
- accounts: deduplicatedAccounts,
512
- activeIndex,
513
- activeIndexByFamily: storage.activeIndexByFamily,
514
- };
515
- }
516
- catch (error) {
517
- const code = error.code;
518
- if (code === "ENOENT") {
519
- return null;
520
- }
521
- log.error("Failed to load account storage", { error: String(error) });
522
- return null;
523
- }
231
+ const path = getStoragePath();
232
+ await ensureGitignore(dirname(path));
233
+ return coreLoadAccountStorage(path);
524
234
  }
525
235
  /**
526
- * Atomically write content to a file using temp-file + rename.
527
- * Retries the rename up to 3 times with exponential backoff to handle
528
- * transient Windows EPERM errors (antivirus, file indexer, watchers).
529
- * Falls back to copyFile + unlink if all rename attempts fail.
236
+ * Merge `storage` into the persisted pool. Use this for non-destructive
237
+ * writes (quota cache, eligibility, last-used) so concurrent writers
238
+ * do not silently drop each other's data.
530
239
  */
531
- async function atomicWriteFile(targetPath, content) {
532
- const tempPath = `${targetPath}.${randomBytes(6).toString("hex")}.tmp`;
533
- await fs.writeFile(tempPath, content, { encoding: "utf-8", mode: 0o600 });
534
- const RETRY_DELAYS = [50, 100, 200];
535
- let lastError;
536
- for (let attempt = 0; attempt <= RETRY_DELAYS.length; attempt++) {
537
- try {
538
- await fs.rename(tempPath, targetPath);
539
- return;
540
- }
541
- catch (error) {
542
- lastError = error;
543
- const code = error.code;
544
- if (code !== "EPERM" && code !== "EACCES") {
545
- break; // Non-transient error, skip retries
546
- }
547
- if (attempt < RETRY_DELAYS.length) {
548
- await new Promise((r) => setTimeout(r, RETRY_DELAYS[attempt]));
549
- }
550
- }
551
- }
552
- // All rename attempts failed — fall back to copy + delete
553
- try {
554
- await fs.copyFile(tempPath, targetPath);
555
- try {
556
- await fs.unlink(tempPath);
557
- }
558
- catch {
559
- // Ignore temp cleanup errors
560
- }
561
- }
562
- catch {
563
- // Copy also failed — clean up temp and throw original rename error
564
- try {
565
- await fs.unlink(tempPath);
566
- }
567
- catch {
568
- // Ignore cleanup errors
569
- }
570
- throw lastError;
571
- }
572
- }
573
240
  export async function saveAccounts(storage) {
574
241
  const path = getStoragePath();
575
242
  const configDir = dirname(path);
576
243
  await fs.mkdir(configDir, { recursive: true });
577
244
  await ensureGitignore(configDir);
578
- await withFileLock(path, async () => {
579
- const existing = await loadAccountsUnsafe();
580
- const merged = existing ? mergeAccountStorage(existing, storage) : storage;
581
- const content = JSON.stringify(merged, null, 2);
582
- await atomicWriteFile(path, content);
583
- });
245
+ await coreSaveAccountStorage(path, storage);
584
246
  }
585
247
  /**
586
248
  * Save accounts storage by replacing the entire file (no merge).
587
- * Use this for destructive operations like delete where we need to
588
- * remove accounts that would otherwise be merged back from existing storage.
249
+ * Required for destructive operations like delete where the next-state
250
+ * must replace — never be merged with — what is on disk.
589
251
  */
590
252
  export async function saveAccountsReplace(storage) {
591
253
  const path = getStoragePath();
592
254
  const configDir = dirname(path);
593
255
  await fs.mkdir(configDir, { recursive: true });
594
256
  await ensureGitignore(configDir);
595
- await withFileLock(path, async () => {
596
- const content = JSON.stringify(storage, null, 2);
597
- await atomicWriteFile(path, content);
598
- });
599
- }
600
- async function loadAccountsUnsafe() {
601
- try {
602
- const path = getStoragePath();
603
- // Ensure permissions are correct on load (fixes existing files)
604
- await ensureSecurePermissions(path);
605
- const content = await fs.readFile(path, "utf-8");
606
- const parsed = JSON.parse(content);
607
- if (parsed.version === 1) {
608
- return migrateV3ToV4(migrateV2ToV3(migrateV1ToV2(parsed)));
609
- }
610
- if (parsed.version === 2) {
611
- return migrateV3ToV4(migrateV2ToV3(parsed));
612
- }
613
- if (parsed.version === 3) {
614
- return migrateV3ToV4(parsed);
615
- }
616
- return {
617
- ...parsed,
618
- accounts: deduplicateAccountsByEmail(parsed.accounts),
619
- };
620
- }
621
- catch (error) {
622
- const code = error.code;
623
- if (code === "ENOENT") {
624
- return null;
625
- }
626
- log.error("Failed to load account storage (file exists but unreadable)", {
627
- error: String(error),
628
- code: code ?? "unknown",
629
- });
630
- return null;
631
- }
257
+ await coreSaveAccountStorageReplace(path, storage);
632
258
  }
633
259
  export async function clearAccounts() {
634
260
  const path = getStoragePath();
635
261
  try {
636
- // Acquire the file lock so a concurrent debounced save can't write state
637
- // back in between (which would resurrect a just-cleared pool).
638
- await withFileLock(path, async () => {
639
- await fs.unlink(path);
640
- });
262
+ await coreClearAccountStorage(path);
641
263
  }
642
264
  catch (error) {
643
265
  const code = error.code;
644
- if (code !== "ENOENT") {
645
- log.error("Failed to clear account storage", { error: String(error) });
266
+ if (code !== 'ENOENT') {
267
+ log.error('Failed to clear account storage', { error: String(error) });
646
268
  }
647
269
  }
648
270
  }
271
+ /**
272
+ * Locate a stored account by its refresh token under the lock-held
273
+ * mutator and apply `mutate(account)`. Returns the (possibly mutated)
274
+ * account, or `undefined` when the token no longer matches any stored
275
+ * account. Concurrent writers that add/remove accounts will not
276
+ * disturb the lookup — the read happens while the lock is held.
277
+ *
278
+ * `mutate` may mutate `account` in place and return `true` to commit
279
+ * the change; returning `false` is treated as "no change" and skips
280
+ * the write.
281
+ */
282
+ export async function mutateAccountByRefreshToken(refreshToken, mutate) {
283
+ const path = getStoragePath();
284
+ const configDir = dirname(path);
285
+ await fs.mkdir(configDir, { recursive: true });
286
+ await ensureGitignore(configDir);
287
+ let result;
288
+ await coreMutateAccountStorage(path, (current) => {
289
+ const idx = current.accounts.findIndex((acc) => acc.refreshToken === refreshToken);
290
+ if (idx === -1)
291
+ return current;
292
+ const target = current.accounts[idx];
293
+ if (!target)
294
+ return current;
295
+ const changed = mutate(target);
296
+ if (!changed)
297
+ return current;
298
+ result = target;
299
+ current.accounts[idx] = target;
300
+ return current;
301
+ });
302
+ return result;
303
+ }
649
304
  //# sourceMappingURL=storage.js.map