@cortexkit/opencode-antigravity-auth 1.1.0 → 2.0.0

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 (371) hide show
  1. package/README.md +225 -569
  2. package/dist/cli.js +3790 -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 +18767 -13829
  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/accounts.d.ts +7 -256
  38. package/dist/src/plugin/accounts.d.ts.map +1 -1
  39. package/dist/src/plugin/accounts.js +31 -1367
  40. package/dist/src/plugin/accounts.js.map +1 -1
  41. package/dist/src/plugin/agy-request-metadata.d.ts +1 -1
  42. package/dist/src/plugin/agy-request-metadata.js +1 -1
  43. package/dist/src/plugin/agy-transport.d.ts +1 -1
  44. package/dist/src/plugin/agy-transport.js +1 -1
  45. package/dist/src/plugin/auth-doctor.d.ts +6 -6
  46. package/dist/src/plugin/auth-doctor.d.ts.map +1 -1
  47. package/dist/src/plugin/auth-doctor.js +74 -66
  48. package/dist/src/plugin/auth-doctor.js.map +1 -1
  49. package/dist/src/plugin/auth-drift.d.ts +4 -4
  50. package/dist/src/plugin/auth-drift.d.ts.map +1 -1
  51. package/dist/src/plugin/auth-drift.js +15 -15
  52. package/dist/src/plugin/auth-drift.js.map +1 -1
  53. package/dist/src/plugin/auth-loader.d.ts +35 -0
  54. package/dist/src/plugin/auth-loader.d.ts.map +1 -0
  55. package/dist/src/plugin/auth-loader.js +144 -0
  56. package/dist/src/plugin/auth-loader.js.map +1 -0
  57. package/dist/src/plugin/auth.d.ts +1 -1
  58. package/dist/src/plugin/auth.js +1 -1
  59. package/dist/src/plugin/cache/index.d.ts +1 -1
  60. package/dist/src/plugin/cache/index.d.ts.map +1 -1
  61. package/dist/src/plugin/cache/index.js +1 -1
  62. package/dist/src/plugin/cache/index.js.map +1 -1
  63. package/dist/src/plugin/cache/signature-cache.d.ts +1 -1
  64. package/dist/src/plugin/cache/signature-cache.d.ts.map +1 -1
  65. package/dist/src/plugin/cache/signature-cache.js +23 -24
  66. package/dist/src/plugin/cache/signature-cache.js.map +1 -1
  67. package/dist/src/plugin/cache.d.ts +6 -5
  68. package/dist/src/plugin/cache.d.ts.map +1 -1
  69. package/dist/src/plugin/cache.js +21 -7
  70. package/dist/src/plugin/cache.js.map +1 -1
  71. package/dist/src/plugin/catalog.d.ts +23 -0
  72. package/dist/src/plugin/catalog.d.ts.map +1 -0
  73. package/dist/src/plugin/catalog.js +60 -0
  74. package/dist/src/plugin/catalog.js.map +1 -0
  75. package/dist/src/plugin/cli.d.ts +7 -7
  76. package/dist/src/plugin/cli.d.ts.map +1 -1
  77. package/dist/src/plugin/cli.js +62 -55
  78. package/dist/src/plugin/cli.js.map +1 -1
  79. package/dist/src/plugin/command-data.d.ts +276 -0
  80. package/dist/src/plugin/command-data.d.ts.map +1 -0
  81. package/dist/src/plugin/command-data.js +325 -0
  82. package/dist/src/plugin/command-data.js.map +1 -0
  83. package/dist/src/plugin/commands.d.ts +151 -0
  84. package/dist/src/plugin/commands.d.ts.map +1 -0
  85. package/dist/src/plugin/commands.js +639 -0
  86. package/dist/src/plugin/commands.js.map +1 -0
  87. package/dist/src/plugin/config/index.d.ts +2 -2
  88. package/dist/src/plugin/config/index.d.ts.map +1 -1
  89. package/dist/src/plugin/config/index.js +2 -2
  90. package/dist/src/plugin/config/index.js.map +1 -1
  91. package/dist/src/plugin/config/loader.d.ts +1 -1
  92. package/dist/src/plugin/config/loader.d.ts.map +1 -1
  93. package/dist/src/plugin/config/loader.js +18 -16
  94. package/dist/src/plugin/config/loader.js.map +1 -1
  95. package/dist/src/plugin/config/models.d.ts +2 -2
  96. package/dist/src/plugin/config/models.d.ts.map +1 -1
  97. package/dist/src/plugin/config/models.js +1 -1
  98. package/dist/src/plugin/config/models.js.map +1 -1
  99. package/dist/src/plugin/config/operator-settings-schema.d.ts +29 -0
  100. package/dist/src/plugin/config/operator-settings-schema.d.ts.map +1 -0
  101. package/dist/src/plugin/config/operator-settings-schema.js +28 -0
  102. package/dist/src/plugin/config/operator-settings-schema.js.map +1 -0
  103. package/dist/src/plugin/config/schema.d.ts +21 -2
  104. package/dist/src/plugin/config/schema.d.ts.map +1 -1
  105. package/dist/src/plugin/config/schema.js +85 -25
  106. package/dist/src/plugin/config/schema.js.map +1 -1
  107. package/dist/src/plugin/config/updater.d.ts.map +1 -1
  108. package/dist/src/plugin/config/updater.js +15 -15
  109. package/dist/src/plugin/config/updater.js.map +1 -1
  110. package/dist/src/plugin/config/writer.d.ts +34 -0
  111. package/dist/src/plugin/config/writer.d.ts.map +1 -0
  112. package/dist/src/plugin/config/writer.js +81 -0
  113. package/dist/src/plugin/config/writer.js.map +1 -0
  114. package/dist/src/plugin/core/streaming/index.d.ts +1 -1
  115. package/dist/src/plugin/core/streaming/index.d.ts.map +1 -1
  116. package/dist/src/plugin/core/streaming/index.js +1 -1
  117. package/dist/src/plugin/core/streaming/index.js.map +1 -1
  118. package/dist/src/plugin/core/streaming/transformer.d.ts.map +1 -1
  119. package/dist/src/plugin/core/streaming/transformer.js +85 -44
  120. package/dist/src/plugin/core/streaming/transformer.js.map +1 -1
  121. package/dist/src/plugin/core/streaming/types.d.ts.map +1 -1
  122. package/dist/src/plugin/debug.d.ts +3 -3
  123. package/dist/src/plugin/debug.d.ts.map +1 -1
  124. package/dist/src/plugin/debug.js +85 -47
  125. package/dist/src/plugin/debug.js.map +1 -1
  126. package/dist/src/plugin/dependencies.d.ts +129 -0
  127. package/dist/src/plugin/dependencies.d.ts.map +1 -0
  128. package/dist/src/plugin/dependencies.js +107 -0
  129. package/dist/src/plugin/dependencies.js.map +1 -0
  130. package/dist/src/plugin/errors.d.ts +27 -0
  131. package/dist/src/plugin/errors.d.ts.map +1 -1
  132. package/dist/src/plugin/errors.js +29 -3
  133. package/dist/src/plugin/errors.js.map +1 -1
  134. package/dist/src/plugin/event-handler.d.ts +53 -0
  135. package/dist/src/plugin/event-handler.d.ts.map +1 -0
  136. package/dist/src/plugin/event-handler.js +101 -0
  137. package/dist/src/plugin/event-handler.js.map +1 -0
  138. package/dist/src/plugin/fetch/retry-state.d.ts +61 -0
  139. package/dist/src/plugin/fetch/retry-state.d.ts.map +1 -0
  140. package/dist/src/plugin/fetch/retry-state.js +248 -0
  141. package/dist/src/plugin/fetch/retry-state.js.map +1 -0
  142. package/dist/src/plugin/fetch/warmup.d.ts +30 -0
  143. package/dist/src/plugin/fetch/warmup.d.ts.map +1 -0
  144. package/dist/src/plugin/fetch/warmup.js +76 -0
  145. package/dist/src/plugin/fetch/warmup.js.map +1 -0
  146. package/dist/src/plugin/fetch-interceptor.d.ts +59 -0
  147. package/dist/src/plugin/fetch-interceptor.d.ts.map +1 -0
  148. package/dist/src/plugin/fetch-interceptor.js +1387 -0
  149. package/dist/src/plugin/fetch-interceptor.js.map +1 -0
  150. package/dist/src/plugin/fetch-routing.d.ts +26 -0
  151. package/dist/src/plugin/fetch-routing.d.ts.map +1 -0
  152. package/dist/src/plugin/fetch-routing.js +99 -0
  153. package/dist/src/plugin/fetch-routing.js.map +1 -0
  154. package/dist/src/plugin/fingerprint.d.ts +1 -1
  155. package/dist/src/plugin/fingerprint.js +1 -1
  156. package/dist/src/plugin/gemini-dump.d.ts +5 -5
  157. package/dist/src/plugin/gemini-dump.d.ts.map +1 -1
  158. package/dist/src/plugin/gemini-dump.js +109 -55
  159. package/dist/src/plugin/gemini-dump.js.map +1 -1
  160. package/dist/src/plugin/google-search-tool.d.ts +9 -0
  161. package/dist/src/plugin/google-search-tool.d.ts.map +1 -0
  162. package/dist/src/plugin/google-search-tool.js +56 -0
  163. package/dist/src/plugin/google-search-tool.js.map +1 -0
  164. package/dist/src/plugin/image-saver.d.ts.map +1 -1
  165. package/dist/src/plugin/image-saver.js +16 -16
  166. package/dist/src/plugin/image-saver.js.map +1 -1
  167. package/dist/src/plugin/index.d.ts +23 -0
  168. package/dist/src/plugin/index.d.ts.map +1 -0
  169. package/dist/src/plugin/index.js +308 -0
  170. package/dist/src/plugin/index.js.map +1 -0
  171. package/dist/src/plugin/killswitch.d.ts +94 -0
  172. package/dist/src/plugin/killswitch.d.ts.map +1 -0
  173. package/dist/src/plugin/killswitch.js +194 -0
  174. package/dist/src/plugin/killswitch.js.map +1 -0
  175. package/dist/src/plugin/lifecycle.d.ts +40 -0
  176. package/dist/src/plugin/lifecycle.d.ts.map +1 -0
  177. package/dist/src/plugin/lifecycle.js +73 -0
  178. package/dist/src/plugin/lifecycle.js.map +1 -0
  179. package/dist/src/plugin/logger.d.ts +10 -1
  180. package/dist/src/plugin/logger.d.ts.map +1 -1
  181. package/dist/src/plugin/logger.js +38 -12
  182. package/dist/src/plugin/logger.js.map +1 -1
  183. package/dist/src/plugin/logging-utils.d.ts +35 -1
  184. package/dist/src/plugin/logging-utils.d.ts.map +1 -1
  185. package/dist/src/plugin/logging-utils.js +98 -15
  186. package/dist/src/plugin/logging-utils.js.map +1 -1
  187. package/dist/src/plugin/model-registry.d.ts +1 -1
  188. package/dist/src/plugin/model-registry.js +1 -1
  189. package/dist/src/plugin/oauth-login.d.ts +22 -0
  190. package/dist/src/plugin/oauth-login.d.ts.map +1 -0
  191. package/dist/src/plugin/oauth-login.js +37 -0
  192. package/dist/src/plugin/oauth-login.js.map +1 -0
  193. package/dist/src/plugin/oauth-methods.d.ts +42 -0
  194. package/dist/src/plugin/oauth-methods.d.ts.map +1 -0
  195. package/dist/src/plugin/oauth-methods.js +1284 -0
  196. package/dist/src/plugin/oauth-methods.js.map +1 -0
  197. package/dist/src/plugin/operator-settings.d.ts +40 -0
  198. package/dist/src/plugin/operator-settings.d.ts.map +1 -0
  199. package/dist/src/plugin/operator-settings.js +148 -0
  200. package/dist/src/plugin/operator-settings.js.map +1 -0
  201. package/dist/src/plugin/persist-account-pool.d.ts +37 -0
  202. package/dist/src/plugin/persist-account-pool.d.ts.map +1 -0
  203. package/dist/src/plugin/persist-account-pool.js +142 -0
  204. package/dist/src/plugin/persist-account-pool.js.map +1 -0
  205. package/dist/src/plugin/project.d.ts +1 -1
  206. package/dist/src/plugin/project.js +1 -1
  207. package/dist/src/plugin/prompt-context.d.ts.map +1 -1
  208. package/dist/src/plugin/prompt-context.js +11 -11
  209. package/dist/src/plugin/prompt-context.js.map +1 -1
  210. package/dist/src/plugin/quota.d.ts +97 -41
  211. package/dist/src/plugin/quota.d.ts.map +1 -1
  212. package/dist/src/plugin/quota.js +273 -285
  213. package/dist/src/plugin/quota.js.map +1 -1
  214. package/dist/src/plugin/recovery/constants.d.ts.map +1 -1
  215. package/dist/src/plugin/recovery/constants.js +24 -15
  216. package/dist/src/plugin/recovery/constants.js.map +1 -1
  217. package/dist/src/plugin/recovery/index.d.ts +3 -3
  218. package/dist/src/plugin/recovery/index.d.ts.map +1 -1
  219. package/dist/src/plugin/recovery/index.js +3 -3
  220. package/dist/src/plugin/recovery/index.js.map +1 -1
  221. package/dist/src/plugin/recovery/storage.d.ts +1 -1
  222. package/dist/src/plugin/recovery/storage.d.ts.map +1 -1
  223. package/dist/src/plugin/recovery/storage.js +31 -39
  224. package/dist/src/plugin/recovery/storage.js.map +1 -1
  225. package/dist/src/plugin/recovery/types.d.ts +12 -12
  226. package/dist/src/plugin/recovery/types.d.ts.map +1 -1
  227. package/dist/src/plugin/recovery.d.ts +3 -3
  228. package/dist/src/plugin/recovery.d.ts.map +1 -1
  229. package/dist/src/plugin/recovery.js +62 -58
  230. package/dist/src/plugin/recovery.js.map +1 -1
  231. package/dist/src/plugin/refresh-queue.d.ts +5 -2
  232. package/dist/src/plugin/refresh-queue.d.ts.map +1 -1
  233. package/dist/src/plugin/refresh-queue.js +37 -15
  234. package/dist/src/plugin/refresh-queue.js.map +1 -1
  235. package/dist/src/plugin/request-helpers.d.ts +1 -1
  236. package/dist/src/plugin/request-helpers.d.ts.map +1 -1
  237. package/dist/src/plugin/request-helpers.js +451 -352
  238. package/dist/src/plugin/request-helpers.js.map +1 -1
  239. package/dist/src/plugin/request.d.ts +7 -7
  240. package/dist/src/plugin/request.d.ts.map +1 -1
  241. package/dist/src/plugin/request.js +622 -384
  242. package/dist/src/plugin/request.js.map +1 -1
  243. package/dist/src/plugin/rotation.d.ts +1 -168
  244. package/dist/src/plugin/rotation.d.ts.map +1 -1
  245. package/dist/src/plugin/rotation.js +1 -327
  246. package/dist/src/plugin/rotation.js.map +1 -1
  247. package/dist/src/plugin/search.d.ts.map +1 -1
  248. package/dist/src/plugin/search.js +39 -35
  249. package/dist/src/plugin/search.js.map +1 -1
  250. package/dist/src/plugin/server.d.ts +1 -1
  251. package/dist/src/plugin/server.d.ts.map +1 -1
  252. package/dist/src/plugin/server.js +42 -37
  253. package/dist/src/plugin/server.js.map +1 -1
  254. package/dist/src/plugin/session-context.d.ts +2 -1
  255. package/dist/src/plugin/session-context.d.ts.map +1 -1
  256. package/dist/src/plugin/session-context.js +11 -7
  257. package/dist/src/plugin/session-context.js.map +1 -1
  258. package/dist/src/plugin/storage.d.ts +59 -120
  259. package/dist/src/plugin/storage.d.ts.map +1 -1
  260. package/dist/src/plugin/storage.js +140 -485
  261. package/dist/src/plugin/storage.js.map +1 -1
  262. package/dist/src/plugin/stores/signature-store.d.ts.map +1 -1
  263. package/dist/src/plugin/stores/signature-store.js.map +1 -1
  264. package/dist/src/plugin/thinking-recovery.d.ts.map +1 -1
  265. package/dist/src/plugin/thinking-recovery.js +35 -33
  266. package/dist/src/plugin/thinking-recovery.js.map +1 -1
  267. package/dist/src/plugin/token.d.ts +2 -2
  268. package/dist/src/plugin/token.d.ts.map +1 -1
  269. package/dist/src/plugin/token.js +30 -21
  270. package/dist/src/plugin/token.js.map +1 -1
  271. package/dist/src/plugin/transform/cross-model-sanitizer.d.ts +1 -1
  272. package/dist/src/plugin/transform/cross-model-sanitizer.js +1 -1
  273. package/dist/src/plugin/transform/index.d.ts +1 -1
  274. package/dist/src/plugin/transform/index.js +1 -1
  275. package/dist/src/plugin/transform/model-resolver.d.ts +1 -1
  276. package/dist/src/plugin/transform/model-resolver.js +1 -1
  277. package/dist/src/plugin/transform/types.d.ts +1 -1
  278. package/dist/src/plugin/transform/types.js +1 -1
  279. package/dist/src/plugin/types.d.ts +25 -69
  280. package/dist/src/plugin/types.d.ts.map +1 -1
  281. package/dist/src/plugin/ui/ansi.d.ts.map +1 -1
  282. package/dist/src/plugin/ui/ansi.js.map +1 -1
  283. package/dist/src/plugin/ui/auth-menu.d.ts +1 -1
  284. package/dist/src/plugin/ui/auth-menu.d.ts.map +1 -1
  285. package/dist/src/plugin/ui/auth-menu.js +82 -31
  286. package/dist/src/plugin/ui/auth-menu.js.map +1 -1
  287. package/dist/src/plugin/ui/confirm.d.ts.map +1 -1
  288. package/dist/src/plugin/ui/confirm.js.map +1 -1
  289. package/dist/src/plugin/ui/model-status.d.ts +3 -3
  290. package/dist/src/plugin/ui/model-status.d.ts.map +1 -1
  291. package/dist/src/plugin/ui/model-status.js +3 -3
  292. package/dist/src/plugin/ui/model-status.js.map +1 -1
  293. package/dist/src/plugin/ui/quota-status.d.ts +4 -4
  294. package/dist/src/plugin/ui/quota-status.d.ts.map +1 -1
  295. package/dist/src/plugin/ui/quota-status.js +51 -49
  296. package/dist/src/plugin/ui/quota-status.js.map +1 -1
  297. package/dist/src/plugin/ui/select.d.ts.map +1 -1
  298. package/dist/src/plugin/ui/select.js +22 -12
  299. package/dist/src/plugin/ui/select.js.map +1 -1
  300. package/dist/src/plugin/version.d.ts +1 -1
  301. package/dist/src/plugin/version.js +1 -1
  302. package/dist/src/rpc/notifications.d.ts +6 -0
  303. package/dist/src/rpc/notifications.d.ts.map +1 -0
  304. package/dist/src/rpc/notifications.js +46 -0
  305. package/dist/src/rpc/notifications.js.map +1 -0
  306. package/dist/src/rpc/port-file.d.ts +13 -0
  307. package/dist/src/rpc/port-file.d.ts.map +1 -0
  308. package/dist/src/rpc/port-file.js +109 -0
  309. package/dist/src/rpc/port-file.js.map +1 -0
  310. package/dist/src/rpc/protocol.d.ts +22 -0
  311. package/dist/src/rpc/protocol.d.ts.map +1 -0
  312. package/dist/src/rpc/protocol.js +1 -0
  313. package/dist/src/rpc/protocol.js.map +1 -0
  314. package/dist/src/rpc/rpc-client.d.ts +10 -0
  315. package/dist/src/rpc/rpc-client.d.ts.map +1 -0
  316. package/dist/src/rpc/rpc-client.js +58 -0
  317. package/dist/src/rpc/rpc-client.js.map +1 -0
  318. package/dist/src/rpc/rpc-dir.d.ts +4 -0
  319. package/dist/src/rpc/rpc-dir.d.ts.map +1 -0
  320. package/dist/src/rpc/rpc-dir.js +19 -0
  321. package/dist/src/rpc/rpc-dir.js.map +1 -0
  322. package/dist/src/rpc/rpc-server.d.ts +13 -0
  323. package/dist/src/rpc/rpc-server.d.ts.map +1 -0
  324. package/dist/src/rpc/rpc-server.js +231 -0
  325. package/dist/src/rpc/rpc-server.js.map +1 -0
  326. package/dist/src/sidebar-state.d.ts +240 -0
  327. package/dist/src/sidebar-state.d.ts.map +1 -0
  328. package/dist/src/sidebar-state.js +520 -0
  329. package/dist/src/sidebar-state.js.map +1 -0
  330. package/dist/src/tui/command-dialogs.d.ts +61 -0
  331. package/dist/src/tui/command-dialogs.d.ts.map +1 -0
  332. package/dist/src/tui/command-dialogs.js +497 -0
  333. package/dist/src/tui/command-dialogs.js.map +1 -0
  334. package/dist/src/tui/file-logger.d.ts +41 -0
  335. package/dist/src/tui/file-logger.d.ts.map +1 -0
  336. package/dist/src/tui/file-logger.js +114 -0
  337. package/dist/src/tui/file-logger.js.map +1 -0
  338. package/dist/src/tui-preferences.d.ts +40 -0
  339. package/dist/src/tui-preferences.d.ts.map +1 -0
  340. package/dist/src/tui-preferences.js +328 -0
  341. package/dist/src/tui-preferences.js.map +1 -0
  342. package/dist/src/tui.d.ts +68 -0
  343. package/dist/src/tui.d.ts.map +1 -0
  344. package/dist/src/tui.js +662 -0
  345. package/dist/src/tui.js.map +1 -0
  346. package/package.json +46 -22
  347. package/src/plugin/command-data.ts +651 -0
  348. package/src/rpc/port-file.ts +143 -0
  349. package/src/rpc/protocol.ts +31 -0
  350. package/src/rpc/rpc-client.ts +102 -0
  351. package/src/rpc/rpc-dir.ts +24 -0
  352. package/src/sidebar-state.ts +717 -0
  353. package/src/tui/command-dialogs.tsx +699 -0
  354. package/src/tui/entry.mjs +74 -0
  355. package/src/tui/file-logger.ts +145 -0
  356. package/src/tui-compiled/plugin/command-data.ts +651 -0
  357. package/src/tui-compiled/rpc/port-file.ts +143 -0
  358. package/src/tui-compiled/rpc/protocol.ts +31 -0
  359. package/src/tui-compiled/rpc/rpc-client.ts +102 -0
  360. package/src/tui-compiled/rpc/rpc-dir.ts +24 -0
  361. package/src/tui-compiled/sidebar-state.ts +717 -0
  362. package/src/tui-compiled/tui/command-dialogs.tsx +659 -0
  363. package/src/tui-compiled/tui/file-logger.ts +145 -0
  364. package/src/tui-compiled/tui-preferences.ts +416 -0
  365. package/src/tui-compiled/tui.tsx +1150 -0
  366. package/src/tui-preferences.ts +416 -0
  367. package/src/tui.tsx +1117 -0
  368. package/dist/src/plugin.d.ts +0 -48
  369. package/dist/src/plugin.d.ts.map +0 -1
  370. package/dist/src/plugin.js +0 -3311
  371. package/dist/src/plugin.js.map +0 -1
@@ -0,0 +1,699 @@
1
+ /** @jsxImportSource @opentui/solid */
2
+
3
+ /**
4
+ * Imperative command-dialog dispatcher for the /antigravity-* slash commands.
5
+ *
6
+ * Mirrors the fleet sibling layout (see `anthropic-auth-live` /
7
+ * `openai-auth-live` `packages/opencode/src/tui/command-dialogs.tsx`):
8
+ * each command's dialog opens with its data/status content rendered into the
9
+ * dialog BODY as a column of plain `<text>` nodes — non-selectable,
10
+ * non-searchable — and a separate `<DialogSelect>` below carries ONLY the
11
+ * real actions with proper `{title, description}` shapes the host renders
12
+ * on separate lines. The earlier implementation crammed the data rows into
13
+ * `DialogSelect`'s `placeholder` (which participates in type-ahead search)
14
+ * and concatenated label+description into a single highlighted option line;
15
+ * this rewrite separates data from actions the way the host expects.
16
+ *
17
+ * Contract:
18
+ * - Every main/subdialog calls `api.ui.dialog.setSize('xlarge')` before
19
+ * `api.ui.dialog.replace()` so the host reserves enough width for the
20
+ * longest line in any branch.
21
+ * - `apply(command, args, options?)` is the RPC apply path the dispatch
22
+ * site (the module-scoped poll in `tui.tsx`) supplies. The dispatcher
23
+ * forwards `options.timeoutMs` so a long-running apply (account add /
24
+ * refresh, future quota refresh) gets the right RPC timeout.
25
+ * - All `DialogSelect` options must remain VISIBLE — the host's
26
+ * `disabled: true` is a hard hide, so this file must never set it.
27
+ * Invalid actions stay visible with an explanatory description and are
28
+ * rejected in `onSelect`. The `no hide-property option scan` test in
29
+ * the verification gates pins this contract.
30
+ * - `onSelect` awaits the apply, toasts the result, then either clears
31
+ * the dialog or replaces it for multi-step flows. The dialog stack
32
+ * never sees a `clear()` between apply and re-render so the user
33
+ * always sees feedback (per the dispatcher contract).
34
+ */
35
+
36
+ import type { TuiPluginApi } from '@opencode-ai/plugin/tui'
37
+ import type { CommandAccountRow } from '../plugin/command-data'
38
+ import type { CommandModalName, OpenDialogPayload } from '../rpc/protocol'
39
+
40
+ /**
41
+ * Apply handler the dispatcher calls when the user selects a dialog
42
+ * option. Mirrors `ApplyRequest` from `rpc/protocol` plus the
43
+ * `RpcRequestOptions.timeoutMs` knob the RPC client already accepts —
44
+ * the call site in `tui.tsx` forwards these directly into
45
+ * `rpcClient.apply(request, options)`.
46
+ */
47
+ export type ApplyFn = (
48
+ command: CommandModalName,
49
+ args: string,
50
+ options?: { timeoutMs?: number },
51
+ ) => Promise<{ text: string; knobs: Record<string, unknown> }>
52
+
53
+ /**
54
+ * Mount the dialog for `payload.command` on the live TUI.
55
+ *
56
+ * The dispatcher branches on `payload.command` — each branch is
57
+ * self-contained: render the data body, render the host DialogSelect
58
+ * below it with the real actions, wire `onSelect` to await `apply(...)`,
59
+ * then toast the result and clear (or replace for multi-step flows).
60
+ * Unknown commands throw so a future command registered in
61
+ * `MODAL_COMMANDS` without a dispatcher branch fails loudly at the first
62
+ * dialog open.
63
+ */
64
+ export function openCommandDialog(
65
+ api: TuiPluginApi,
66
+ payload: OpenDialogPayload,
67
+ apply: ApplyFn,
68
+ ): void {
69
+ if (payload.command === 'antigravity-dump') {
70
+ renderDumpDialog(api, payload, apply)
71
+ return
72
+ }
73
+ if (payload.command === 'antigravity-logging') {
74
+ renderLoggingDialog(api, payload, apply)
75
+ return
76
+ }
77
+ if (payload.command === 'antigravity-quota') {
78
+ throw new Error('antigravity-quota is rendered by the TUI quota panel')
79
+ }
80
+ if (payload.command === 'antigravity-account') {
81
+ renderAccountDialog(api, payload, apply)
82
+ return
83
+ }
84
+ if (payload.command === 'antigravity-routing') {
85
+ renderRoutingDialog(api, payload, apply)
86
+ return
87
+ }
88
+ if (payload.command === 'antigravity-killswitch') {
89
+ renderKillswitchDialog(api, payload, apply)
90
+ return
91
+ }
92
+ const exhaustiveCheck: never = payload.command
93
+ throw new Error(`Unknown command ${exhaustiveCheck as string}`)
94
+ }
95
+
96
+ // ---------------------------------------------------------------------------
97
+ // Fully wired branches — non-data-first dialogs.
98
+ // ---------------------------------------------------------------------------
99
+
100
+ /**
101
+ * /antigravity-dump: three actions (on / off / status). Each selection
102
+ * applies through the RPC, toasts the result text, and clears the
103
+ * dialog. Status is a read-only check that still goes through apply so
104
+ * the dump helper runs once and reports the current state.
105
+ */
106
+ function renderDumpDialog(
107
+ api: TuiPluginApi,
108
+ _payload: OpenDialogPayload,
109
+ apply: ApplyFn,
110
+ ): void {
111
+ const DialogSelect = api.ui.DialogSelect<string>
112
+ api.ui.dialog.setSize('xlarge')
113
+ api.ui.dialog.replace(() => (
114
+ <DialogSelect
115
+ title='Antigravity wire dump'
116
+ options={[
117
+ {
118
+ title: 'Turn dump on',
119
+ value: 'on',
120
+ description: 'Write request and response bodies to the dump dir.',
121
+ },
122
+ {
123
+ title: 'Turn dump off',
124
+ value: 'off',
125
+ description: 'Stop writing new dump files.',
126
+ },
127
+ {
128
+ title: 'Show dump status',
129
+ value: 'status',
130
+ description: 'Display whether dumps are enabled and where they go.',
131
+ },
132
+ ]}
133
+ onSelect={(option) => {
134
+ void apply('antigravity-dump', String(option.value)).then((result) => {
135
+ api.ui.toast({ message: result.text })
136
+ api.ui.dialog.clear()
137
+ })
138
+ }}
139
+ />
140
+ ))
141
+ }
142
+
143
+ /**
144
+ * /antigravity-logging: every log level as an option. The dispatcher
145
+ * forwards the level as the apply arg; the apply path persists it
146
+ * through `OperatorSettingsController` and toasts the resolution text.
147
+ */
148
+ function renderLoggingDialog(
149
+ api: TuiPluginApi,
150
+ payload: OpenDialogPayload,
151
+ apply: ApplyFn,
152
+ ): void {
153
+ const DialogSelect = api.ui.DialogSelect<string>
154
+ const current = (payload.knobs.log_level as string) ?? 'info'
155
+ api.ui.dialog.setSize('xlarge')
156
+ api.ui.dialog.replace(() => (
157
+ <DialogSelect
158
+ title='Antigravity logging'
159
+ current={current}
160
+ options={[
161
+ { title: 'Error', value: 'error', description: 'Errors only.' },
162
+ { title: 'Warn', value: 'warn', description: 'Warnings and errors.' },
163
+ {
164
+ title: 'Info',
165
+ value: 'info',
166
+ description: 'Default. Includes informational events.',
167
+ },
168
+ {
169
+ title: 'Debug',
170
+ value: 'debug',
171
+ description: 'Includes debug-level events.',
172
+ },
173
+ {
174
+ title: 'Trace',
175
+ value: 'trace',
176
+ description: 'Most verbose — every diagnostic event.',
177
+ },
178
+ ]}
179
+ onSelect={(option) => {
180
+ void apply('antigravity-logging', String(option.value)).then(
181
+ (result) => {
182
+ api.ui.toast({ message: result.text })
183
+ api.ui.dialog.clear()
184
+ },
185
+ )
186
+ }}
187
+ />
188
+ ))
189
+ }
190
+
191
+ // ---------------------------------------------------------------------------
192
+ // Shared helpers — render data rows as plain text in the dialog body.
193
+ // ---------------------------------------------------------------------------
194
+
195
+ function formatQuotaRowLine(row: CommandAccountRow): string {
196
+ const status = row.enabled ? '' : ' (disabled)'
197
+ const current = row.current ? ' *' : ''
198
+ if (row.quota.length === 0) {
199
+ return `${row.label}${status}${current}: no cached quota`
200
+ }
201
+ const parts = row.quota.map((q) => {
202
+ const pct = q.remainingPercent == null ? '–%' : `${q.remainingPercent}%`
203
+ return `${q.label} ${pct}`
204
+ })
205
+ return `${row.label}${status}${current}: ${parts.join(', ')}`
206
+ }
207
+
208
+ /**
209
+ * /antigravity-account data-first dialog.
210
+ *
211
+ * The body lists each account row as a plain `<text>` node (cache-only
212
+ * — no network I/O on open). The DialogSelect carries ONLY real
213
+ * actions: Add account… and one drill-in entry per row. Drill-in
214
+ * navigates to a row-level subdialog that exposes toggle / set-current
215
+ * / remove with a DialogConfirm gate for the destructive path.
216
+ *
217
+ * Each action calls `apply('antigravity-account', '<verb> <index>')`,
218
+ * which the apply path translates into a locked-storage mutation.
219
+ * The service returns fresh `CommandAccountRow[]`; the dialog mutates
220
+ * its closed-over payload and re-renders via `renderMain()` so the
221
+ * user never sees a clear-then-redraw gap.
222
+ */
223
+ function renderAccountDialog(
224
+ api: TuiPluginApi,
225
+ initialPayload: OpenDialogPayload,
226
+ apply: ApplyFn,
227
+ ): void {
228
+ // Closed-over payload: every render reads from the latest snapshot.
229
+ const payload: OpenDialogPayload = { ...initialPayload }
230
+
231
+ const rowsFromKnobs = (): CommandAccountRow[] => {
232
+ const raw = payload.knobs.accounts
233
+ return Array.isArray(raw) ? (raw as CommandAccountRow[]) : []
234
+ }
235
+
236
+ const runApply = async (
237
+ args: string,
238
+ options?: { timeoutMs?: number },
239
+ ): Promise<CommandAccountRow[] | null> => {
240
+ const result = await apply('antigravity-account', args, options)
241
+ api.ui.toast({ message: result.text })
242
+ const next = result.knobs.accounts
243
+ if (Array.isArray(next)) {
244
+ payload.knobs = {
245
+ ...payload.knobs,
246
+ accounts: next as CommandAccountRow[],
247
+ }
248
+ renderMain()
249
+ return next as CommandAccountRow[]
250
+ }
251
+ renderMain()
252
+ return null
253
+ }
254
+
255
+ const renderManageRow = (row: CommandAccountRow): void => {
256
+ const DialogSelect = api.ui.DialogSelect<string>
257
+ api.ui.dialog.setSize('xlarge')
258
+ api.ui.dialog.replace(() => (
259
+ <box flexDirection='column' padding={1} width='100%'>
260
+ <text>{row.label}</text>
261
+ <text>
262
+ {row.quota.length === 0
263
+ ? 'no cached quota'
264
+ : row.quota
265
+ .map((q) =>
266
+ q.remainingPercent == null
267
+ ? `${q.label} –%`
268
+ : `${q.label} ${q.remainingPercent}%`,
269
+ )
270
+ .join(', ')}
271
+ </text>
272
+ <box marginTop={1}>
273
+ <DialogSelect
274
+ title={`Manage ${row.label}`}
275
+ options={[
276
+ {
277
+ title: row.enabled ? 'Disable account' : 'Enable account',
278
+ value: `toggle ${row.index}`,
279
+ description: row.enabled
280
+ ? 'Skip this account in rotation when its quota is low.'
281
+ : 'Include this account in rotation again.',
282
+ },
283
+ {
284
+ title: 'Set as current',
285
+ value: `current ${row.index}`,
286
+ description:
287
+ 'Pin this account as the active Claude + Gemini choice.',
288
+ },
289
+ {
290
+ title: 'Remove account…',
291
+ value: `__remove_prompt__ ${row.index}`,
292
+ description:
293
+ 'Permanently delete this account from the local pool.',
294
+ },
295
+ {
296
+ title: 'Back',
297
+ value: '__back__',
298
+ description: 'Return to the account list.',
299
+ },
300
+ ]}
301
+ onSelect={(option) => {
302
+ const raw = String(option.value)
303
+ if (raw === '__back__') {
304
+ renderMain()
305
+ return
306
+ }
307
+ if (raw.startsWith('__remove_prompt__ ')) {
308
+ const targetIndex = Number.parseInt(raw.split(' ')[1] ?? '', 10)
309
+ promptRemove(targetIndex)
310
+ return
311
+ }
312
+ if (raw.startsWith('toggle ') || raw.startsWith('current ')) {
313
+ void runApply(raw, { timeoutMs: 2_000 }).catch(() => {
314
+ api.ui.toast({
315
+ message: `${row.label}: action failed`,
316
+ })
317
+ })
318
+ return
319
+ }
320
+ api.ui.toast({
321
+ message: `${row.label}: unknown action`,
322
+ })
323
+ }}
324
+ />
325
+ </box>
326
+ </box>
327
+ ))
328
+ }
329
+
330
+ const promptRemove = (index: number): void => {
331
+ const DialogConfirm = api.ui.DialogConfirm
332
+ const row = rowsFromKnobs()[index]
333
+ api.ui.dialog.setSize('xlarge')
334
+ api.ui.dialog.replace(() => (
335
+ <DialogConfirm
336
+ title='Remove account'
337
+ message={`Permanently remove ${row?.label ?? `account ${index + 1}`} from the local pool? This cannot be undone.`}
338
+ onConfirm={async () => {
339
+ try {
340
+ const next = await runApply(`remove ${index}`, {
341
+ timeoutMs: 2_000,
342
+ })
343
+ if (next === null) {
344
+ renderMain()
345
+ }
346
+ } catch {
347
+ api.ui.toast({ message: 'Account remove failed' })
348
+ renderMain()
349
+ }
350
+ }}
351
+ onCancel={() => {
352
+ renderMain()
353
+ }}
354
+ />
355
+ ))
356
+ }
357
+
358
+ const renderMain = (): void => {
359
+ const DialogSelect = api.ui.DialogSelect<string>
360
+ api.ui.dialog.setSize('xlarge')
361
+ const rows = rowsFromKnobs()
362
+ const bodyLines = rows.length
363
+ ? rows.map(formatQuotaRowLine)
364
+ : ['No accounts configured. Add one via the menu below.']
365
+ api.ui.dialog.replace(() => (
366
+ <box flexDirection='column' padding={1} width='100%'>
367
+ {bodyLines.map((line) => (
368
+ <text>{line}</text>
369
+ ))}
370
+ <box marginTop={1}>
371
+ <DialogSelect
372
+ title='Antigravity accounts'
373
+ options={[
374
+ {
375
+ title: 'Add account…',
376
+ value: 'add',
377
+ description:
378
+ 'Open the OAuth flow to add a new account (120s timeout).',
379
+ },
380
+ ...rows.map((row) => ({
381
+ title: row.label,
382
+ value: `__manage__ ${row.index}`,
383
+ description: row.enabled
384
+ ? row.current
385
+ ? 'Current account — toggle, remove, or back.'
386
+ : 'Enabled — toggle, set as current, or remove.'
387
+ : 'Disabled — toggle to re-enable, or remove.',
388
+ })),
389
+ { title: 'Back', value: 'back' },
390
+ ]}
391
+ onSelect={(option) => {
392
+ const raw = String(option.value)
393
+ if (raw === 'back') {
394
+ api.ui.dialog.clear()
395
+ return
396
+ }
397
+ if (raw === 'add') {
398
+ void runApply('add', { timeoutMs: 120_000 }).catch(() => {
399
+ api.ui.toast({ message: 'Account add failed' })
400
+ })
401
+ return
402
+ }
403
+ if (raw.startsWith('__manage__ ')) {
404
+ const targetIndex = Number.parseInt(raw.split(' ')[1] ?? '', 10)
405
+ const target = rows[targetIndex]
406
+ if (target) renderManageRow(target)
407
+ return
408
+ }
409
+ api.ui.toast({ message: 'Unknown action' })
410
+ }}
411
+ />
412
+ </box>
413
+ </box>
414
+ ))
415
+ }
416
+
417
+ renderMain()
418
+ }
419
+
420
+ /**
421
+ * /antigravity-routing data-first dialog.
422
+ *
423
+ * The body lists the current persisted values (`cli_first`,
424
+ * `quota_style_fallback`) as plain `<text>` nodes so the data is
425
+ * visible without filtering the action list. The DialogSelect carries
426
+ * ONLY real toggle actions — each row flips exactly one flag, awaits
427
+ * apply, toasts the result, and re-renders in place from the
428
+ * freshly-returned state.
429
+ *
430
+ * Re-render contract mirrors the quota/account dialogs: the
431
+ * closed-over `payload.knobs` is mutated with the apply response and
432
+ * `renderMain()` is re-invoked. The dialog stack never sees a
433
+ * `clear()` between apply and re-render.
434
+ *
435
+ * Error path: when apply returns a `knobs.error === true` payload
436
+ * (lock contention, unreadable config), the dispatcher does NOT swap
437
+ * the closed-over payload — the dialog stays mounted on the previous
438
+ * state so the user can retry or back out. The error message was
439
+ * already toasted by `runApply`.
440
+ */
441
+ function renderRoutingDialog(
442
+ api: TuiPluginApi,
443
+ initialPayload: OpenDialogPayload,
444
+ apply: ApplyFn,
445
+ ): void {
446
+ // Closed-over payload: every render reads from the latest snapshot.
447
+ const payload: OpenDialogPayload = { ...initialPayload }
448
+
449
+ const readRouting = (): { cliFirst: boolean; quotaFallback: boolean } => ({
450
+ cliFirst: payload.knobs.cli_first === true,
451
+ quotaFallback: payload.knobs.quota_style_fallback === true,
452
+ })
453
+
454
+ const runApply = async (args: string): Promise<void> => {
455
+ const result = await apply('antigravity-routing', args, {
456
+ timeoutMs: 2_000,
457
+ })
458
+ api.ui.toast({ message: result.text })
459
+ if (result.knobs.error === true) {
460
+ return
461
+ }
462
+ payload.knobs = {
463
+ ...payload.knobs,
464
+ cli_first: result.knobs.cli_first,
465
+ quota_style_fallback: result.knobs.quota_style_fallback,
466
+ }
467
+ renderMain()
468
+ }
469
+
470
+ const renderMain = (): void => {
471
+ const DialogSelect = api.ui.DialogSelect<string>
472
+ api.ui.dialog.setSize('xlarge')
473
+ const { cliFirst, quotaFallback } = readRouting()
474
+ const bodyLines = [
475
+ `cli_first: ${cliFirst ? 'on' : 'off'}`,
476
+ `quota_style_fallback: ${quotaFallback ? 'on' : 'off'}`,
477
+ ]
478
+ api.ui.dialog.replace(() => (
479
+ <box flexDirection='column' padding={1} width='100%'>
480
+ {bodyLines.map((line) => (
481
+ <text>{line}</text>
482
+ ))}
483
+ <box marginTop={1}>
484
+ <DialogSelect
485
+ title='Antigravity routing'
486
+ options={[
487
+ {
488
+ title: `${cliFirst ? '●' : '○'} cli_first: ${cliFirst}`,
489
+ value: `cli_first=${!cliFirst}`,
490
+ description: cliFirst
491
+ ? 'CLI is preferred before Antigravity. Click to turn off.'
492
+ : 'Antigravity runs before CLI. Click to turn on.',
493
+ },
494
+ {
495
+ title: `${quotaFallback ? '●' : '○'} quota_style_fallback: ${quotaFallback}`,
496
+ value: `quota_style_fallback=${!quotaFallback}`,
497
+ description: quotaFallback
498
+ ? 'Falls back to the alternate quota style on exhaustion. Click to turn off.'
499
+ : 'No quota-style fallback today. Click to turn on.',
500
+ },
501
+ { title: 'Back', value: 'back' },
502
+ ]}
503
+ onSelect={(option) => {
504
+ const raw = String(option.value)
505
+ if (raw === 'back') {
506
+ api.ui.dialog.clear()
507
+ return
508
+ }
509
+ if (
510
+ !raw.startsWith('cli_first=') &&
511
+ !raw.startsWith('quota_style_fallback=')
512
+ ) {
513
+ api.ui.toast({ message: 'Unknown routing action' })
514
+ return
515
+ }
516
+ void runApply(raw).catch(() => {
517
+ api.ui.toast({ message: 'Routing update failed' })
518
+ renderMain()
519
+ })
520
+ }}
521
+ />
522
+ </box>
523
+ </box>
524
+ ))
525
+ }
526
+
527
+ renderMain()
528
+ }
529
+
530
+ /**
531
+ * /antigravity-killswitch data-first dialog.
532
+ *
533
+ * The body lists the current persisted killswitch state (`enabled`,
534
+ * `minimum_remaining_percent`, and the per-account override map) as
535
+ * plain `<text>` nodes. The DialogSelect carries ONLY real actions:
536
+ * the global enabled toggle, the threshold-edit prompt, and a Back
537
+ * affordance. The threshold edit opens a DialogPrompt for a fresh
538
+ * integer in `0..100`; out-of-range input stays at the prompt without
539
+ * applying.
540
+ *
541
+ * Re-render contract matches the routing dialog: the closed-over
542
+ * `payload.knobs` is swapped to the apply response on success and
543
+ * `renderMain()` re-runs. Errors leave the payload untouched.
544
+ */
545
+ function renderKillswitchDialog(
546
+ api: TuiPluginApi,
547
+ initialPayload: OpenDialogPayload,
548
+ apply: ApplyFn,
549
+ ): void {
550
+ const payload: OpenDialogPayload = { ...initialPayload }
551
+
552
+ const readKillswitch = (): {
553
+ enabled: boolean
554
+ minimum: number
555
+ accounts: Record<string, number>
556
+ } => {
557
+ const enabled = payload.knobs.enabled === true
558
+ const rawMin = payload.knobs.minimum_remaining_percent
559
+ const minimum =
560
+ typeof rawMin === 'number' && Number.isFinite(rawMin)
561
+ ? Math.max(0, Math.min(100, Math.round(rawMin)))
562
+ : 0
563
+ const rawAccounts = payload.knobs.accounts
564
+ const accounts =
565
+ rawAccounts &&
566
+ typeof rawAccounts === 'object' &&
567
+ !Array.isArray(rawAccounts)
568
+ ? (rawAccounts as Record<string, number>)
569
+ : {}
570
+ return { enabled, minimum, accounts }
571
+ }
572
+
573
+ const runApply = async (args: string): Promise<void> => {
574
+ const result = await apply('antigravity-killswitch', args, {
575
+ timeoutMs: 2_000,
576
+ })
577
+ api.ui.toast({ message: result.text })
578
+ if (result.knobs.error === true) {
579
+ return
580
+ }
581
+ payload.knobs = {
582
+ ...payload.knobs,
583
+ enabled: result.knobs.enabled,
584
+ minimum_remaining_percent: result.knobs.minimum_remaining_percent,
585
+ accounts: result.knobs.accounts ?? {},
586
+ }
587
+ renderMain()
588
+ }
589
+
590
+ const openThresholdPrompt = (currentMinimum: number): void => {
591
+ const DialogPrompt = api.ui.DialogPrompt
592
+ api.ui.dialog.setSize('xlarge')
593
+ api.ui.dialog.replace(() => (
594
+ <DialogPrompt
595
+ title='Antigravity killswitch — set threshold'
596
+ description={() => (
597
+ <text>
598
+ Enter a new minimum_remaining_percent (0-100). Empty input cancels.
599
+ </text>
600
+ )}
601
+ placeholder={`${currentMinimum}`}
602
+ value={`${currentMinimum}`}
603
+ onConfirm={(value: string) => {
604
+ const trimmed = value.trim()
605
+ if (!trimmed) {
606
+ renderMain()
607
+ return
608
+ }
609
+ const parsed = Number.parseInt(trimmed, 10)
610
+ if (
611
+ !Number.isInteger(parsed) ||
612
+ parsed < 0 ||
613
+ parsed > 100 ||
614
+ String(parsed) !== trimmed
615
+ ) {
616
+ api.ui.toast({
617
+ message: 'Threshold must be an integer between 0 and 100',
618
+ })
619
+ openThresholdPrompt(currentMinimum)
620
+ return
621
+ }
622
+ void runApply(`minimum_remaining_percent=${parsed}`).catch(() => {
623
+ api.ui.toast({ message: 'Killswitch update failed' })
624
+ renderMain()
625
+ })
626
+ }}
627
+ onCancel={() => {
628
+ renderMain()
629
+ }}
630
+ />
631
+ ))
632
+ }
633
+
634
+ const renderMain = (): void => {
635
+ const DialogSelect = api.ui.DialogSelect<string>
636
+ api.ui.dialog.setSize('xlarge')
637
+ const { enabled, minimum, accounts } = readKillswitch()
638
+ const accountKeys = Object.keys(accounts)
639
+ const bodyLines = [
640
+ `Killswitch: ${enabled ? 'enabled' : 'disabled'}`,
641
+ `Minimum remaining percent: ${minimum}%`,
642
+ ...(accountKeys.length > 0
643
+ ? [
644
+ 'Per-account overrides:',
645
+ ...accountKeys.map((key) => ` ${key}: ${accounts[key] ?? 0}%`),
646
+ ]
647
+ : []),
648
+ ]
649
+ api.ui.dialog.replace(() => (
650
+ <box flexDirection='column' padding={1} width='100%'>
651
+ {bodyLines.map((line) => (
652
+ <text>{line}</text>
653
+ ))}
654
+ <box marginTop={1}>
655
+ <DialogSelect
656
+ title='Antigravity killswitch'
657
+ options={[
658
+ {
659
+ title: `${enabled ? '●' : '○'} Killswitch: ${enabled ? 'enabled' : 'disabled'}`,
660
+ value: `enabled=${!enabled}`,
661
+ description: enabled
662
+ ? 'Drop candidates below the floor before dispatch. Click to turn off.'
663
+ : 'Resume candidate selection regardless of quota. Click to turn on.',
664
+ },
665
+ {
666
+ title: `Set minimum remaining percent (${minimum}%)`,
667
+ value: '__edit_threshold__',
668
+ description:
669
+ 'Prompt for a new global floor (0-100). Per-account overrides are listed above.',
670
+ },
671
+ { title: 'Back', value: 'back' },
672
+ ]}
673
+ onSelect={(option) => {
674
+ const raw = String(option.value)
675
+ if (raw === 'back') {
676
+ api.ui.dialog.clear()
677
+ return
678
+ }
679
+ if (raw === '__edit_threshold__') {
680
+ openThresholdPrompt(minimum)
681
+ return
682
+ }
683
+ if (raw === 'enabled=true' || raw === 'enabled=false') {
684
+ void runApply(raw).catch(() => {
685
+ api.ui.toast({ message: 'Killswitch update failed' })
686
+ renderMain()
687
+ })
688
+ return
689
+ }
690
+ api.ui.toast({ message: 'Unknown killswitch action' })
691
+ }}
692
+ />
693
+ </box>
694
+ </box>
695
+ ))
696
+ }
697
+
698
+ renderMain()
699
+ }