@percygfx/opencode-antigravity-auth 0.0.0-stage → 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 (312) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +896 -3
  3. package/dist/index.d.ts +4 -0
  4. package/dist/index.d.ts.map +1 -0
  5. package/dist/index.js +3 -0
  6. package/dist/index.js.map +1 -0
  7. package/dist/rpc.d.ts +176 -0
  8. package/dist/rpc.d.ts.map +1 -0
  9. package/dist/rpc.js +91 -0
  10. package/dist/rpc.js.map +1 -0
  11. package/dist/server.d.ts +3 -0
  12. package/dist/server.d.ts.map +1 -0
  13. package/dist/server.js +5 -0
  14. package/dist/server.js.map +1 -0
  15. package/dist/src/antigravity/oauth.d.ts +31 -0
  16. package/dist/src/antigravity/oauth.d.ts.map +1 -0
  17. package/dist/src/antigravity/oauth.js +171 -0
  18. package/dist/src/antigravity/oauth.js.map +1 -0
  19. package/dist/src/constants.d.ts +153 -0
  20. package/dist/src/constants.d.ts.map +1 -0
  21. package/dist/src/constants.js +238 -0
  22. package/dist/src/constants.js.map +1 -0
  23. package/dist/src/core/gateway.d.ts +43 -0
  24. package/dist/src/core/gateway.d.ts.map +1 -0
  25. package/dist/src/core/gateway.js +241 -0
  26. package/dist/src/core/gateway.js.map +1 -0
  27. package/dist/src/core/index.d.ts +8 -0
  28. package/dist/src/core/index.d.ts.map +1 -0
  29. package/dist/src/core/index.js +8 -0
  30. package/dist/src/core/index.js.map +1 -0
  31. package/dist/src/core/types.d.ts +60 -0
  32. package/dist/src/core/types.d.ts.map +1 -0
  33. package/dist/src/core/types.js +5 -0
  34. package/dist/src/core/types.js.map +1 -0
  35. package/dist/src/hooks/auto-update-checker/cache.d.ts +3 -0
  36. package/dist/src/hooks/auto-update-checker/cache.d.ts.map +1 -0
  37. package/dist/src/hooks/auto-update-checker/cache.js +71 -0
  38. package/dist/src/hooks/auto-update-checker/cache.js.map +1 -0
  39. package/dist/src/hooks/auto-update-checker/checker.d.ts +16 -0
  40. package/dist/src/hooks/auto-update-checker/checker.d.ts.map +1 -0
  41. package/dist/src/hooks/auto-update-checker/checker.js +234 -0
  42. package/dist/src/hooks/auto-update-checker/checker.js.map +1 -0
  43. package/dist/src/hooks/auto-update-checker/constants.d.ts +11 -0
  44. package/dist/src/hooks/auto-update-checker/constants.d.ts.map +1 -0
  45. package/dist/src/hooks/auto-update-checker/constants.js +26 -0
  46. package/dist/src/hooks/auto-update-checker/constants.js.map +1 -0
  47. package/dist/src/hooks/auto-update-checker/index.d.ts +34 -0
  48. package/dist/src/hooks/auto-update-checker/index.d.ts.map +1 -0
  49. package/dist/src/hooks/auto-update-checker/index.js +122 -0
  50. package/dist/src/hooks/auto-update-checker/index.js.map +1 -0
  51. package/dist/src/hooks/auto-update-checker/logging.d.ts +3 -0
  52. package/dist/src/hooks/auto-update-checker/logging.d.ts.map +1 -0
  53. package/dist/src/hooks/auto-update-checker/logging.js +9 -0
  54. package/dist/src/hooks/auto-update-checker/logging.js.map +1 -0
  55. package/dist/src/hooks/auto-update-checker/types.d.ts +25 -0
  56. package/dist/src/hooks/auto-update-checker/types.d.ts.map +1 -0
  57. package/dist/src/hooks/auto-update-checker/types.js +1 -0
  58. package/dist/src/hooks/auto-update-checker/types.js.map +1 -0
  59. package/dist/src/opencode-v2/accounts.d.ts +24 -0
  60. package/dist/src/opencode-v2/accounts.d.ts.map +1 -0
  61. package/dist/src/opencode-v2/accounts.js +109 -0
  62. package/dist/src/opencode-v2/accounts.js.map +1 -0
  63. package/dist/src/opencode-v2/catalog.d.ts +31 -0
  64. package/dist/src/opencode-v2/catalog.d.ts.map +1 -0
  65. package/dist/src/opencode-v2/catalog.js +68 -0
  66. package/dist/src/opencode-v2/catalog.js.map +1 -0
  67. package/dist/src/opencode-v2/client-shim.d.ts +9 -0
  68. package/dist/src/opencode-v2/client-shim.d.ts.map +1 -0
  69. package/dist/src/opencode-v2/client-shim.js +42 -0
  70. package/dist/src/opencode-v2/client-shim.js.map +1 -0
  71. package/dist/src/opencode-v2/clipboard.d.ts +7 -0
  72. package/dist/src/opencode-v2/clipboard.d.ts.map +1 -0
  73. package/dist/src/opencode-v2/clipboard.js +54 -0
  74. package/dist/src/opencode-v2/clipboard.js.map +1 -0
  75. package/dist/src/opencode-v2/index.d.ts +5 -0
  76. package/dist/src/opencode-v2/index.d.ts.map +1 -0
  77. package/dist/src/opencode-v2/index.js +4 -0
  78. package/dist/src/opencode-v2/index.js.map +1 -0
  79. package/dist/src/opencode-v2/plugin.d.ts +23 -0
  80. package/dist/src/opencode-v2/plugin.d.ts.map +1 -0
  81. package/dist/src/opencode-v2/plugin.js +466 -0
  82. package/dist/src/opencode-v2/plugin.js.map +1 -0
  83. package/dist/src/opencode-v2/proxy.d.ts +23 -0
  84. package/dist/src/opencode-v2/proxy.d.ts.map +1 -0
  85. package/dist/src/opencode-v2/proxy.js +148 -0
  86. package/dist/src/opencode-v2/proxy.js.map +1 -0
  87. package/dist/src/opencode-v2/quota-format.d.ts +19 -0
  88. package/dist/src/opencode-v2/quota-format.d.ts.map +1 -0
  89. package/dist/src/opencode-v2/quota-format.js +71 -0
  90. package/dist/src/opencode-v2/quota-format.js.map +1 -0
  91. package/dist/src/opencode-v2/quota.d.ts +18 -0
  92. package/dist/src/opencode-v2/quota.d.ts.map +1 -0
  93. package/dist/src/opencode-v2/quota.js +118 -0
  94. package/dist/src/opencode-v2/quota.js.map +1 -0
  95. package/dist/src/opencode-v2/sign-in-attempts.d.ts +52 -0
  96. package/dist/src/opencode-v2/sign-in-attempts.d.ts.map +1 -0
  97. package/dist/src/opencode-v2/sign-in-attempts.js +81 -0
  98. package/dist/src/opencode-v2/sign-in-attempts.js.map +1 -0
  99. package/dist/src/plugin/account-models.d.ts +38 -0
  100. package/dist/src/plugin/account-models.d.ts.map +1 -0
  101. package/dist/src/plugin/account-models.js +78 -0
  102. package/dist/src/plugin/account-models.js.map +1 -0
  103. package/dist/src/plugin/accounts.d.ts +186 -0
  104. package/dist/src/plugin/accounts.d.ts.map +1 -0
  105. package/dist/src/plugin/accounts.js +1045 -0
  106. package/dist/src/plugin/accounts.js.map +1 -0
  107. package/dist/src/plugin/auth.d.ts +21 -0
  108. package/dist/src/plugin/auth.d.ts.map +1 -0
  109. package/dist/src/plugin/auth.js +46 -0
  110. package/dist/src/plugin/auth.js.map +1 -0
  111. package/dist/src/plugin/cache/index.d.ts +5 -0
  112. package/dist/src/plugin/cache/index.d.ts.map +1 -0
  113. package/dist/src/plugin/cache/index.js +5 -0
  114. package/dist/src/plugin/cache/index.js.map +1 -0
  115. package/dist/src/plugin/cache/signature-cache.d.ts +111 -0
  116. package/dist/src/plugin/cache/signature-cache.d.ts.map +1 -0
  117. package/dist/src/plugin/cache/signature-cache.js +375 -0
  118. package/dist/src/plugin/cache/signature-cache.js.map +1 -0
  119. package/dist/src/plugin/cache.d.ts +44 -0
  120. package/dist/src/plugin/cache.d.ts.map +1 -0
  121. package/dist/src/plugin/cache.js +200 -0
  122. package/dist/src/plugin/cache.js.map +1 -0
  123. package/dist/src/plugin/cli.d.ts +26 -0
  124. package/dist/src/plugin/cli.d.ts.map +1 -0
  125. package/dist/src/plugin/cli.js +119 -0
  126. package/dist/src/plugin/cli.js.map +1 -0
  127. package/dist/src/plugin/config/index.d.ts +16 -0
  128. package/dist/src/plugin/config/index.d.ts.map +1 -0
  129. package/dist/src/plugin/config/index.js +16 -0
  130. package/dist/src/plugin/config/index.js.map +1 -0
  131. package/dist/src/plugin/config/loader.d.ts +36 -0
  132. package/dist/src/plugin/config/loader.d.ts.map +1 -0
  133. package/dist/src/plugin/config/loader.js +140 -0
  134. package/dist/src/plugin/config/loader.js.map +1 -0
  135. package/dist/src/plugin/config/models.d.ts +41 -0
  136. package/dist/src/plugin/config/models.d.ts.map +1 -0
  137. package/dist/src/plugin/config/models.js +46 -0
  138. package/dist/src/plugin/config/models.js.map +1 -0
  139. package/dist/src/plugin/config/schema.d.ts +135 -0
  140. package/dist/src/plugin/config/schema.d.ts.map +1 -0
  141. package/dist/src/plugin/config/schema.js +438 -0
  142. package/dist/src/plugin/config/schema.js.map +1 -0
  143. package/dist/src/plugin/config/updater.d.ts +55 -0
  144. package/dist/src/plugin/config/updater.d.ts.map +1 -0
  145. package/dist/src/plugin/config/updater.js +125 -0
  146. package/dist/src/plugin/config/updater.js.map +1 -0
  147. package/dist/src/plugin/core/streaming/index.d.ts +3 -0
  148. package/dist/src/plugin/core/streaming/index.d.ts.map +1 -0
  149. package/dist/src/plugin/core/streaming/index.js +3 -0
  150. package/dist/src/plugin/core/streaming/index.js.map +1 -0
  151. package/dist/src/plugin/core/streaming/transformer.d.ts +10 -0
  152. package/dist/src/plugin/core/streaming/transformer.d.ts.map +1 -0
  153. package/dist/src/plugin/core/streaming/transformer.js +271 -0
  154. package/dist/src/plugin/core/streaming/transformer.js.map +1 -0
  155. package/dist/src/plugin/core/streaming/types.d.ts +27 -0
  156. package/dist/src/plugin/core/streaming/types.d.ts.map +1 -0
  157. package/dist/src/plugin/core/streaming/types.js +1 -0
  158. package/dist/src/plugin/core/streaming/types.js.map +1 -0
  159. package/dist/src/plugin/debug.d.ts +94 -0
  160. package/dist/src/plugin/debug.d.ts.map +1 -0
  161. package/dist/src/plugin/debug.js +382 -0
  162. package/dist/src/plugin/debug.js.map +1 -0
  163. package/dist/src/plugin/errors.d.ts +28 -0
  164. package/dist/src/plugin/errors.d.ts.map +1 -0
  165. package/dist/src/plugin/errors.js +42 -0
  166. package/dist/src/plugin/errors.js.map +1 -0
  167. package/dist/src/plugin/fingerprint.d.ts +70 -0
  168. package/dist/src/plugin/fingerprint.d.ts.map +1 -0
  169. package/dist/src/plugin/fingerprint.js +138 -0
  170. package/dist/src/plugin/fingerprint.js.map +1 -0
  171. package/dist/src/plugin/image-saver.d.ts +25 -0
  172. package/dist/src/plugin/image-saver.d.ts.map +1 -0
  173. package/dist/src/plugin/image-saver.js +86 -0
  174. package/dist/src/plugin/image-saver.js.map +1 -0
  175. package/dist/src/plugin/logger.d.ts +36 -0
  176. package/dist/src/plugin/logger.d.ts.map +1 -0
  177. package/dist/src/plugin/logger.js +71 -0
  178. package/dist/src/plugin/logger.js.map +1 -0
  179. package/dist/src/plugin/logging-utils.d.ts +23 -0
  180. package/dist/src/plugin/logging-utils.d.ts.map +1 -0
  181. package/dist/src/plugin/logging-utils.js +92 -0
  182. package/dist/src/plugin/logging-utils.js.map +1 -0
  183. package/dist/src/plugin/model-discovery.d.ts +28 -0
  184. package/dist/src/plugin/model-discovery.d.ts.map +1 -0
  185. package/dist/src/plugin/model-discovery.js +59 -0
  186. package/dist/src/plugin/model-discovery.js.map +1 -0
  187. package/dist/src/plugin/model-registry.d.ts +108 -0
  188. package/dist/src/plugin/model-registry.d.ts.map +1 -0
  189. package/dist/src/plugin/model-registry.js +304 -0
  190. package/dist/src/plugin/model-registry.js.map +1 -0
  191. package/dist/src/plugin/project.d.ts +33 -0
  192. package/dist/src/plugin/project.d.ts.map +1 -0
  193. package/dist/src/plugin/project.js +235 -0
  194. package/dist/src/plugin/project.js.map +1 -0
  195. package/dist/src/plugin/quota.d.ts +58 -0
  196. package/dist/src/plugin/quota.d.ts.map +1 -0
  197. package/dist/src/plugin/quota.js +296 -0
  198. package/dist/src/plugin/quota.js.map +1 -0
  199. package/dist/src/plugin/recovery/constants.d.ts +22 -0
  200. package/dist/src/plugin/recovery/constants.d.ts.map +1 -0
  201. package/dist/src/plugin/recovery/constants.js +43 -0
  202. package/dist/src/plugin/recovery/constants.js.map +1 -0
  203. package/dist/src/plugin/recovery/index.d.ts +12 -0
  204. package/dist/src/plugin/recovery/index.d.ts.map +1 -0
  205. package/dist/src/plugin/recovery/index.js +12 -0
  206. package/dist/src/plugin/recovery/index.js.map +1 -0
  207. package/dist/src/plugin/recovery/storage.d.ts +24 -0
  208. package/dist/src/plugin/recovery/storage.d.ts.map +1 -0
  209. package/dist/src/plugin/recovery/storage.js +354 -0
  210. package/dist/src/plugin/recovery/storage.js.map +1 -0
  211. package/dist/src/plugin/recovery/types.d.ts +116 -0
  212. package/dist/src/plugin/recovery/types.d.ts.map +1 -0
  213. package/dist/src/plugin/recovery/types.js +6 -0
  214. package/dist/src/plugin/recovery/types.js.map +1 -0
  215. package/dist/src/plugin/recovery.d.ts +61 -0
  216. package/dist/src/plugin/recovery.d.ts.map +1 -0
  217. package/dist/src/plugin/recovery.js +381 -0
  218. package/dist/src/plugin/recovery.js.map +1 -0
  219. package/dist/src/plugin/refresh-queue.d.ts +100 -0
  220. package/dist/src/plugin/refresh-queue.d.ts.map +1 -0
  221. package/dist/src/plugin/refresh-queue.js +247 -0
  222. package/dist/src/plugin/refresh-queue.js.map +1 -0
  223. package/dist/src/plugin/request-helpers.d.ts +282 -0
  224. package/dist/src/plugin/request-helpers.d.ts.map +1 -0
  225. package/dist/src/plugin/request-helpers.js +2343 -0
  226. package/dist/src/plugin/request-helpers.js.map +1 -0
  227. package/dist/src/plugin/request.d.ts +95 -0
  228. package/dist/src/plugin/request.d.ts.map +1 -0
  229. package/dist/src/plugin/request.js +1491 -0
  230. package/dist/src/plugin/request.js.map +1 -0
  231. package/dist/src/plugin/rotation.d.ts +169 -0
  232. package/dist/src/plugin/rotation.d.ts.map +1 -0
  233. package/dist/src/plugin/rotation.js +328 -0
  234. package/dist/src/plugin/rotation.js.map +1 -0
  235. package/dist/src/plugin/search.d.ts +32 -0
  236. package/dist/src/plugin/search.d.ts.map +1 -0
  237. package/dist/src/plugin/search.js +195 -0
  238. package/dist/src/plugin/search.js.map +1 -0
  239. package/dist/src/plugin/server.d.ts +23 -0
  240. package/dist/src/plugin/server.d.ts.map +1 -0
  241. package/dist/src/plugin/server.js +324 -0
  242. package/dist/src/plugin/server.js.map +1 -0
  243. package/dist/src/plugin/storage.d.ts +173 -0
  244. package/dist/src/plugin/storage.d.ts.map +1 -0
  245. package/dist/src/plugin/storage.js +674 -0
  246. package/dist/src/plugin/storage.js.map +1 -0
  247. package/dist/src/plugin/stores/signature-store.d.ts +5 -0
  248. package/dist/src/plugin/stores/signature-store.d.ts.map +1 -0
  249. package/dist/src/plugin/stores/signature-store.js +25 -0
  250. package/dist/src/plugin/stores/signature-store.js.map +1 -0
  251. package/dist/src/plugin/thinking-recovery.d.ts +90 -0
  252. package/dist/src/plugin/thinking-recovery.d.ts.map +1 -0
  253. package/dist/src/plugin/thinking-recovery.js +316 -0
  254. package/dist/src/plugin/thinking-recovery.js.map +1 -0
  255. package/dist/src/plugin/token.d.ts +19 -0
  256. package/dist/src/plugin/token.d.ts.map +1 -0
  257. package/dist/src/plugin/token.js +128 -0
  258. package/dist/src/plugin/token.js.map +1 -0
  259. package/dist/src/plugin/transform/claude.d.ts +80 -0
  260. package/dist/src/plugin/transform/claude.d.ts.map +1 -0
  261. package/dist/src/plugin/transform/claude.js +265 -0
  262. package/dist/src/plugin/transform/claude.js.map +1 -0
  263. package/dist/src/plugin/transform/cross-model-sanitizer.d.ts +35 -0
  264. package/dist/src/plugin/transform/cross-model-sanitizer.d.ts.map +1 -0
  265. package/dist/src/plugin/transform/cross-model-sanitizer.js +225 -0
  266. package/dist/src/plugin/transform/cross-model-sanitizer.js.map +1 -0
  267. package/dist/src/plugin/transform/gemini.d.ts +100 -0
  268. package/dist/src/plugin/transform/gemini.d.ts.map +1 -0
  269. package/dist/src/plugin/transform/gemini.js +446 -0
  270. package/dist/src/plugin/transform/gemini.js.map +1 -0
  271. package/dist/src/plugin/transform/index.d.ts +15 -0
  272. package/dist/src/plugin/transform/index.d.ts.map +1 -0
  273. package/dist/src/plugin/transform/index.js +14 -0
  274. package/dist/src/plugin/transform/index.js.map +1 -0
  275. package/dist/src/plugin/transform/model-resolver.d.ts +99 -0
  276. package/dist/src/plugin/transform/model-resolver.d.ts.map +1 -0
  277. package/dist/src/plugin/transform/model-resolver.js +340 -0
  278. package/dist/src/plugin/transform/model-resolver.js.map +1 -0
  279. package/dist/src/plugin/transform/types.d.ts +111 -0
  280. package/dist/src/plugin/transform/types.d.ts.map +1 -0
  281. package/dist/src/plugin/transform/types.js +1 -0
  282. package/dist/src/plugin/transform/types.js.map +1 -0
  283. package/dist/src/plugin/types.d.ts +97 -0
  284. package/dist/src/plugin/types.d.ts.map +1 -0
  285. package/dist/src/plugin/types.js +1 -0
  286. package/dist/src/plugin/types.js.map +1 -0
  287. package/dist/src/plugin/ui/ansi.d.ts +32 -0
  288. package/dist/src/plugin/ui/ansi.d.ts.map +1 -0
  289. package/dist/src/plugin/ui/ansi.js +52 -0
  290. package/dist/src/plugin/ui/ansi.js.map +1 -0
  291. package/dist/src/plugin/ui/auth-menu.d.ts +33 -0
  292. package/dist/src/plugin/ui/auth-menu.d.ts.map +1 -0
  293. package/dist/src/plugin/ui/auth-menu.js +110 -0
  294. package/dist/src/plugin/ui/auth-menu.js.map +1 -0
  295. package/dist/src/plugin/ui/confirm.d.ts +2 -0
  296. package/dist/src/plugin/ui/confirm.d.ts.map +1 -0
  297. package/dist/src/plugin/ui/confirm.js +15 -0
  298. package/dist/src/plugin/ui/confirm.js.map +1 -0
  299. package/dist/src/plugin/ui/select.d.ts +23 -0
  300. package/dist/src/plugin/ui/select.d.ts.map +1 -0
  301. package/dist/src/plugin/ui/select.js +254 -0
  302. package/dist/src/plugin/ui/select.js.map +1 -0
  303. package/dist/src/plugin/version.d.ts +19 -0
  304. package/dist/src/plugin/version.d.ts.map +1 -0
  305. package/dist/src/plugin/version.js +80 -0
  306. package/dist/src/plugin/version.js.map +1 -0
  307. package/dist/src/plugin.d.ts +51 -0
  308. package/dist/src/plugin.d.ts.map +1 -0
  309. package/dist/src/plugin.js +2852 -0
  310. package/dist/src/plugin.js.map +1 -0
  311. package/dist/tui.js +420 -0
  312. package/package.json +99 -6
@@ -0,0 +1,148 @@
1
+ import { randomBytes } from "node:crypto";
2
+ import { createServer } from "node:http";
3
+ import { Readable } from "node:stream";
4
+ import { createLogger } from "../plugin/logger";
5
+ const log = createLogger("opencode-v2.proxy");
6
+ /** The host the v1 request pipeline recognises and rewrites to Antigravity. */
7
+ export const UPSTREAM_ORIGIN = "https://generativelanguage.googleapis.com";
8
+ /** Request headers that describe the loopback hop rather than the upstream request. */
9
+ const DROPPED_REQUEST_HEADERS = new Set([
10
+ "host",
11
+ "connection",
12
+ "content-length",
13
+ "transfer-encoding",
14
+ "keep-alive",
15
+ "accept-encoding",
16
+ // opencode sends the OAuth access token here; the pipeline authenticates per account instead.
17
+ "x-goog-api-key",
18
+ "authorization",
19
+ ]);
20
+ /** `fetch()` already decoded the body, so these no longer describe what we write back. */
21
+ const DROPPED_RESPONSE_HEADERS = new Set([
22
+ "connection",
23
+ "content-length",
24
+ "content-encoding",
25
+ "transfer-encoding",
26
+ "keep-alive",
27
+ ]);
28
+ /** Error the handler can throw to control the HTTP status of the reply. */
29
+ export class ProxyRequestError extends Error {
30
+ status;
31
+ constructor(message, status) {
32
+ super(message);
33
+ this.status = status;
34
+ this.name = "ProxyRequestError";
35
+ }
36
+ }
37
+ /**
38
+ * opencode v2 drives Google models through its own native client, which takes a `baseURL` but no
39
+ * custom `fetch`. This loopback server sits behind that `baseURL` and hands each request to the
40
+ * v1 `fetch(url, init)` pipeline as if it were addressed to generativelanguage.googleapis.com.
41
+ *
42
+ * It listens on 127.0.0.1 only, and every path must start with a random per-process secret so
43
+ * other local processes cannot spend the signed-in accounts' quota.
44
+ */
45
+ export async function startLoopbackProxy(handler) {
46
+ const secret = randomBytes(24).toString("hex");
47
+ const prefix = `/${secret}`;
48
+ const server = createServer((req, res) => {
49
+ void handle(req, res, prefix, handler);
50
+ });
51
+ // Streaming completions can stay open for many minutes.
52
+ server.requestTimeout = 0;
53
+ server.headersTimeout = 60_000;
54
+ await new Promise((resolve, reject) => {
55
+ server.once("error", reject);
56
+ server.listen(0, "127.0.0.1", () => {
57
+ server.off("error", reject);
58
+ resolve();
59
+ });
60
+ });
61
+ server.unref();
62
+ const { port } = server.address();
63
+ log.debug("listening", { port });
64
+ return {
65
+ baseURL: `http://127.0.0.1:${port}${prefix}/v1beta`,
66
+ close: () => new Promise((resolve) => {
67
+ server.closeAllConnections();
68
+ server.close(() => resolve());
69
+ }),
70
+ };
71
+ }
72
+ async function handle(req, res, prefix, handler) {
73
+ const path = req.url ?? "/";
74
+ if (!path.startsWith(`${prefix}/`)) {
75
+ sendError(res, 404, "Not found");
76
+ return;
77
+ }
78
+ const abort = new AbortController();
79
+ res.on("close", () => {
80
+ if (!res.writableFinished)
81
+ abort.abort();
82
+ });
83
+ try {
84
+ const body = await readBody(req);
85
+ const response = await handler(`${UPSTREAM_ORIGIN}${path.slice(prefix.length)}`, {
86
+ method: req.method ?? "POST",
87
+ headers: forwardHeaders(req),
88
+ // The v1 pipeline only rewrites string bodies (Gemini requests are always JSON).
89
+ body: body.length > 0 ? body.toString("utf8") : undefined,
90
+ signal: abort.signal,
91
+ });
92
+ const headers = {};
93
+ response.headers.forEach((value, key) => {
94
+ if (!DROPPED_RESPONSE_HEADERS.has(key.toLowerCase()))
95
+ headers[key] = value;
96
+ });
97
+ res.writeHead(response.status, headers);
98
+ if (!response.body) {
99
+ res.end();
100
+ return;
101
+ }
102
+ const stream = Readable.fromWeb(response.body);
103
+ stream.on("error", (error) => {
104
+ log.warn("upstream stream failed", { error: String(error) });
105
+ res.destroy(error);
106
+ });
107
+ stream.pipe(res);
108
+ }
109
+ catch (error) {
110
+ if (abort.signal.aborted) {
111
+ res.destroy();
112
+ return;
113
+ }
114
+ const status = error instanceof ProxyRequestError ? error.status : 502;
115
+ const message = error instanceof Error ? error.message : String(error);
116
+ log.warn("request failed", { status, error: message });
117
+ if (res.headersSent) {
118
+ res.destroy();
119
+ return;
120
+ }
121
+ sendError(res, status, message);
122
+ }
123
+ }
124
+ function forwardHeaders(req) {
125
+ const headers = new Headers();
126
+ for (const [key, value] of Object.entries(req.headers)) {
127
+ if (value === undefined || DROPPED_REQUEST_HEADERS.has(key.toLowerCase()))
128
+ continue;
129
+ headers.set(key, Array.isArray(value) ? value.join(", ") : value);
130
+ }
131
+ return headers;
132
+ }
133
+ async function readBody(req) {
134
+ const chunks = [];
135
+ for await (const chunk of req) {
136
+ chunks.push(typeof chunk === "string" ? Buffer.from(chunk) : chunk);
137
+ }
138
+ return Buffer.concat(chunks);
139
+ }
140
+ /** Replies in the Gemini API error shape so opencode surfaces the message to the user. */
141
+ function sendError(res, status, message) {
142
+ const payload = JSON.stringify({
143
+ error: { code: status, message, status: status === 401 ? "UNAUTHENTICATED" : "UNAVAILABLE" },
144
+ });
145
+ res.writeHead(status, { "content-type": "application/json" });
146
+ res.end(payload);
147
+ }
148
+ //# sourceMappingURL=proxy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"proxy.js","sourceRoot":"","sources":["../../../src/opencode-v2/proxy.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ import type { QuotaAccount, QuotaLimit, QuotaWindow } from "../../rpc";
2
+ export type QuotaLevel = "ok" | "low" | "critical" | "unknown";
3
+ /** "6d 23h", "4h 48m", "12m", "now"; empty when Antigravity gave no reset time. */
4
+ export declare function formatReset(resetAt: number | null, now: number): string;
5
+ /** The windows to show for a group: "5h" first, then "wk" (weekly); missing ones are skipped. */
6
+ export declare function windowsOf(limit: QuotaLimit): Array<{
7
+ label: "5h" | "wk";
8
+ window: QuotaWindow;
9
+ }>;
10
+ export declare function formatPercent(window: QuotaWindow): string;
11
+ export declare function windowLevel(window: QuotaWindow): QuotaLevel;
12
+ /** The worst level among all of an account's windows, for its status dot. */
13
+ export declare function accountLevel(account: QuotaAccount): QuotaLevel;
14
+ /**
15
+ * The account serving the selected model's group first, then other accounts in use, then the
16
+ * remaining enabled ones, then disabled ones; stable otherwise.
17
+ */
18
+ export declare function sortAccounts(accounts: readonly QuotaAccount[], currentGroup?: string): QuotaAccount[];
19
+ //# sourceMappingURL=quota-format.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"quota-format.d.ts","sourceRoot":"","sources":["../../../src/opencode-v2/quota-format.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAEvE,MAAM,MAAM,UAAU,GAAG,IAAI,GAAG,KAAK,GAAG,UAAU,GAAG,SAAS,CAAC;AAE/D,mFAAmF;AACnF,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CASvE;AAED,iGAAiG;AACjG,wBAAgB,SAAS,CAAC,KAAK,EAAE,UAAU,GAAG,KAAK,CAAC;IAAE,KAAK,EAAE,IAAI,GAAG,IAAI,CAAC;IAAC,MAAM,EAAE,WAAW,CAAA;CAAE,CAAC,CAK/F;AAED,wBAAgB,aAAa,CAAC,MAAM,EAAE,WAAW,GAAG,MAAM,CAGzD;AAED,wBAAgB,WAAW,CAAC,MAAM,EAAE,WAAW,GAAG,UAAU,CAK3D;AAED,6EAA6E;AAC7E,wBAAgB,YAAY,CAAC,OAAO,EAAE,YAAY,GAAG,UAAU,CAU9D;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,QAAQ,EAAE,SAAS,YAAY,EAAE,EAAE,YAAY,CAAC,EAAE,MAAM,GAAG,YAAY,EAAE,CAUrG"}
@@ -0,0 +1,71 @@
1
+ /** "6d 23h", "4h 48m", "12m", "now"; empty when Antigravity gave no reset time. */
2
+ export function formatReset(resetAt, now) {
3
+ if (resetAt === null)
4
+ return "";
5
+ const minutes = Math.ceil((resetAt - now) / 60_000);
6
+ if (minutes <= 0)
7
+ return "now";
8
+ const days = Math.floor(minutes / 1440);
9
+ const hours = Math.floor((minutes % 1440) / 60);
10
+ const rest = minutes % 60;
11
+ if (days > 0)
12
+ return `${days}d ${String(hours).padStart(2, "0")}h`;
13
+ return hours > 0 ? `${hours}h ${String(rest).padStart(2, "0")}m` : `${rest}m`;
14
+ }
15
+ /** The windows to show for a group: "5h" first, then "wk" (weekly); missing ones are skipped. */
16
+ export function windowsOf(limit) {
17
+ const entries = [];
18
+ if (limit.fiveHour)
19
+ entries.push({ label: "5h", window: limit.fiveHour });
20
+ if (limit.weekly)
21
+ entries.push({ label: "wk", window: limit.weekly });
22
+ return entries;
23
+ }
24
+ export function formatPercent(window) {
25
+ if (window.remainingPercent === null)
26
+ return "?";
27
+ return `${Math.floor(window.remainingPercent)}%`;
28
+ }
29
+ export function windowLevel(window) {
30
+ if (window.remainingPercent === null)
31
+ return "unknown";
32
+ if (window.remainingPercent <= 10)
33
+ return "critical";
34
+ if (window.remainingPercent <= 30)
35
+ return "low";
36
+ return "ok";
37
+ }
38
+ /** The worst level among all of an account's windows, for its status dot. */
39
+ export function accountLevel(account) {
40
+ if (account.error || !account.enabled)
41
+ return "unknown";
42
+ const levels = account.limits
43
+ .flatMap((limit) => [limit.fiveHour, limit.weekly])
44
+ .filter((window) => window !== null)
45
+ .map(windowLevel);
46
+ if (levels.includes("critical"))
47
+ return "critical";
48
+ if (levels.includes("low"))
49
+ return "low";
50
+ if (levels.includes("ok"))
51
+ return "ok";
52
+ return "unknown";
53
+ }
54
+ /**
55
+ * The account serving the selected model's group first, then other accounts in use, then the
56
+ * remaining enabled ones, then disabled ones; stable otherwise.
57
+ */
58
+ export function sortAccounts(accounts, currentGroup) {
59
+ const rank = (account) => {
60
+ if (!account.enabled)
61
+ return 3;
62
+ if (currentGroup !== undefined && account.inUse.includes(currentGroup))
63
+ return 0;
64
+ return account.inUse.length > 0 ? 1 : 2;
65
+ };
66
+ return accounts
67
+ .map((account, index) => ({ account, index }))
68
+ .sort((a, b) => rank(a.account) - rank(b.account) || a.index - b.index)
69
+ .map(({ account }) => account);
70
+ }
71
+ //# sourceMappingURL=quota-format.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"quota-format.js","sourceRoot":"","sources":["../../../src/opencode-v2/quota-format.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ import type { QuotaAccount, QuotaSnapshot } from "../../rpc";
2
+ import { checkAccountsQuota, type AccountQuotaResult } from "../plugin/quota";
3
+ import type { PluginClient } from "../plugin/types";
4
+ type FetchQuota = typeof checkAccountsQuota;
5
+ /** "Gemini Models" → "Gemini", "Claude and GPT models" → "Claude & GPT". */
6
+ export declare function shortGroupName(displayName: string | undefined): string;
7
+ export declare function toQuotaAccount(result: AccountQuotaResult, inUse: string[]): QuotaAccount;
8
+ /**
9
+ * Builds the per-account quota snapshot the TUI sidebar shows. Results are cached for a minute
10
+ * and concurrent callers share one fetch.
11
+ */
12
+ export declare function createQuotaReporter(client: PluginClient, providerId: string, fetchQuota?: FetchQuota): {
13
+ snapshot(refresh?: boolean): Promise<QuotaSnapshot>;
14
+ /** Drops the cached snapshot after the pool changed, so the next read reflects it. */
15
+ invalidate(): void;
16
+ };
17
+ export {};
18
+ //# sourceMappingURL=quota.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"quota.d.ts","sourceRoot":"","sources":["../../../src/opencode-v2/quota.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAc,aAAa,EAAe,MAAM,WAAW,CAAC;AAEtF,OAAO,EACL,kBAAkB,EAClB,KAAK,kBAAkB,EAGxB,MAAM,iBAAiB,CAAC;AAEzB,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAOpD,KAAK,UAAU,GAAG,OAAO,kBAAkB,CAAC;AAW5C,4EAA4E;AAC5E,wBAAgB,cAAc,CAAC,WAAW,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAGtE;AAwCD,wBAAgB,cAAc,CAAC,MAAM,EAAE,kBAAkB,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,YAAY,CAkBxF;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,EAAE,UAAU,GAAE,UAA+B;iCA2B1F,OAAO,CAAC,aAAa,CAAC;IAcjD,sFAAsF;kBACxE,IAAI;EAIrB"}
@@ -0,0 +1,118 @@
1
+ import { createLogger } from "../plugin/logger";
2
+ import { checkAccountsQuota, } from "../plugin/quota";
3
+ import { loadAccounts } from "../plugin/storage";
4
+ const log = createLogger("opencode-v2.quota");
5
+ /** The shortest quota window is 5 hours; asking more than once a minute adds nothing. */
6
+ const QUOTA_CACHE_MS = 60_000;
7
+ function toPercent(fraction) {
8
+ return typeof fraction === "number" ? Math.round(fraction * 1000) / 10 : null;
9
+ }
10
+ function toTime(resetTime) {
11
+ const value = resetTime ? Date.parse(resetTime) : Number.NaN;
12
+ return Number.isFinite(value) ? value : null;
13
+ }
14
+ /** "Gemini Models" → "Gemini", "Claude and GPT models" → "Claude & GPT". */
15
+ export function shortGroupName(displayName) {
16
+ const name = (displayName ?? "Models").replace(/\s+models$/i, "").replace(/\s+and\s+/i, " & ").trim();
17
+ return name || "Models";
18
+ }
19
+ function summaryWindow(group, window) {
20
+ const bucket = group.buckets?.find((entry) => entry.window === window || entry.bucketId?.endsWith(window === "5h" ? "-5h" : "-weekly"));
21
+ if (!bucket)
22
+ return null;
23
+ return { remainingPercent: toPercent(bucket.remainingFraction), resetAt: toTime(bucket.resetTime) };
24
+ }
25
+ /** Limits from `retrieveUserQuotaSummary`: per model group, the 5-hour and the weekly window. */
26
+ function summaryLimits(groups) {
27
+ return groups.map((group) => ({
28
+ name: shortGroupName(group.displayName),
29
+ fiveHour: summaryWindow(group, "5h"),
30
+ weekly: summaryWindow(group, "weekly"),
31
+ }));
32
+ }
33
+ /**
34
+ * Fallback without the summary: per-model 5-hour quota from `fetchAvailableModels`. Gemini Pro
35
+ * and Flash draw on one bucket, so report the lower remaining and earlier reset.
36
+ */
37
+ function mergeGroups(name, groups) {
38
+ const present = groups.filter((group) => group !== undefined);
39
+ if (present.length === 0)
40
+ return undefined;
41
+ const remaining = present
42
+ .map((group) => group.remainingFraction)
43
+ .filter((value) => typeof value === "number");
44
+ const resets = present.map((group) => toTime(group.resetTime)).filter((value) => value !== null);
45
+ return {
46
+ name,
47
+ fiveHour: {
48
+ remainingPercent: remaining.length > 0 ? toPercent(Math.min(...remaining)) : null,
49
+ resetAt: resets.length > 0 ? Math.min(...resets) : null,
50
+ },
51
+ weekly: null,
52
+ };
53
+ }
54
+ export function toQuotaAccount(result, inUse) {
55
+ const groups = result.quota?.groups ?? {};
56
+ const summaryGroups = result.quotaSummary?.groups ?? [];
57
+ const limits = summaryGroups.length > 0
58
+ ? summaryLimits(summaryGroups)
59
+ : [
60
+ mergeGroups("Gemini", [groups["gemini-pro"], groups["gemini-flash"]]),
61
+ mergeGroups("Claude & GPT", [groups.claude]),
62
+ ].filter((limit) => limit !== undefined);
63
+ return {
64
+ index: result.index,
65
+ email: result.email ?? `Account ${result.index + 1}`,
66
+ enabled: !result.disabled,
67
+ inUse,
68
+ limits,
69
+ ...(result.error || result.quota?.error ? { error: result.error ?? result.quota?.error } : {}),
70
+ };
71
+ }
72
+ /**
73
+ * Builds the per-account quota snapshot the TUI sidebar shows. Results are cached for a minute
74
+ * and concurrent callers share one fetch.
75
+ */
76
+ export function createQuotaReporter(client, providerId, fetchQuota = checkAccountsQuota) {
77
+ let cached;
78
+ let pending;
79
+ const build = async () => {
80
+ const storage = await loadAccounts();
81
+ const accounts = storage?.accounts ?? [];
82
+ const results = await fetchQuota(accounts, client, providerId);
83
+ const activeGemini = storage?.activeIndexByFamily?.gemini ?? storage?.activeIndex ?? 0;
84
+ const activeClaude = storage?.activeIndexByFamily?.claude ?? storage?.activeIndex ?? 0;
85
+ const snapshot = {
86
+ fetchedAt: Date.now(),
87
+ accounts: results.map((result) => {
88
+ const inUse = result.disabled
89
+ ? []
90
+ : [result.index === activeGemini ? "Gemini" : undefined, result.index === activeClaude ? "Claude" : undefined].filter((name) => name !== undefined);
91
+ return toQuotaAccount(result, inUse);
92
+ }),
93
+ };
94
+ cached = snapshot;
95
+ return snapshot;
96
+ };
97
+ return {
98
+ snapshot(refresh = false) {
99
+ if (!refresh && cached && Date.now() - cached.fetchedAt < QUOTA_CACHE_MS) {
100
+ return Promise.resolve(cached);
101
+ }
102
+ pending ??= build()
103
+ .catch((error) => {
104
+ log.warn("quota check failed", { error: String(error) });
105
+ throw error;
106
+ })
107
+ .finally(() => {
108
+ pending = undefined;
109
+ });
110
+ return pending;
111
+ },
112
+ /** Drops the cached snapshot after the pool changed, so the next read reflects it. */
113
+ invalidate() {
114
+ cached = undefined;
115
+ },
116
+ };
117
+ }
118
+ //# sourceMappingURL=quota.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"quota.js","sourceRoot":"","sources":["../../../src/opencode-v2/quota.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,52 @@
1
+ /** What the plugin's browser or paste sign-in returns (the shape opencode's OAuth methods use). */
2
+ export type SignInAuthorization<Result> = {
3
+ mode: "auto";
4
+ url: string;
5
+ instructions: string;
6
+ callback: Promise<Result>;
7
+ /** Finishes with a pasted redirect URL when the browser could not reach the callback page. */
8
+ paste?: (code: string) => Promise<Result>;
9
+ } | {
10
+ mode: "code";
11
+ url: string;
12
+ instructions: string;
13
+ callback: (code: string) => Promise<Result>;
14
+ };
15
+ export type SignInStatus = {
16
+ status: "pending";
17
+ } | {
18
+ status: "complete";
19
+ email?: string;
20
+ } | {
21
+ status: "failed";
22
+ message: string;
23
+ } | {
24
+ status: "expired";
25
+ };
26
+ export interface SignInStart {
27
+ attemptID: string;
28
+ mode: "auto" | "code";
29
+ url: string;
30
+ instructions: string;
31
+ }
32
+ /**
33
+ * Sign-ins the plugin runs itself (re-authenticate / add account from the TUI), outside opencode's
34
+ * integration dialog: they update the plugin's account pool without creating another opencode
35
+ * login. The TUI starts an attempt, then polls it (browser) or completes it with a pasted code.
36
+ */
37
+ export declare function createSignInAttempts<Result>(options: {
38
+ start: (loginHint?: string) => Promise<SignInAuthorization<Result>>;
39
+ emailOf: (result: Result) => string | undefined;
40
+ onComplete?: () => void;
41
+ onCancel?: () => void | Promise<void>;
42
+ now?: () => number;
43
+ }): {
44
+ start(loginHint?: string): Promise<SignInStart>;
45
+ status(attemptID: string): SignInStatus;
46
+ /** Finishes a sign-in with the pasted redirect URL or code (paste mode, or browser fallback). */
47
+ complete(attemptID: string, code: string): Promise<{
48
+ email?: string;
49
+ }>;
50
+ cancel(attemptID: string): Promise<void>;
51
+ };
52
+ //# sourceMappingURL=sign-in-attempts.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sign-in-attempts.d.ts","sourceRoot":"","sources":["../../../src/opencode-v2/sign-in-attempts.ts"],"names":[],"mappings":"AAEA,mGAAmG;AACnG,MAAM,MAAM,mBAAmB,CAAC,MAAM,IAClC;IACE,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;IAC1B,8FAA8F;IAC9F,KAAK,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;CAC3C,GACD;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAA;CAAE,CAAC;AAErG,MAAM,MAAM,YAAY,GACpB;IAAE,MAAM,EAAE,SAAS,CAAA;CAAE,GACrB;IAAE,MAAM,EAAE,UAAU,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,GACtC;IAAE,MAAM,EAAE,QAAQ,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GACrC;IAAE,MAAM,EAAE,SAAS,CAAA;CAAE,CAAC;AAE1B,MAAM,WAAW,WAAW;IAC1B,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;IACtB,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,EAAE,MAAM,CAAC;CACtB;AAeD;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,OAAO,EAAE;IACpD,KAAK,EAAE,CAAC,SAAS,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,mBAAmB,CAAC,MAAM,CAAC,CAAC,CAAC;IACpE,OAAO,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,MAAM,GAAG,SAAS,CAAC;IAChD,UAAU,CAAC,EAAE,MAAM,IAAI,CAAC;IACxB,QAAQ,CAAC,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACtC,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;CACpB;sBAiB2B,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC;sBAqBnC,MAAM,GAAG,YAAY;IAOvC,iGAAiG;wBACvE,MAAM,QAAQ,MAAM,GAAG,OAAO,CAAC;QAAE,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;sBAmBpD,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;EAMjD"}
@@ -0,0 +1,81 @@
1
+ import { randomUUID } from "node:crypto";
2
+ /** Matches opencode's own limit for an unfinished sign-in. */
3
+ const ATTEMPT_TTL_MS = 10 * 60 * 1000;
4
+ function message(error) {
5
+ return error instanceof Error ? error.message : String(error);
6
+ }
7
+ /**
8
+ * Sign-ins the plugin runs itself (re-authenticate / add account from the TUI), outside opencode's
9
+ * integration dialog: they update the plugin's account pool without creating another opencode
10
+ * login. The TUI starts an attempt, then polls it (browser) or completes it with a pasted code.
11
+ */
12
+ export function createSignInAttempts(options) {
13
+ const now = options.now ?? Date.now;
14
+ const attempts = new Map();
15
+ const prune = () => {
16
+ for (const [id, attempt] of attempts) {
17
+ if (now() > attempt.expiresAt + ATTEMPT_TTL_MS)
18
+ attempts.delete(id);
19
+ }
20
+ };
21
+ const settle = (attempt, result) => {
22
+ attempt.status = { status: "complete", email: options.emailOf(result) };
23
+ options.onComplete?.();
24
+ return attempt.status;
25
+ };
26
+ return {
27
+ async start(loginHint) {
28
+ prune();
29
+ const authorization = await options.start(loginHint);
30
+ const attemptID = randomUUID();
31
+ const attempt = { authorization, status: { status: "pending" }, expiresAt: now() + ATTEMPT_TTL_MS };
32
+ attempts.set(attemptID, attempt);
33
+ if (authorization.mode === "auto") {
34
+ // Only a pending attempt changes: a pasted URL may have finished it first.
35
+ const pending = () => attempts.get(attemptID) === attempt && attempt.status.status === "pending";
36
+ authorization.callback.then((result) => {
37
+ if (pending())
38
+ settle(attempt, result);
39
+ }, (error) => {
40
+ if (pending())
41
+ attempt.status = { status: "failed", message: message(error) };
42
+ });
43
+ }
44
+ return { attemptID, mode: authorization.mode, url: authorization.url, instructions: authorization.instructions };
45
+ },
46
+ status(attemptID) {
47
+ const attempt = attempts.get(attemptID);
48
+ if (!attempt)
49
+ return { status: "expired" };
50
+ if (attempt.status.status === "pending" && now() > attempt.expiresAt)
51
+ attempt.status = { status: "expired" };
52
+ return attempt.status;
53
+ },
54
+ /** Finishes a sign-in with the pasted redirect URL or code (paste mode, or browser fallback). */
55
+ async complete(attemptID, code) {
56
+ const attempt = attempts.get(attemptID);
57
+ const finish = attempt?.authorization.mode === "code" ? attempt.authorization.callback : attempt?.authorization.paste;
58
+ if (!attempt || !finish || now() > attempt.expiresAt) {
59
+ throw new Error("This sign-in has expired. Start it again.");
60
+ }
61
+ if (attempt.status.status === "complete") {
62
+ return attempt.status.email ? { email: attempt.status.email } : {};
63
+ }
64
+ try {
65
+ const status = settle(attempt, await finish(code));
66
+ return status.status === "complete" && status.email ? { email: status.email } : {};
67
+ }
68
+ catch (error) {
69
+ attempt.status = { status: "failed", message: message(error) };
70
+ throw error;
71
+ }
72
+ },
73
+ async cancel(attemptID) {
74
+ const attempt = attempts.get(attemptID);
75
+ attempts.delete(attemptID);
76
+ if (attempt?.authorization.mode === "auto" && attempt.status.status === "pending")
77
+ await options.onCancel?.();
78
+ },
79
+ };
80
+ }
81
+ //# sourceMappingURL=sign-in-attempts.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sign-in-attempts.js","sourceRoot":"","sources":["../../../src/opencode-v2/sign-in-attempts.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Per-account model discovery.
3
+ *
4
+ * Antigravity offers different models on different plans: free accounts get Claude 4.6, paid
5
+ * Pro accounts get Claude 5.5 and Gemini 4 Argon. Each account's list is asked for separately
6
+ * and stored with the account, so request routing only picks accounts that have the requested
7
+ * model, and the catalog offers every model at least one account has.
8
+ */
9
+ import type { AccountManager } from "./accounts";
10
+ import { type AccountModelDiscovery } from "./model-discovery";
11
+ import type { PluginClient } from "./types";
12
+ /** An account to discover; `access`/`expires` skip the token refresh when still valid. */
13
+ export interface PoolModelsAccount {
14
+ refreshToken: string;
15
+ email?: string;
16
+ projectId?: string;
17
+ managedProjectId?: string;
18
+ access?: string;
19
+ expires?: number;
20
+ /** The list stored by the previous discovery, kept in the catalog if this one fails. */
21
+ availableModels?: string[];
22
+ }
23
+ export interface PoolModelsResult {
24
+ account: PoolModelsAccount;
25
+ discovery?: AccountModelDiscovery;
26
+ error?: string;
27
+ }
28
+ type Discover = (accessToken: string, projectId: string) => Promise<AccountModelDiscovery>;
29
+ /** Discovers every account's models in parallel. A failure only affects that account's result. */
30
+ export declare function discoverPoolModels(accounts: readonly PoolModelsAccount[], client: PluginClient, providerId: string, discover?: Discover): Promise<PoolModelsResult[]>;
31
+ /**
32
+ * Makes the combined list the catalog and stores each discovered account's list, on disk and in
33
+ * the running account manager. Accounts whose discovery failed keep their previous list, and
34
+ * their models stay in the catalog. Returns false when no account answered.
35
+ */
36
+ export declare function applyPoolModels(results: readonly PoolModelsResult[], manager: AccountManager | null, now?: number): Promise<boolean>;
37
+ export {};
38
+ //# sourceMappingURL=account-models.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"account-models.d.ts","sourceRoot":"","sources":["../../../src/plugin/account-models.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAGjD,OAAO,EAAyB,KAAK,qBAAqB,EAAE,MAAM,mBAAmB,CAAC;AAItF,OAAO,KAAK,EAAoB,YAAY,EAAE,MAAM,SAAS,CAAC;AAI9D,0FAA0F;AAC1F,MAAM,WAAW,iBAAiB;IAChC,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,wFAAwF;IACxF,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;CAC5B;AAED,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,iBAAiB,CAAC;IAC3B,SAAS,CAAC,EAAE,qBAAqB,CAAC;IAClC,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,KAAK,QAAQ,GAAG,CAAC,WAAW,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,KAAK,OAAO,CAAC,qBAAqB,CAAC,CAAC;AAmB3F,kGAAkG;AAClG,wBAAsB,kBAAkB,CACtC,QAAQ,EAAE,SAAS,iBAAiB,EAAE,EACtC,MAAM,EAAE,YAAY,EACpB,UAAU,EAAE,MAAM,EAClB,QAAQ,GAAE,QAAgC,GACzC,OAAO,CAAC,gBAAgB,EAAE,CAAC,CAc7B;AAQD;;;;GAIG;AACH,wBAAsB,eAAe,CACnC,OAAO,EAAE,SAAS,gBAAgB,EAAE,EACpC,OAAO,EAAE,cAAc,GAAG,IAAI,EAC9B,GAAG,GAAE,MAAmB,GACvB,OAAO,CAAC,OAAO,CAAC,CAqBlB"}