@cortexkit/opencode-antigravity-auth 3.0.0 → 3.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (148) hide show
  1. package/README.md +5 -3
  2. package/dist/cli.js +38 -33
  3. package/dist/cli.js.map +2 -2
  4. package/dist/cli.meta.json +35 -14
  5. package/dist/index.d.ts +1 -1
  6. package/dist/index.js +1916 -1436
  7. package/dist/index.js.map +4 -4
  8. package/dist/index.meta.json +154 -43
  9. package/dist/server.js +606 -104
  10. package/dist/server.js.map +4 -4
  11. package/dist/server.meta.json +1 -7284
  12. package/dist/src/cli.d.ts +1 -1
  13. package/dist/src/constants.d.ts +1 -1
  14. package/dist/src/ga/rpc/protocol.d.ts +1 -1
  15. package/dist/src/ga/server/index.d.ts +6 -6
  16. package/dist/src/ga/server/index.d.ts.map +1 -1
  17. package/dist/src/ga/server/index.js +29 -1
  18. package/dist/src/ga/server/index.js.map +1 -1
  19. package/dist/src/ga/tui/host-ga.d.ts +2 -2
  20. package/dist/src/hooks/auto-update-checker/checker.d.ts +1 -1
  21. package/dist/src/hooks/auto-update-checker/index.d.ts +4 -4
  22. package/dist/src/plugin/account-access.d.ts +6 -6
  23. package/dist/src/plugin/account-command-oauth.d.ts +2 -2
  24. package/dist/src/plugin/accounts.d.ts +3 -3
  25. package/dist/src/plugin/auth-doctor.d.ts +2 -2
  26. package/dist/src/plugin/auth-drift.d.ts +2 -2
  27. package/dist/src/plugin/auth-loader.d.ts +8 -8
  28. package/dist/src/plugin/auth-loader.d.ts.map +1 -1
  29. package/dist/src/plugin/auth-loader.js +1 -0
  30. package/dist/src/plugin/auth-loader.js.map +1 -1
  31. package/dist/src/plugin/background-quota-refresh.d.ts +3 -3
  32. package/dist/src/plugin/background-vault-quota-refresh.d.ts +43 -0
  33. package/dist/src/plugin/background-vault-quota-refresh.d.ts.map +1 -0
  34. package/dist/src/plugin/background-vault-quota-refresh.js +155 -0
  35. package/dist/src/plugin/background-vault-quota-refresh.js.map +1 -0
  36. package/dist/src/plugin/cache/index.d.ts +1 -1
  37. package/dist/src/plugin/cache/signature-cache.d.ts +2 -2
  38. package/dist/src/plugin/cache.d.ts +6 -6
  39. package/dist/src/plugin/cli.d.ts +6 -6
  40. package/dist/src/plugin/command-apply.d.ts +1 -1
  41. package/dist/src/plugin/command-data.d.ts +6 -4
  42. package/dist/src/plugin/command-data.d.ts.map +1 -1
  43. package/dist/src/plugin/command-data.js +13 -34
  44. package/dist/src/plugin/command-data.js.map +1 -1
  45. package/dist/src/plugin/commands.d.ts +4 -4
  46. package/dist/src/plugin/config/index.d.ts +2 -2
  47. package/dist/src/plugin/config/loader.d.ts +2 -2
  48. package/dist/src/plugin/config/models.d.ts +2 -2
  49. package/dist/src/plugin/config/writer.d.ts +2 -2
  50. package/dist/src/plugin/core/streaming/index.d.ts +2 -2
  51. package/dist/src/plugin/core/streaming/transformer.d.ts +1 -1
  52. package/dist/src/plugin/debug.d.ts +1 -1
  53. package/dist/src/plugin/dependencies.d.ts +3 -3
  54. package/dist/src/plugin/event-handler.d.ts +3 -3
  55. package/dist/src/plugin/fetch-interceptor.d.ts +10 -10
  56. package/dist/src/plugin/fetch-routing.d.ts +3 -3
  57. package/dist/src/plugin/ga-location-services.d.ts +10 -10
  58. package/dist/src/plugin/google-search-tool.d.ts +1 -1
  59. package/dist/src/plugin/index.d.ts +8 -6
  60. package/dist/src/plugin/index.d.ts.map +1 -1
  61. package/dist/src/plugin/index.js +41 -18
  62. package/dist/src/plugin/index.js.map +1 -1
  63. package/dist/src/plugin/killswitch.d.ts +1 -1
  64. package/dist/src/plugin/lifecycle.d.ts +2 -2
  65. package/dist/src/plugin/logger.d.ts +2 -2
  66. package/dist/src/plugin/oauth-login.d.ts +1 -1
  67. package/dist/src/plugin/oauth-methods.d.ts +9 -9
  68. package/dist/src/plugin/operator-settings.d.ts +3 -3
  69. package/dist/src/plugin/persist-account-pool.d.ts +1 -1
  70. package/dist/src/plugin/quota.d.ts +5 -4
  71. package/dist/src/plugin/quota.d.ts.map +1 -1
  72. package/dist/src/plugin/quota.js +1 -0
  73. package/dist/src/plugin/quota.js.map +1 -1
  74. package/dist/src/plugin/recovery/index.d.ts +3 -3
  75. package/dist/src/plugin/recovery/storage.d.ts +1 -1
  76. package/dist/src/plugin/recovery.d.ts +3 -3
  77. package/dist/src/plugin/refresh-queue.d.ts +3 -3
  78. package/dist/src/plugin/request-helpers.d.ts +1 -1
  79. package/dist/src/plugin/request.d.ts +9 -9
  80. package/dist/src/plugin/request.d.ts.map +1 -1
  81. package/dist/src/plugin/request.js +39 -5
  82. package/dist/src/plugin/request.js.map +1 -1
  83. package/dist/src/plugin/session-context.d.ts +1 -1
  84. package/dist/src/plugin/shared/request-services.d.ts +9 -9
  85. package/dist/src/plugin/shared/request-services.d.ts.map +1 -1
  86. package/dist/src/plugin/shared/request-services.js +13 -4
  87. package/dist/src/plugin/shared/request-services.js.map +1 -1
  88. package/dist/src/plugin/shared/runtime.d.ts +11 -11
  89. package/dist/src/plugin/shared/source-sidebar.d.ts +1 -1
  90. package/dist/src/plugin/shared/vault-menu.d.ts +1 -1
  91. package/dist/src/plugin/shared/vault-request-credentials.d.ts +3 -1
  92. package/dist/src/plugin/shared/vault-request-credentials.d.ts.map +1 -1
  93. package/dist/src/plugin/shared/vault-request-credentials.js +1 -1
  94. package/dist/src/plugin/shared/vault-request-credentials.js.map +1 -1
  95. package/dist/src/plugin/stores/signature-store.d.ts +1 -1
  96. package/dist/src/plugin/token.d.ts +1 -1
  97. package/dist/src/plugin/ui/auth-menu.d.ts +4 -4
  98. package/dist/src/plugin/ui/model-status.d.ts +3 -3
  99. package/dist/src/plugin/ui/quota-status.d.ts +2 -2
  100. package/dist/src/plugin/vault-activation.d.ts +1 -1
  101. package/dist/src/plugin/vault-quota-refresh.d.ts +7 -0
  102. package/dist/src/plugin/vault-quota-refresh.d.ts.map +1 -0
  103. package/dist/src/plugin/vault-quota-refresh.js +12 -0
  104. package/dist/src/plugin/vault-quota-refresh.js.map +1 -0
  105. package/dist/src/plugin/vault-sidebar-projection.d.ts +27 -0
  106. package/dist/src/plugin/vault-sidebar-projection.d.ts.map +1 -0
  107. package/dist/src/plugin/vault-sidebar-projection.js +34 -0
  108. package/dist/src/plugin/vault-sidebar-projection.js.map +1 -0
  109. package/dist/src/rpc/notifications.d.ts +1 -1
  110. package/dist/src/rpc/rpc-server.d.ts +1 -1
  111. package/dist/src/server.d.ts +3 -3
  112. package/dist/src/sidebar-state.d.ts +20 -13
  113. package/dist/src/sidebar-state.d.ts.map +1 -1
  114. package/dist/src/sidebar-state.js +20 -10
  115. package/dist/src/sidebar-state.js.map +1 -1
  116. package/dist/src/tui/command-dialogs.d.ts +1 -1
  117. package/dist/src/tui/host-v1.d.ts +3 -3
  118. package/dist/src/tui.d.ts +3 -3
  119. package/dist/src/tui.js +1 -1
  120. package/dist/tui-build-map.json +6 -6
  121. package/dist/types/src/ga/server/index.d.ts.map +1 -1
  122. package/dist/types/src/plugin/auth-loader.d.ts.map +1 -1
  123. package/dist/types/src/plugin/background-vault-quota-refresh.d.ts +43 -0
  124. package/dist/types/src/plugin/background-vault-quota-refresh.d.ts.map +1 -0
  125. package/dist/types/src/plugin/command-data.d.ts +6 -4
  126. package/dist/types/src/plugin/command-data.d.ts.map +1 -1
  127. package/dist/types/src/plugin/index.d.ts +2 -0
  128. package/dist/types/src/plugin/index.d.ts.map +1 -1
  129. package/dist/types/src/plugin/quota.d.ts +1 -0
  130. package/dist/types/src/plugin/quota.d.ts.map +1 -1
  131. package/dist/types/src/plugin/request.d.ts.map +1 -1
  132. package/dist/types/src/plugin/shared/request-services.d.ts.map +1 -1
  133. package/dist/types/src/plugin/shared/vault-request-credentials.d.ts +2 -0
  134. package/dist/types/src/plugin/shared/vault-request-credentials.d.ts.map +1 -1
  135. package/dist/types/src/plugin/vault-quota-refresh.d.ts +7 -0
  136. package/dist/types/src/plugin/vault-quota-refresh.d.ts.map +1 -0
  137. package/dist/types/src/plugin/vault-sidebar-projection.d.ts +27 -0
  138. package/dist/types/src/plugin/vault-sidebar-projection.d.ts.map +1 -0
  139. package/dist/types/src/sidebar-state.d.ts +20 -13
  140. package/dist/types/src/sidebar-state.d.ts.map +1 -1
  141. package/package.json +3 -3
  142. package/src/plugin/command-data.ts +19 -47
  143. package/src/sidebar-state.ts +34 -15
  144. package/src/tui-compiled/sidebar-state.js +12 -5
  145. package/src/tui-compiled/tui.js +1 -1
  146. package/src/tui-raw/sidebar-state.js +12 -5
  147. package/src/tui-raw/tui.tsx +1 -1
  148. package/src/tui.tsx +1 -1
package/dist/index.js CHANGED
@@ -14082,7 +14082,8 @@ function jsonBytes(bytes) {
14082
14082
  }
14083
14083
  async function syncFile(path5) {
14084
14084
  await secureRead(path5);
14085
- const handle = await open(path5, constants.O_RDONLY | constants.O_NOFOLLOW);
14085
+ const access = process.platform === "win32" ? constants.O_RDWR : constants.O_RDONLY;
14086
+ const handle = await open(path5, access | constants.O_NOFOLLOW);
14086
14087
  try {
14087
14088
  await handle.sync();
14088
14089
  } finally {
@@ -17197,8 +17198,8 @@ function createAccountRepositoryFactory(modules, factoryOptions = {}) {
17197
17198
 
17198
17199
  // ../core/dist/fingerprint.js
17199
17200
  import * as crypto from "node:crypto";
17200
- var AGY_CLI_VERSION = "1.1.24";
17201
- var AGY_CLI_CHANGE_LIST = "974782877";
17201
+ var AGY_CLI_VERSION = "1.3.3";
17202
+ var AGY_CLI_CHANGE_LIST = "996823801";
17202
17203
  var ANTIGRAVITY_API_CLIENT = "antigravity-cli";
17203
17204
  var MAX_FINGERPRINT_HISTORY = 5;
17204
17205
  function normalizeHarnessPlatform(platform = process.platform) {
@@ -17270,7 +17271,7 @@ function buildFingerprintHeaders(fingerprint) {
17270
17271
  return {};
17271
17272
  }
17272
17273
  return {
17273
- "User-Agent": fingerprint.userAgent
17274
+ "User-Agent": buildAntigravityHarnessUserAgent()
17274
17275
  };
17275
17276
  }
17276
17277
  var sessionFingerprint = null;
@@ -17301,7 +17302,227 @@ function defineModel(id, model) {
17301
17302
  ...model
17302
17303
  };
17303
17304
  }
17305
+ var AGY_NATIVE_MODEL_DEFINITIONS = {
17306
+ "gemini-3.8-flash-high": {
17307
+ displayName: "Gemini 3.8 Flash (High)",
17308
+ maxTokens: 1048576,
17309
+ maxOutputTokens: 65536,
17310
+ model: "MODEL_PLACEHOLDER_M318",
17311
+ thinkingBudget: -1,
17312
+ supportsThinking: true
17313
+ },
17314
+ "gemini-3.8-flash-medium": {
17315
+ displayName: "Gemini 3.8 Flash (Medium)",
17316
+ maxTokens: 1048576,
17317
+ maxOutputTokens: 65536,
17318
+ model: "MODEL_PLACEHOLDER_M319",
17319
+ thinkingBudget: 4e3,
17320
+ supportsThinking: true
17321
+ },
17322
+ "gemini-3.8-flash-low": {
17323
+ displayName: "Gemini 3.8 Flash (Low)",
17324
+ maxTokens: 1048576,
17325
+ maxOutputTokens: 65536,
17326
+ model: "MODEL_PLACEHOLDER_M320",
17327
+ thinkingBudget: 1e3,
17328
+ supportsThinking: true
17329
+ },
17330
+ "gemini-3.7-flash-high": {
17331
+ displayName: "Gemini 3.7 Flash (High)",
17332
+ maxTokens: 1048576,
17333
+ maxOutputTokens: 65536,
17334
+ model: "MODEL_PLACEHOLDER_M298",
17335
+ thinkingBudget: -1,
17336
+ supportsThinking: true
17337
+ },
17338
+ "gemini-3.7-flash-medium": {
17339
+ displayName: "Gemini 3.7 Flash (Medium)",
17340
+ maxTokens: 1048576,
17341
+ maxOutputTokens: 65536,
17342
+ model: "MODEL_PLACEHOLDER_M299",
17343
+ thinkingBudget: 4e3,
17344
+ supportsThinking: true
17345
+ },
17346
+ "gemini-3.7-flash-low": {
17347
+ displayName: "Gemini 3.7 Flash (Low)",
17348
+ maxTokens: 1048576,
17349
+ maxOutputTokens: 65536,
17350
+ model: "MODEL_PLACEHOLDER_M300",
17351
+ thinkingBudget: 1e3,
17352
+ supportsThinking: true
17353
+ },
17354
+ "gemini-3.6-flash-high": {
17355
+ displayName: "Gemini 3.6 Flash (High)",
17356
+ maxTokens: 1048576,
17357
+ maxOutputTokens: 65536,
17358
+ model: "MODEL_PLACEHOLDER_M71",
17359
+ thinkingBudget: -1,
17360
+ supportsThinking: true
17361
+ },
17362
+ "gemini-3.6-flash-medium": {
17363
+ displayName: "Gemini 3.6 Flash (Medium)",
17364
+ maxTokens: 1048576,
17365
+ maxOutputTokens: 65536,
17366
+ model: "MODEL_PLACEHOLDER_M72",
17367
+ thinkingBudget: 4e3,
17368
+ supportsThinking: true
17369
+ },
17370
+ "gemini-3.6-flash-low": {
17371
+ displayName: "Gemini 3.6 Flash (Low)",
17372
+ maxTokens: 1048576,
17373
+ maxOutputTokens: 65536,
17374
+ model: "MODEL_PLACEHOLDER_M73",
17375
+ thinkingBudget: 1e3,
17376
+ supportsThinking: true
17377
+ },
17378
+ "gemini-3.1-pro-high": {
17379
+ displayName: "Gemini 3.1 Pro (High)",
17380
+ maxTokens: 1048576,
17381
+ maxOutputTokens: 65535,
17382
+ model: "MODEL_PLACEHOLDER_M37",
17383
+ thinkingBudget: 10001,
17384
+ supportsThinking: true
17385
+ },
17386
+ "gemini-3.1-pro-low": {
17387
+ displayName: "Gemini 3.1 Pro (Low)",
17388
+ maxTokens: 1048576,
17389
+ maxOutputTokens: 65535,
17390
+ model: "MODEL_PLACEHOLDER_M36",
17391
+ thinkingBudget: 1001,
17392
+ supportsThinking: true
17393
+ },
17394
+ "claude-opus-5-5-low": {
17395
+ displayName: "Claude Opus 5.5 (Low)",
17396
+ maxTokens: 1e6,
17397
+ maxOutputTokens: 128e3,
17398
+ model: "MODEL_PLACEHOLDER_M400",
17399
+ thinkingLevel: 1,
17400
+ supportsThinking: true,
17401
+ supportsAdaptiveThinking: true,
17402
+ vertexModelId: "claude-opus-5-5@default"
17403
+ },
17404
+ "claude-opus-5-5-medium": {
17405
+ displayName: "Claude Opus 5.5 (Medium)",
17406
+ maxTokens: 1e6,
17407
+ maxOutputTokens: 128e3,
17408
+ model: "MODEL_PLACEHOLDER_M401",
17409
+ thinkingLevel: 2,
17410
+ supportsThinking: true,
17411
+ supportsAdaptiveThinking: true,
17412
+ vertexModelId: "claude-opus-5-5@default"
17413
+ },
17414
+ "claude-opus-5-5-high": {
17415
+ displayName: "Claude Opus 5.5 (High)",
17416
+ maxTokens: 1e6,
17417
+ maxOutputTokens: 128e3,
17418
+ model: "MODEL_PLACEHOLDER_M402",
17419
+ thinkingLevel: 3,
17420
+ supportsThinking: true,
17421
+ supportsAdaptiveThinking: true,
17422
+ vertexModelId: "claude-opus-5-5@default"
17423
+ },
17424
+ "claude-sonnet-5-5-low": {
17425
+ displayName: "Claude Sonnet 5.5 (Low)",
17426
+ maxTokens: 1e6,
17427
+ maxOutputTokens: 128e3,
17428
+ model: "MODEL_PLACEHOLDER_M403",
17429
+ thinkingLevel: 1,
17430
+ supportsThinking: true,
17431
+ supportsAdaptiveThinking: true,
17432
+ vertexModelId: "claude-sonnet-5-5@default"
17433
+ },
17434
+ "claude-sonnet-5-5-medium": {
17435
+ displayName: "Claude Sonnet 5.5 (Medium)",
17436
+ maxTokens: 1e6,
17437
+ maxOutputTokens: 128e3,
17438
+ model: "MODEL_PLACEHOLDER_M404",
17439
+ thinkingLevel: 2,
17440
+ supportsThinking: true,
17441
+ supportsAdaptiveThinking: true,
17442
+ vertexModelId: "claude-sonnet-5-5@default"
17443
+ },
17444
+ "claude-sonnet-5-5-high": {
17445
+ displayName: "Claude Sonnet 5.5 (High)",
17446
+ maxTokens: 1e6,
17447
+ maxOutputTokens: 128e3,
17448
+ model: "MODEL_PLACEHOLDER_M405",
17449
+ thinkingLevel: 3,
17450
+ supportsThinking: true,
17451
+ supportsAdaptiveThinking: true,
17452
+ vertexModelId: "claude-sonnet-5-5@default"
17453
+ },
17454
+ "gpt-oss-120b-medium": {
17455
+ displayName: "GPT-OSS 120B (Medium)",
17456
+ maxTokens: 131072,
17457
+ maxOutputTokens: 32768,
17458
+ model: "MODEL_OPENAI_GPT_OSS_120B_MEDIUM",
17459
+ thinkingBudget: 8192,
17460
+ supportsThinking: true,
17461
+ vertexModelId: "openai/gpt-oss-120b-maas"
17462
+ },
17463
+ "gemini-3.5-flash-extra-low": {
17464
+ displayName: "Gemini 3.5 Flash (Low)",
17465
+ maxTokens: 1048576,
17466
+ maxOutputTokens: 65536,
17467
+ model: "MODEL_PLACEHOLDER_M187",
17468
+ thinkingBudget: 1e3,
17469
+ supportsThinking: true
17470
+ },
17471
+ "gemini-3.5-flash-low": {
17472
+ displayName: "Gemini 3.5 Flash (Medium)",
17473
+ maxTokens: 1048576,
17474
+ maxOutputTokens: 65536,
17475
+ model: "MODEL_PLACEHOLDER_M20",
17476
+ thinkingBudget: 4e3,
17477
+ supportsThinking: true
17478
+ },
17479
+ "gemini-3-flash-agent": {
17480
+ displayName: "Gemini 3.5 Flash (High)",
17481
+ maxTokens: 1048576,
17482
+ maxOutputTokens: 65536,
17483
+ model: "MODEL_PLACEHOLDER_M84",
17484
+ thinkingBudget: -1,
17485
+ supportsThinking: true
17486
+ },
17487
+ "gemini-3.1-flash-image": {
17488
+ displayName: "Gemini 3.1 Flash Image",
17489
+ model: "MODEL_PLACEHOLDER_M21"
17490
+ },
17491
+ "gemini-pro-agent": {
17492
+ displayName: "Gemini 3.1 Pro (High)",
17493
+ maxTokens: 1048576,
17494
+ maxOutputTokens: 65535,
17495
+ model: "MODEL_PLACEHOLDER_M16",
17496
+ thinkingBudget: 10001,
17497
+ supportsThinking: true
17498
+ }
17499
+ };
17500
+ function getAgyNativeModel(model) {
17501
+ return AGY_NATIVE_MODEL_DEFINITIONS[model.toLowerCase()];
17502
+ }
17503
+ var RETIRED_AGY_MODEL_MESSAGE = "This Antigravity model is no longer offered. Choose another model.";
17504
+ function isRetiredAgyModel(model) {
17505
+ const route = model.toLowerCase().replace(/^antigravity-/, "").replace(/^gemini-(?=claude-)/, "");
17506
+ return /^claude-(opus|sonnet)-4-6(?:-thinking)?(?:-(?:minimal|low|medium|high))?$/.test(route) && getAgyNativeModel(route) === void 0;
17507
+ }
17304
17508
  var ALL_MODEL_DEFINITIONS = {
17509
+ "antigravity-gemini-3.5-flash": defineModel("antigravity-gemini-3.5-flash", {
17510
+ name: "Gemini 3.5 Flash (Antigravity)",
17511
+ reasoning: true,
17512
+ limit: { context: 1048576, output: 65536 },
17513
+ modalities: DEFAULT_MODALITIES,
17514
+ variants: {
17515
+ low: { thinkingLevel: "low" },
17516
+ medium: { thinkingLevel: "medium" },
17517
+ high: { thinkingLevel: "high" }
17518
+ }
17519
+ }),
17520
+ "antigravity-gemini-3.1-flash-image": defineModel("antigravity-gemini-3.1-flash-image", {
17521
+ name: "Gemini 3.1 Flash Image (Antigravity)",
17522
+ reasoning: false,
17523
+ limit: { context: 66e3, output: 33e3 },
17524
+ modalities: { input: ["text", "image"], output: ["text", "image"] }
17525
+ }),
17305
17526
  "antigravity-gemini-3.1-pro": defineModel("antigravity-gemini-3.1-pro", {
17306
17527
  name: "Gemini 3.1 Pro (Antigravity)",
17307
17528
  reasoning: true,
@@ -17319,6 +17540,7 @@ var ALL_MODEL_DEFINITIONS = {
17319
17540
  modalities: DEFAULT_MODALITIES,
17320
17541
  variants: {
17321
17542
  low: { thinkingLevel: "low" },
17543
+ medium: { thinkingLevel: "medium" },
17322
17544
  high: { thinkingLevel: "high" }
17323
17545
  }
17324
17546
  }),
@@ -17329,6 +17551,7 @@ var ALL_MODEL_DEFINITIONS = {
17329
17551
  modalities: DEFAULT_MODALITIES,
17330
17552
  variants: {
17331
17553
  low: { thinkingLevel: "low" },
17554
+ medium: { thinkingLevel: "medium" },
17332
17555
  high: { thinkingLevel: "high" }
17333
17556
  }
17334
17557
  }),
@@ -17339,46 +17562,30 @@ var ALL_MODEL_DEFINITIONS = {
17339
17562
  modalities: DEFAULT_MODALITIES,
17340
17563
  variants: {
17341
17564
  low: { thinkingLevel: "low" },
17565
+ medium: { thinkingLevel: "medium" },
17342
17566
  high: { thinkingLevel: "high" }
17343
17567
  }
17344
17568
  }),
17345
- "antigravity-gemini-3.5-flash": defineModel("antigravity-gemini-3.5-flash", {
17346
- name: "Gemini 3.5 Flash (Antigravity)",
17569
+ "antigravity-claude-sonnet-5-5": defineModel("antigravity-claude-sonnet-5-5", {
17570
+ name: "Claude Sonnet 5.5 (Antigravity)",
17347
17571
  reasoning: true,
17348
- limit: { context: 1048576, output: 65536 },
17572
+ limit: { context: 1e6, output: 128e3 },
17349
17573
  modalities: DEFAULT_MODALITIES,
17350
17574
  variants: {
17351
17575
  low: { thinkingLevel: "low" },
17576
+ medium: { thinkingLevel: "medium" },
17352
17577
  high: { thinkingLevel: "high" }
17353
17578
  }
17354
17579
  }),
17355
- "antigravity-claude-sonnet-4-6-thinking": defineModel("antigravity-claude-sonnet-4-6-thinking", {
17356
- name: "Claude Sonnet 4.6 Thinking (Antigravity)",
17357
- reasoning: true,
17358
- limit: { context: 25e4, output: 64e3 },
17359
- modalities: DEFAULT_MODALITIES,
17360
- variants: {
17361
- low: { disabled: true },
17362
- high: { disabled: true }
17363
- }
17364
- }),
17365
- "antigravity-claude-opus-4-6-thinking": defineModel("antigravity-claude-opus-4-6-thinking", {
17366
- name: "Claude Opus 4.6 Thinking (Antigravity)",
17580
+ "antigravity-claude-opus-5-5": defineModel("antigravity-claude-opus-5-5", {
17581
+ name: "Claude Opus 5.5 (Antigravity)",
17367
17582
  reasoning: true,
17368
- limit: { context: 25e4, output: 64e3 },
17583
+ limit: { context: 1e6, output: 128e3 },
17369
17584
  modalities: DEFAULT_MODALITIES,
17370
17585
  variants: {
17371
- low: { disabled: true },
17372
- high: { disabled: true }
17373
- }
17374
- }),
17375
- "antigravity-gemini-3.1-flash-image": defineModel("antigravity-gemini-3.1-flash-image", {
17376
- name: "Gemini 3.1 Flash Image (Antigravity)",
17377
- reasoning: false,
17378
- limit: { context: 66e3, output: 33e3 },
17379
- modalities: {
17380
- input: ["text", "image"],
17381
- output: ["text", "image"]
17586
+ low: { thinkingLevel: "low" },
17587
+ medium: { thinkingLevel: "medium" },
17588
+ high: { thinkingLevel: "high" }
17382
17589
  }
17383
17590
  }),
17384
17591
  "antigravity-gpt-oss-120b-medium": defineModel("antigravity-gpt-oss-120b-medium", {
@@ -17460,6 +17667,7 @@ var RESOLVER_ALIASES = {
17460
17667
  "gemini-3.8-flash-low": "gemini-3.8-flash",
17461
17668
  "gemini-3.8-flash-medium": "gemini-3.8-flash",
17462
17669
  "gemini-3.8-flash-high": "gemini-3.8-flash",
17670
+ // Historical parsing does not authorize serving: admission rejects retired routes.
17463
17671
  "gemini-claude-opus-4-6-thinking-low": "claude-opus-4-6-thinking",
17464
17672
  "gemini-claude-opus-4-6-thinking-medium": "claude-opus-4-6-thinking",
17465
17673
  "gemini-claude-opus-4-6-thinking-high": "claude-opus-4-6-thinking",
@@ -17542,10 +17750,10 @@ var ANTIGRAVITY_OPENCODE_MODEL_IDS = [
17542
17750
  "antigravity-gemini-3.7-flash",
17543
17751
  "antigravity-gemini-3.6-flash",
17544
17752
  "antigravity-gemini-3.5-flash",
17545
- "antigravity-gemini-3.1-pro",
17546
- "antigravity-claude-sonnet-4-6-thinking",
17547
- "antigravity-claude-opus-4-6-thinking",
17548
17753
  "antigravity-gemini-3.1-flash-image",
17754
+ "antigravity-gemini-3.1-pro",
17755
+ "antigravity-claude-sonnet-5-5",
17756
+ "antigravity-claude-opus-5-5",
17549
17757
  "antigravity-gpt-oss-120b-medium"
17550
17758
  ];
17551
17759
  function pickModelDefinitions(ids) {
@@ -21440,26 +21648,6 @@ var AGY_REQUEST_FIELD_ORDER = [
21440
21648
  "generationConfig",
21441
21649
  "sessionId"
21442
21650
  ];
21443
- var AGY_MODEL_ENUM_BY_WIRE_MODEL = {
21444
- "gemini-3.5-flash-extra-low": "MODEL_PLACEHOLDER_M187",
21445
- "gemini-3.5-flash-low": "MODEL_PLACEHOLDER_M20",
21446
- "gemini-3-flash-agent": "MODEL_PLACEHOLDER_M84",
21447
- "gemini-3.6-flash-low": "MODEL_PLACEHOLDER_M73",
21448
- "gemini-3.6-flash-medium": "MODEL_PLACEHOLDER_M72",
21449
- "gemini-3.6-flash-high": "MODEL_PLACEHOLDER_M71",
21450
- "gemini-3.7-flash-low": "MODEL_PLACEHOLDER_M300",
21451
- "gemini-3.7-flash-medium": "MODEL_PLACEHOLDER_M299",
21452
- "gemini-3.7-flash-high": "MODEL_PLACEHOLDER_M298",
21453
- "gemini-3.8-flash-low": "MODEL_PLACEHOLDER_M320",
21454
- "gemini-3.8-flash-medium": "MODEL_PLACEHOLDER_M319",
21455
- "gemini-3.8-flash-high": "MODEL_PLACEHOLDER_M318",
21456
- "gemini-3.1-pro-low": "MODEL_PLACEHOLDER_M36",
21457
- "gemini-pro-agent": "MODEL_PLACEHOLDER_M16",
21458
- "claude-sonnet-4-6": "MODEL_PLACEHOLDER_M35",
21459
- "claude-opus-4-6-thinking": "MODEL_PLACEHOLDER_M26",
21460
- "gemini-3.1-flash-image": "MODEL_PLACEHOLDER_M21",
21461
- "gpt-oss-120b-medium": "MODEL_OPENAI_GPT_OSS_120B_MEDIUM"
21462
- };
21463
21651
  function fnv1a64Signed(input2) {
21464
21652
  let hash2 = FNV1A_64_OFFSET_BASIS;
21465
21653
  for (const byte of Buffer2.from(input2, "utf8")) {
@@ -21551,8 +21739,13 @@ var AgyRequestSessionStore = class {
21551
21739
  }
21552
21740
  }
21553
21741
  };
21742
+ var HISTORICAL_AGY_MODEL_ENUMS = {
21743
+ "claude-sonnet-4-6": "MODEL_PLACEHOLDER_M35",
21744
+ "claude-opus-4-6-thinking": "MODEL_PLACEHOLDER_M26"
21745
+ };
21554
21746
  function getAgyModelEnum(model) {
21555
- return AGY_MODEL_ENUM_BY_WIRE_MODEL[model.toLowerCase()];
21747
+ const lower = model.toLowerCase();
21748
+ return getAgyNativeModel(lower)?.model ?? HISTORICAL_AGY_MODEL_ENUMS[lower];
21556
21749
  }
21557
21750
  function orderAgyRequestPayloadInPlace(payload) {
21558
21751
  const ordered = {};
@@ -23972,6 +24165,30 @@ async function defaultTransport(url, init, options) {
23972
24165
  return fetchWithActiveTimeout(url, init, { timeoutMs: options.timeoutMs });
23973
24166
  }
23974
24167
 
24168
+ // ../core/dist/transform/agy-generation.js
24169
+ var ADAPTIVE_LEVELS = {
24170
+ 1: "LOW",
24171
+ 2: "MEDIUM",
24172
+ 3: "HIGH"
24173
+ };
24174
+ function applyAgyNativeGenerationConfig(wireModel, generationConfig) {
24175
+ const native = getAgyNativeModel(wireModel);
24176
+ if (!native)
24177
+ return;
24178
+ const output2 = generationConfig.max_output_tokens ?? native.maxOutputTokens;
24179
+ if (generationConfig.maxOutputTokens === void 0 && output2 !== void 0) {
24180
+ generationConfig.maxOutputTokens = output2;
24181
+ }
24182
+ delete generationConfig.max_output_tokens;
24183
+ if (native.supportsAdaptiveThinking && native.thinkingLevel !== void 0) {
24184
+ generationConfig.thinkingConfig = {
24185
+ includeThoughts: true,
24186
+ thinkingBudget: 0,
24187
+ thinkingLevel: ADAPTIVE_LEVELS[native.thinkingLevel]
24188
+ };
24189
+ }
24190
+ }
24191
+
23975
24192
  // ../core/dist/transform/claude.js
23976
24193
  var CLAUDE_THINKING_MAX_OUTPUT_TOKENS = 64e3;
23977
24194
  function computeClaudeMaxOutputTokens(thinkingBudget) {
@@ -23986,7 +24203,7 @@ function isClaudeModel(model) {
23986
24203
  }
23987
24204
  function isClaudeThinkingModel(model) {
23988
24205
  const lower = model.toLowerCase();
23989
- return lower.includes("claude") && (lower.includes("thinking") || lower.endsWith("claude-sonnet-4-6"));
24206
+ return lower.includes("claude") && (lower.includes("thinking") || lower.endsWith("claude-sonnet-4-6") || /claude-(opus|sonnet)-5-5(?:-(low|medium|high))?$/.test(lower));
23990
24207
  }
23991
24208
  function appendClaudeThinkingHint(payload, hint = CLAUDE_INTERLEAVED_THINKING_HINT) {
23992
24209
  const existing = payload.systemInstruction;
@@ -24487,7 +24704,7 @@ var GEMINI_3_FLASH_REGEX = /^gemini-3(?:\.\d+)?-flash/i;
24487
24704
  var IMAGE_GENERATION_MODELS = /image|imagen/i;
24488
24705
  function supportsThinkingTiers(model) {
24489
24706
  const lower = model.toLowerCase();
24490
- return lower.includes("gemini-3") || lower.includes("gemini-2.5") || lower.includes("claude") && lower.includes("thinking");
24707
+ return lower.includes("gemini-3") || lower.includes("gemini-2.5") || lower.includes("claude") && (lower.includes("thinking") || /^claude-(opus|sonnet)-5-5/.test(lower));
24491
24708
  }
24492
24709
  function extractThinkingTierFromModel(model) {
24493
24710
  if (!supportsThinkingTiers(model)) {
@@ -24524,7 +24741,7 @@ function isGemini35FlashModel(model) {
24524
24741
  function resolveGemini35FlashAntigravityModel(tier) {
24525
24742
  return getGemini35FlashAntigravityModel(tier);
24526
24743
  }
24527
- function getAgyGeminiFlashThinkingBudget(tier, highBudget = 1e4) {
24744
+ function getAgyGeminiFlashThinkingBudget(tier, highBudget = -1) {
24528
24745
  switch (tier) {
24529
24746
  case "low":
24530
24747
  return 1e3;
@@ -24535,7 +24752,7 @@ function getAgyGeminiFlashThinkingBudget(tier, highBudget = 1e4) {
24535
24752
  }
24536
24753
  }
24537
24754
  function getAgyGemini31ProModel(tier) {
24538
- return tier === "high" ? "gemini-pro-agent" : "gemini-3.1-pro-low";
24755
+ return tier === "high" ? "gemini-3.1-pro-high" : "gemini-3.1-pro-low";
24539
24756
  }
24540
24757
  function getAgyGemini31ProThinkingBudget(tier) {
24541
24758
  return tier === "high" ? 10001 : 1001;
@@ -24550,6 +24767,29 @@ function resolveModelWithTier(requestedModel, options = {}) {
24550
24767
  const preferGeminiCli = options.cli_first === true && !isAntigravity && !isImageModel && !isClaudeModel2;
24551
24768
  const quotaPreference = preferGeminiCli ? "gemini-cli" : "antigravity";
24552
24769
  const explicitQuota = isAntigravity || isImageModel;
24770
+ const native = getAgyNativeModel(modelWithoutQuota);
24771
+ const groupedGemini35Tier = isAntigravity && /^gemini-3\.5-flash-(low|medium|high)$/i.test(modelWithoutQuota);
24772
+ if (native && quotaPreference === "antigravity" && !groupedGemini35Tier) {
24773
+ return {
24774
+ actualModel: modelWithoutQuota,
24775
+ thinkingBudget: native.supportsAdaptiveThinking ? 0 : native.thinkingBudget,
24776
+ isThinkingModel: native.supportsThinking ?? false,
24777
+ ...isImageModel ? { isImageModel: true } : {},
24778
+ tier,
24779
+ quotaPreference,
24780
+ explicitQuota
24781
+ };
24782
+ }
24783
+ if (/^claude-(opus|sonnet)-5-5$/i.test(modelWithoutQuota)) {
24784
+ return {
24785
+ actualModel: `${modelWithoutQuota}-low`,
24786
+ thinkingBudget: 0,
24787
+ isThinkingModel: true,
24788
+ tier: "low",
24789
+ quotaPreference,
24790
+ explicitQuota
24791
+ };
24792
+ }
24553
24793
  const isGemini3 = modelWithoutQuota.toLowerCase().startsWith("gemini-3");
24554
24794
  const skipAlias = isAntigravity && isGemini3;
24555
24795
  const isGemini3Pro = isGemini3ProModel(modelWithoutQuota);
@@ -24583,7 +24823,7 @@ function resolveModelWithTier(requestedModel, options = {}) {
24583
24823
  if (isGemini36Flash && quotaPreference === "antigravity") {
24584
24824
  return {
24585
24825
  actualModel: getGemini36FlashAntigravityModel(tier ?? "medium"),
24586
- thinkingBudget: getAgyGeminiFlashThinkingBudget(tier),
24826
+ thinkingBudget: getAgyGeminiFlashThinkingBudget(tier, -1),
24587
24827
  tier: tier ?? "medium",
24588
24828
  isThinkingModel: true,
24589
24829
  quotaPreference,
@@ -26909,7 +27149,7 @@ async function replacePoolLogins(repository, results, options = {}) {
26909
27149
  }
26910
27150
 
26911
27151
  // src/sidebar-state.ts
26912
- import { mkdirSync as mkdirSync3, readFileSync as readFileSync2 } from "node:fs";
27152
+ import { chmodSync as chmodSync3, mkdirSync as mkdirSync3, readFileSync as readFileSync2 } from "node:fs";
26913
27153
  import { homedir as homedir3 } from "node:os";
26914
27154
  import { dirname as dirname14, join as join12 } from "node:path";
26915
27155
 
@@ -26933,7 +27173,7 @@ if (xdgConfig) {
26933
27173
  }
26934
27174
 
26935
27175
  // src/sidebar-state.ts
26936
- var SIDEBAR_STATE_VERSION = 1;
27176
+ var SIDEBAR_STATE_VERSION = 2;
26937
27177
  var DEFAULT_SIDEBAR_STATE = {
26938
27178
  version: SIDEBAR_STATE_VERSION,
26939
27179
  checkedAt: 0,
@@ -26994,7 +27234,7 @@ function normalizeSidebarState(input2) {
26994
27234
  }
26995
27235
  const record2 = input2;
26996
27236
  const version = record2.version;
26997
- if (version !== SIDEBAR_STATE_VERSION) {
27237
+ if (version !== 1 && version !== SIDEBAR_STATE_VERSION) {
26998
27238
  return {
26999
27239
  ...DEFAULT_SIDEBAR_STATE,
27000
27240
  lastError: `unsupported-version:${stringifySafe(version)}`
@@ -27049,6 +27289,7 @@ function normalizeAccount(input2) {
27049
27289
  return {
27050
27290
  id,
27051
27291
  label,
27292
+ ...typeof record2.email === "string" ? { email: record2.email } : {},
27052
27293
  enabled,
27053
27294
  health,
27054
27295
  current,
@@ -27070,6 +27311,7 @@ function normalizeQuota(input2) {
27070
27311
  if (!isObject(input2)) return null;
27071
27312
  const record2 = input2;
27072
27313
  const remaining = toFiniteNumber(record2.remainingPercent);
27314
+ const fraction = toFiniteNumber(record2.remainingFraction);
27073
27315
  if (remaining === null) return null;
27074
27316
  const resetAt = toFiniteNumber(record2.resetAt) ?? void 0;
27075
27317
  const checkedAt = toFiniteNumber(record2.checkedAt) ?? void 0;
@@ -27083,10 +27325,12 @@ function normalizeQuota(input2) {
27083
27325
  );
27084
27326
  const ra = toFiniteNumber(w.resetAt);
27085
27327
  const ca = toFiniteNumber(w.checkedAt);
27328
+ const rf = toFiniteNumber(w.remainingFraction);
27086
27329
  if (win !== "weekly" && win !== "5h" || rp === null) return null;
27087
27330
  return {
27088
27331
  window: win,
27089
27332
  remainingPercent: clampNumber(rp, 0, 100),
27333
+ ...rf !== null ? { remainingFraction: clampNumber(rf, 0, 1) } : {},
27090
27334
  resetAt: ra ?? void 0,
27091
27335
  ...ca !== null && ca >= 0 ? { checkedAt: ca } : {}
27092
27336
  };
@@ -27095,6 +27339,7 @@ function normalizeQuota(input2) {
27095
27339
  }
27096
27340
  return {
27097
27341
  remainingPercent: clampNumber(remaining, 0, 100),
27342
+ ...fraction !== null ? { remainingFraction: clampNumber(fraction, 0, 1) } : {},
27098
27343
  resetAt,
27099
27344
  ...checkedAt !== void 0 ? { checkedAt } : {},
27100
27345
  windows
@@ -27146,6 +27391,7 @@ function stringifySafe(value) {
27146
27391
  }
27147
27392
  function ensureSidebarStateDir(path5 = getSidebarStateFile()) {
27148
27393
  mkdirSync3(dirname14(path5), { recursive: true, mode: SIDEBAR_STATE_DIR_MODE });
27394
+ chmodSync3(dirname14(path5), SIDEBAR_STATE_DIR_MODE);
27149
27395
  }
27150
27396
  function pruneActiveRouting(map, now) {
27151
27397
  const cutoff = now - ACTIVE_ROUTING_MAX_AGE_MS;
@@ -27224,6 +27470,7 @@ function projectQuotaPoolForSidebar(source, checkedAt) {
27224
27470
  0,
27225
27471
  100
27226
27472
  ),
27473
+ remainingFraction: clampNumber(w.remainingFraction, 0, 1),
27227
27474
  resetAt: typeof w.resetTime === "string" && w.resetTime.length > 0 ? (() => {
27228
27475
  const parsed = Date.parse(w.resetTime);
27229
27476
  return Number.isFinite(parsed) ? parsed : void 0;
@@ -27231,6 +27478,7 @@ function projectQuotaPoolForSidebar(source, checkedAt) {
27231
27478
  })) : void 0;
27232
27479
  return {
27233
27480
  remainingPercent,
27481
+ remainingFraction: clampNumber(fraction, 0, 1),
27234
27482
  resetAt,
27235
27483
  windows,
27236
27484
  ...readingAt !== void 0 ? { checkedAt: readingAt } : {}
@@ -27267,6 +27515,7 @@ function redactAccountForSidebar(source) {
27267
27515
  return {
27268
27516
  id,
27269
27517
  label,
27518
+ ...typeof source.email === "string" ? { email: source.email } : {},
27270
27519
  enabled,
27271
27520
  health,
27272
27521
  current,
@@ -27868,6 +28117,7 @@ async function pushSidebarQuotaSnapshot(getAccounts, backoffUntil = 0, getActive
27868
28117
  accounts.map((entry) => ({
27869
28118
  index: entry.index,
27870
28119
  label: entry.label,
28120
+ email: entry.email,
27871
28121
  enabled: entry.enabled,
27872
28122
  current: activeByFamily ? isAccountCurrent(entry.index, activeByFamily) : false,
27873
28123
  coolingDownUntil: entry.coolingDownUntil,
@@ -35586,7 +35836,7 @@ function clearSignatureCache(sessionId) {
35586
35836
  }
35587
35837
 
35588
35838
  // src/plugin/image-saver.ts
35589
- import { chmodSync as chmodSync3, existsSync as existsSync11, mkdirSync as mkdirSync6, writeFileSync as writeFileSync6 } from "node:fs";
35839
+ import { chmodSync as chmodSync4, existsSync as existsSync11, mkdirSync as mkdirSync6, writeFileSync as writeFileSync6 } from "node:fs";
35590
35840
  import { homedir as homedir9 } from "node:os";
35591
35841
  import { join as join22 } from "node:path";
35592
35842
  function getImageOutputDir(outputDir) {
@@ -35594,7 +35844,7 @@ function getImageOutputDir(outputDir) {
35594
35844
  if (!existsSync11(resolved)) {
35595
35845
  mkdirSync6(resolved, { recursive: true, mode: 448 });
35596
35846
  }
35597
- chmodSync3(resolved, 448);
35847
+ chmodSync4(resolved, 448);
35598
35848
  return resolved;
35599
35849
  }
35600
35850
  function generateImageFilename(mimeType) {
@@ -35615,7 +35865,7 @@ function saveImageToDisk(base64Data, mimeType, outputDir) {
35615
35865
  const resolvedOutputDir = getImageOutputDir(outputDir);
35616
35866
  const filePath = join22(resolvedOutputDir, generateImageFilename(mimeType));
35617
35867
  writeFileSync6(filePath, Buffer.from(base64Data, "base64"), { mode: 384 });
35618
- chmodSync3(filePath, 384);
35868
+ chmodSync4(filePath, 384);
35619
35869
  return filePath;
35620
35870
  } catch (error) {
35621
35871
  console.error("[image-saver] Failed to save image:", error);
@@ -38793,6 +39043,8 @@ function getImageModelLocalTitle(input2, init) {
38793
39043
  }
38794
39044
  }
38795
39045
  function getAgyMaxOutputTokens(model) {
39046
+ const native = getAgyNativeModel(model);
39047
+ if (native) return native.maxOutputTokens;
38796
39048
  const lower = model.toLowerCase();
38797
39049
  if (lower === "gemini-3.5-flash-low" || lower === "gemini-3.5-flash-extra-low" || lower === "gemini-3-flash-agent" || lower === "gemini-3.6-flash-low" || lower === "gemini-3.6-flash-medium" || lower === "gemini-3.6-flash-high" || lower === "gemini-3.7-flash-low" || lower === "gemini-3.7-flash-medium" || lower === "gemini-3.7-flash-high" || lower === "gemini-3.8-flash-low" || lower === "gemini-3.8-flash-medium" || lower === "gemini-3.8-flash-high") {
38798
39050
  return 65536;
@@ -38812,6 +39064,10 @@ function applyAgyGenerationDefaults(model, generationConfig, headerStyle) {
38812
39064
  if (headerStyle !== "antigravity") {
38813
39065
  return;
38814
39066
  }
39067
+ if (getAgyNativeModel(model)) {
39068
+ applyAgyNativeGenerationConfig(model, generationConfig);
39069
+ return;
39070
+ }
38815
39071
  const maxOutputTokens = getAgyMaxOutputTokens(model);
38816
39072
  if (maxOutputTokens !== void 0) {
38817
39073
  generationConfig.maxOutputTokens = maxOutputTokens;
@@ -39717,6 +39973,11 @@ function prepareAntigravityRequestIn(wire, input2, init, accessToken, projectId,
39717
39973
  const wireRequest = requestObjects.at(-1);
39718
39974
  if (wireRequest) {
39719
39975
  if (headerStyle === "antigravity") {
39976
+ const generationConfig = wireRequest.generationConfig;
39977
+ const config = generationConfig && typeof generationConfig === "object" && !Array.isArray(generationConfig) ? generationConfig : {};
39978
+ applyAgyNativeGenerationConfig(effectiveModel, config);
39979
+ if (Object.keys(config).length > 0)
39980
+ wireRequest.generationConfig = config;
39720
39981
  const metadata = buildAgyAgentRequestMetadata(
39721
39982
  options?.agySession ?? DEFAULT_AGY_REQUEST_SESSION,
39722
39983
  wireRequest,
@@ -39752,7 +40013,7 @@ function prepareAntigravityRequestIn(wire, input2, init, accessToken, projectId,
39752
40013
  `[ThinkingResolution] rawModel=${rawModel} resolvedModel=${effectiveModel} resolvedTier=${tierThinkingLevel ?? "none"} variantLevel=${variantConfig?.thinkingLevel ?? "none"} variantBudget=${variantConfig?.thinkingBudget ?? "none"} providerOptions.google=${JSON.stringify(requestPayload.providerOptions?.google ?? null)} generationConfig.thinkingConfig=${JSON.stringify(rawGenerationConfig?.thinkingConfig ?? null)}`
39753
40014
  );
39754
40015
  delete requestPayload.providerOptions;
39755
- if (variantConfig?.thinkingLevel && isGemini3) {
40016
+ if (variantConfig?.thinkingLevel && (isGemini3 || getAgyNativeModel(effectiveModel)?.supportsAdaptiveThinking)) {
39756
40017
  const variantModelBase = rawModel.replace(/-preview-customtools$/i, "").replace(/-preview$/i, "").replace(/-(minimal|low|medium|high)$/i, "");
39757
40018
  const variantResolved = resolveModelForHeaderStyle(
39758
40019
  `${variantModelBase}-${variantConfig.thinkingLevel}`,
@@ -40179,6 +40440,11 @@ function prepareAntigravityRequestIn(wire, input2, init, accessToken, projectId,
40179
40440
  stripInjectedDebugFromRequestPayload(requestPayload);
40180
40441
  sanitizeRequestPayloadForAntigravity(requestPayload);
40181
40442
  if (headerStyle === "antigravity") {
40443
+ const generationConfig = requestPayload.generationConfig;
40444
+ const config = generationConfig && typeof generationConfig === "object" && !Array.isArray(generationConfig) ? generationConfig : {};
40445
+ applyAgyNativeGenerationConfig(effectiveModel, config);
40446
+ if (Object.keys(config).length > 0)
40447
+ requestPayload.generationConfig = config;
40182
40448
  stripUnsupportedAntigravityFields(requestPayload);
40183
40449
  configureAntigravityToolCalling(requestPayload);
40184
40450
  normalizeNativeFunctionResponseRoles(requestPayload);
@@ -40289,7 +40555,10 @@ function buildThinkingWarmupBody(bodyText, isClaudeThinking) {
40289
40555
  return null;
40290
40556
  }
40291
40557
  const warmupPrompt = "Warmup request for thinking signature.";
40292
- const wireModel = typeof parsed.model === "string" ? parsed.model : "claude-sonnet-4-6";
40558
+ const candidate = typeof parsed.model === "string" ? parsed.model : "";
40559
+ if (candidate && isRetiredAgyModel(candidate)) return null;
40560
+ const wireModel = candidate || "claude-sonnet-5-5-low";
40561
+ parsed.model = wireModel;
40293
40562
  const requestObjects = [];
40294
40563
  const updateRequest = (req) => {
40295
40564
  req.contents = [{ role: "user", parts: [{ text: warmupPrompt }] }];
@@ -40300,7 +40569,8 @@ function buildThinkingWarmupBody(bodyText, isClaudeThinking) {
40300
40569
  includeThoughts: true,
40301
40570
  thinkingBudget: AGY_CLAUDE_THINKING_BUDGET
40302
40571
  };
40303
- generationConfig.maxOutputTokens = getAgyMaxOutputTokens(wireModel) ?? computeClaudeMaxOutputTokens(AGY_CLAUDE_THINKING_BUDGET);
40572
+ generationConfig.maxOutputTokens ??= generationConfig.max_output_tokens ?? getAgyMaxOutputTokens(wireModel) ?? computeClaudeMaxOutputTokens(AGY_CLAUDE_THINKING_BUDGET);
40573
+ applyAgyNativeGenerationConfig(wireModel, generationConfig);
40304
40574
  req.generationConfig = generationConfig;
40305
40575
  requestObjects.push(req);
40306
40576
  };
@@ -40748,6 +41018,7 @@ function createAuthLoader({
40748
41018
  return {
40749
41019
  index: entry.index,
40750
41020
  label: entry.label,
41021
+ email: entry.email,
40751
41022
  enabled: entry.enabled,
40752
41023
  current: isAccountCurrent(entry.index, activeByFamily),
40753
41024
  coolingDownUntil: entry.coolingDownUntil,
@@ -41280,550 +41551,833 @@ var BackgroundQuotaRefresh = class {
41280
41551
  }
41281
41552
  };
41282
41553
 
41283
- // src/plugin/operator-settings.ts
41284
- import { createHash as createHash18 } from "node:crypto";
41285
- import { existsSync as existsSync14, readFileSync as readFileSync12 } from "node:fs";
41286
- import { z as z4 } from "zod";
41287
-
41288
- // src/plugin/config/operator-settings-schema.ts
41289
- import { z as z2 } from "zod";
41290
- var OperatorSettingsSchema = z2.object({
41291
- routing: z2.object({
41292
- cli_first: z2.boolean(),
41293
- quota_style_fallback: z2.boolean()
41294
- }),
41295
- killswitch: z2.object({
41296
- enabled: z2.boolean(),
41297
- minimum_remaining_percent: z2.number().min(0).max(100),
41298
- accounts: z2.record(z2.string(), z2.number().min(0).max(100)).optional()
41299
- }),
41300
- log_level: z2.enum(["error", "warn", "info", "debug", "trace"])
41301
- });
41302
- function emptyOperatorSettings() {
41303
- return {
41304
- routing: { cli_first: false, quota_style_fallback: false },
41305
- killswitch: { enabled: false, minimum_remaining_percent: 5 },
41306
- log_level: "info"
41307
- };
41554
+ // src/plugin/shared/vault-request-credentials.ts
41555
+ function vaultAccountRows(routes) {
41556
+ return routes.map((route, index) => ({
41557
+ index,
41558
+ enabled: true,
41559
+ lastUsed: 0,
41560
+ rateLimitResetTimes: {},
41561
+ touchedForQuota: {},
41562
+ route,
41563
+ ...route.email !== void 0 ? { email: route.email } : {}
41564
+ }));
41308
41565
  }
41309
-
41310
- // src/plugin/config/writer.ts
41311
- import { existsSync as existsSync13, readFileSync as readFileSync11 } from "node:fs";
41312
- import { z as z3 } from "zod";
41313
- async function writeOperatorConfig(options) {
41314
- const target = existsSync13(options.projectConfigPath) ? options.projectConfigPath : options.userConfigPath;
41315
- await writeOperatorConfigAt(target, options.operator);
41566
+ function vaultAccountRowKey(row) {
41567
+ return JSON.stringify([
41568
+ row.route.routeId,
41569
+ row.route.credentialId,
41570
+ row.route.accountIdentity
41571
+ ]);
41316
41572
  }
41317
- async function writeOperatorConfigAt(target, settings) {
41318
- const operator = OperatorSettingsSchema.parse(settings);
41319
- const lock = await acquireFencedFileLock({
41320
- path: target,
41321
- name: "antigravity-operator",
41322
- ttlMs: 5e3,
41323
- renew: false
41324
- });
41325
- if (!lock) {
41326
- throw new Error(
41327
- `Could not acquire operator-config lock at ${target} (already held by another writer).`
41328
- );
41329
- }
41330
- try {
41331
- const existing = readExistingConfig(target);
41332
- const merged = mergeOperator(existing, operator);
41333
- await writeJsonAtomic(target, merged);
41334
- } finally {
41335
- await lock.release().catch(() => {
41573
+ function refreshVaultAccountRow(prior, fresh) {
41574
+ prior.route = fresh.route;
41575
+ if (fresh.email === void 0) delete prior.email;
41576
+ else prior.email = fresh.email;
41577
+ }
41578
+ var VaultSendGrant = class {
41579
+ credentialId;
41580
+ accountIdentity;
41581
+ recordVersion;
41582
+ projectId;
41583
+ report401;
41584
+ constructor(admission, report) {
41585
+ Object.defineProperty(this, "accessToken", {
41586
+ value: admission.accessToken,
41587
+ enumerable: false
41336
41588
  });
41589
+ this.credentialId = admission.credentialId;
41590
+ this.accountIdentity = admission.accountIdentity;
41591
+ this.recordVersion = admission.recordVersion;
41592
+ this.projectId = admission.projectId;
41593
+ this.report401 = report;
41337
41594
  }
41338
- }
41339
- function readExistingConfig(target) {
41340
- if (!existsSync13(target)) return {};
41341
- try {
41342
- const raw = readFileSync11(target, "utf-8");
41343
- const parsed = JSON.parse(raw);
41344
- if (parsed !== null && typeof parsed === "object" && !Array.isArray(parsed)) {
41345
- return parsed;
41595
+ };
41596
+ function createVaultRequestCredentials(source, onAdmitted) {
41597
+ return {
41598
+ domain: "vault",
41599
+ async admit({ account, signal }) {
41600
+ const admission = await source.admit(account.route, signal);
41601
+ if (onAdmitted)
41602
+ onAdmitted.admitted(account, onAdmitted.source.attribution(admission));
41603
+ return new VaultSendGrant(
41604
+ admission,
41605
+ (status) => source.reportServedStatus(admission, status)
41606
+ );
41346
41607
  }
41347
- return {};
41348
- } catch {
41349
- return {};
41350
- }
41608
+ };
41351
41609
  }
41352
- function mergeOperator(existing, operator) {
41353
- const next = { ...existing };
41354
- next.operator = operator;
41355
- return next;
41610
+ function present4(value) {
41611
+ return value === null ? void 0 : value;
41356
41612
  }
41357
-
41358
- // src/plugin/operator-settings.ts
41359
- var PartialOperatorSettingsSchema = z4.object({
41360
- routing: z4.object({
41361
- cli_first: z4.boolean().optional(),
41362
- quota_style_fallback: z4.boolean().optional()
41363
- }).optional(),
41364
- killswitch: z4.object({
41365
- enabled: z4.boolean().optional(),
41366
- minimum_remaining_percent: z4.number().min(0).max(100).optional(),
41367
- accounts: z4.record(z4.string(), z4.number().min(0).max(100)).optional()
41368
- }).optional(),
41369
- log_level: z4.enum(["error", "warn", "info", "debug", "trace"]).optional()
41370
- });
41371
- function createOperatorSettingsController(options) {
41372
- let cached = null;
41373
- let disposed = false;
41374
- let pending = null;
41375
- const loadFromDisk = () => {
41376
- const existing = readOperatorFile(options.projectConfigPath);
41377
- if (existing) return existing;
41378
- const fromUser = readOperatorFile(options.userConfigPath);
41379
- if (fromUser) return fromUser;
41380
- return emptyOperatorSettings();
41381
- };
41382
- const persist = async (next) => {
41383
- if (pending) await pending;
41384
- pending = writeOperatorConfig({
41385
- projectConfigPath: options.projectConfigPath,
41386
- userConfigPath: options.userConfigPath,
41387
- operator: next
41388
- });
41389
- try {
41390
- await pending;
41391
- } finally {
41392
- pending = null;
41393
- }
41394
- };
41395
- return {
41396
- get() {
41397
- if (!cached) cached = loadFromDisk();
41398
- return cached;
41399
- },
41400
- async update(mutator) {
41401
- if (disposed) throw new Error("OperatorSettingsController is disposed");
41402
- const current = cached ?? loadFromDisk();
41403
- const draft = JSON.parse(
41404
- JSON.stringify(current)
41405
- );
41406
- mutator(draft);
41407
- const validated = OperatorSettingsSchema.parse(draft);
41408
- cached = validated;
41409
- await persist(validated);
41410
- },
41411
- async dispose() {
41412
- if (disposed) return;
41413
- disposed = true;
41414
- if (pending) {
41415
- try {
41416
- await pending;
41417
- } catch {
41418
- }
41419
- }
41420
- }
41421
- };
41613
+ function storedResets(resets) {
41614
+ const stored = {};
41615
+ for (const [key, at] of Object.entries(resets))
41616
+ if (typeof at === "number") stored[key] = at;
41617
+ return stored;
41422
41618
  }
41423
- function createOperatorSettingsRegistry() {
41424
- const entries = /* @__PURE__ */ new Map();
41425
- const createEntry = (path5) => {
41426
- let state;
41427
- let chain = Promise.resolve();
41428
- const read = () => {
41429
- if (state === void 0) state = readOperatorFile(path5);
41430
- return state;
41431
- };
41432
- return {
41433
- path: path5,
41434
- refs: 0,
41435
- read,
41436
- update(seed, mutator) {
41437
- const run = chain.then(async () => {
41438
- const draft = cloneSettings(read() ?? seed());
41439
- mutator(draft);
41440
- const validated = OperatorSettingsSchema.parse(draft);
41441
- state = validated;
41442
- await writeOperatorConfigAt(path5, validated);
41443
- });
41444
- chain = run.catch(() => {
41445
- });
41446
- return run;
41447
- }
41619
+ function cachedQuotaOf(quota) {
41620
+ const groups = quota.cachedQuota;
41621
+ if (groups == null) return void 0;
41622
+ const out = {};
41623
+ for (const name of ["gemini", "non-gemini"]) {
41624
+ const group = groups[name];
41625
+ if (group === void 0) continue;
41626
+ out[name] = {
41627
+ modelCount: group.modelCount,
41628
+ ...group.remainingFraction != null ? { remainingFraction: group.remainingFraction } : {},
41629
+ ...group.resetTime != null ? { resetTime: group.resetTime } : {},
41630
+ ...group.windows != null ? {
41631
+ windows: group.windows.map((window) => ({
41632
+ window: window.window,
41633
+ remainingFraction: window.remainingFraction,
41634
+ resetTime: window.resetTime
41635
+ }))
41636
+ } : {}
41448
41637
  };
41449
- };
41450
- const registry = {
41451
- livePaths: () => [...entries.keys()],
41452
- acquire(path5) {
41453
- const key = canonicalizeOwnedPath(path5);
41454
- let entry = entries.get(key);
41455
- if (!entry) {
41456
- entry = createEntry(key);
41457
- entries.set(key, entry);
41458
- }
41459
- entry.refs++;
41460
- return entry;
41461
- },
41462
- release(entry) {
41463
- entry.refs--;
41464
- if (entry.refs <= 0 && entries.get(entry.path) === entry) {
41465
- entries.delete(entry.path);
41466
- }
41467
- }
41468
- };
41469
- return registry;
41470
- }
41471
- var processOperatorSettingsRegistry = createOperatorSettingsRegistry();
41472
- function cloneSettings(settings) {
41473
- return JSON.parse(JSON.stringify(settings));
41474
- }
41475
- function readOperatorFile(path5) {
41476
- try {
41477
- const raw = readFileSync12(path5, "utf-8");
41478
- const parsed = JSON.parse(raw);
41479
- if (parsed === null || typeof parsed !== "object" || !("operator" in parsed)) {
41480
- return null;
41481
- }
41482
- const partial = PartialOperatorSettingsSchema.safeParse(
41483
- parsed.operator
41484
- );
41485
- if (!partial.success) return null;
41486
- return mergeWithDefaults(partial.data);
41487
- } catch {
41488
- return null;
41489
41638
  }
41639
+ return out;
41490
41640
  }
41491
- function mergeWithDefaults(partial) {
41492
- const defaults = emptyOperatorSettings();
41641
+ function durableSelectionOf(row) {
41493
41642
  return {
41494
- routing: { ...defaults.routing, ...partial.routing ?? {} },
41495
- killswitch: {
41496
- ...defaults.killswitch,
41497
- ...partial.killswitch ?? {},
41498
- accounts: {
41499
- ...defaults.killswitch.accounts ?? {},
41500
- ...partial.killswitch?.accounts ?? {}
41501
- }
41502
- },
41503
- log_level: partial.log_level ?? defaults.log_level
41643
+ lastUsed: row.lastUsed,
41644
+ ...row.lastSwitchReason !== void 0 ? { lastSwitchReason: row.lastSwitchReason } : {},
41645
+ rateLimitResetTimes: storedResets(row.rateLimitResetTimes),
41646
+ ...row.coolingDownUntil !== void 0 ? { coolingDownUntil: row.coolingDownUntil } : {},
41647
+ ...row.cooldownReason !== void 0 ? { cooldownReason: row.cooldownReason } : {},
41648
+ ...row.fingerprint !== void 0 ? { fingerprint: structuredClone(row.fingerprint) } : {},
41649
+ ...row.fingerprintHistory !== void 0 ? { fingerprintHistory: structuredClone(row.fingerprintHistory) } : {},
41650
+ ...row.verificationRequired !== void 0 ? { verificationRequired: row.verificationRequired } : {},
41651
+ ...row.verificationRequiredAt !== void 0 ? { verificationRequiredAt: row.verificationRequiredAt } : {},
41652
+ ...row.verificationRequiredReason !== void 0 ? { verificationRequiredReason: row.verificationRequiredReason } : {},
41653
+ ...row.verificationUrl !== void 0 ? { verificationUrl: row.verificationUrl } : {},
41654
+ ...row.accountIneligible !== void 0 ? { accountIneligible: row.accountIneligible } : {},
41655
+ ...row.accountIneligibleAt !== void 0 ? { accountIneligibleAt: row.accountIneligibleAt } : {},
41656
+ ...row.accountIneligibleReason !== void 0 ? { accountIneligibleReason: row.accountIneligibleReason } : {},
41657
+ ...row.eligibilityStateUpdatedAt !== void 0 ? { eligibilityStateUpdatedAt: row.eligibilityStateUpdatedAt } : {},
41658
+ ...row.dailyRequestCounts !== void 0 ? { dailyRequestCounts: { ...row.dailyRequestCounts } } : {}
41504
41659
  };
41505
41660
  }
41506
- function accountKeyForRefreshToken(refreshToken) {
41507
- return createHash18("sha256").update(refreshToken).digest("hex").slice(0, 12);
41661
+ function applyDurableSelection(row, metadata) {
41662
+ row.lastUsed = metadata.lastUsed;
41663
+ const reason = present4(metadata.lastSwitchReason);
41664
+ if (reason !== void 0) row.lastSwitchReason = reason;
41665
+ const resets = present4(metadata.rateLimitResetTimes);
41666
+ if (resets !== void 0) {
41667
+ const copy = {};
41668
+ for (const [key, at] of Object.entries(resets))
41669
+ if (typeof at === "number") copy[key] = at;
41670
+ row.rateLimitResetTimes = copy;
41671
+ }
41672
+ const until = present4(metadata.coolingDownUntil);
41673
+ const cooldownReason = present4(metadata.cooldownReason);
41674
+ if (until !== void 0 && cooldownReason !== void 0) {
41675
+ row.coolingDownUntil = until;
41676
+ row.cooldownReason = cooldownReason;
41677
+ }
41678
+ const fingerprint = present4(metadata.fingerprint);
41679
+ if (fingerprint !== void 0) row.fingerprint = structuredClone(fingerprint);
41680
+ const history = present4(metadata.fingerprintHistory);
41681
+ if (history !== void 0) row.fingerprintHistory = structuredClone(history);
41682
+ const verification = present4(metadata.verificationRequired);
41683
+ if (verification !== void 0) row.verificationRequired = verification;
41684
+ const verificationAt = present4(metadata.verificationRequiredAt);
41685
+ if (verificationAt !== void 0) row.verificationRequiredAt = verificationAt;
41686
+ const verificationReason = present4(metadata.verificationRequiredReason);
41687
+ if (verificationReason !== void 0)
41688
+ row.verificationRequiredReason = verificationReason;
41689
+ const verificationUrl = present4(metadata.verificationUrl);
41690
+ if (verificationUrl !== void 0) row.verificationUrl = verificationUrl;
41691
+ const ineligible = present4(metadata.accountIneligible);
41692
+ if (ineligible !== void 0) row.accountIneligible = ineligible;
41693
+ const ineligibleAt = present4(metadata.accountIneligibleAt);
41694
+ if (ineligibleAt !== void 0) row.accountIneligibleAt = ineligibleAt;
41695
+ const ineligibleReason = present4(metadata.accountIneligibleReason);
41696
+ if (ineligibleReason !== void 0)
41697
+ row.accountIneligibleReason = ineligibleReason;
41698
+ const eligibilityAt = present4(metadata.eligibilityStateUpdatedAt);
41699
+ if (eligibilityAt !== void 0) row.eligibilityStateUpdatedAt = eligibilityAt;
41700
+ const counts = present4(metadata.dailyRequestCounts);
41701
+ if (counts !== void 0) row.dailyRequestCounts = { ...counts };
41508
41702
  }
41509
-
41510
- // src/plugin/command-apply.ts
41511
- function operatorMenuSettings(settings) {
41512
- return {
41513
- read() {
41514
- const current = settings.get();
41515
- return {
41516
- routing: {
41517
- cliFirst: current.routing.cli_first,
41518
- quotaStyleFallback: current.routing.quota_style_fallback
41703
+ function stateBelongsTo(state, row) {
41704
+ return state.observed.routeId === row.route.routeId && state.observed.credentialId === row.route.credentialId;
41705
+ }
41706
+ function createVaultSelectionState(options) {
41707
+ const now = options.now ?? (() => Date.now());
41708
+ const attributions = /* @__PURE__ */ new WeakMap();
41709
+ const changed = /* @__PURE__ */ new Set();
41710
+ let writing = Promise.resolve();
41711
+ const mark = (row) => {
41712
+ changed.add(row);
41713
+ };
41714
+ const report = (error) => {
41715
+ try {
41716
+ options.onError?.(error);
41717
+ } catch {
41718
+ }
41719
+ };
41720
+ const writeRow = async (row) => {
41721
+ const attribution = attributions.get(row);
41722
+ if (attribution === void 0) return;
41723
+ changed.delete(row);
41724
+ const selection = durableSelectionOf(row);
41725
+ try {
41726
+ await options.source.commitState(attribution, (current) => ({
41727
+ metadata: {
41728
+ ...current?.metadata ?? { addedAt: now() },
41729
+ ...selection
41519
41730
  },
41520
- killswitch: {
41521
- enabled: current.killswitch.enabled,
41522
- minimumRemainingPercent: current.killswitch.minimum_remaining_percent
41523
- }
41524
- };
41525
- },
41526
- updateRouting: (next) => settings.update((draft) => {
41527
- draft.routing.cli_first = next.cliFirst;
41528
- draft.routing.quota_style_fallback = next.quotaStyleFallback;
41529
- }),
41530
- updateKillswitch: (next) => settings.update((draft) => {
41531
- draft.killswitch.enabled = next.enabled;
41532
- draft.killswitch.minimum_remaining_percent = next.minimumRemainingPercent;
41533
- })
41731
+ ...current?.quota !== void 0 ? { quota: current.quota } : {},
41732
+ ...current?.extensions !== void 0 ? { extensions: current.extensions } : {}
41733
+ }));
41734
+ } catch (error) {
41735
+ report(error);
41736
+ }
41737
+ };
41738
+ const flush = () => {
41739
+ writing = writing.then(async () => {
41740
+ for (const row of [...changed]) await writeRow(row);
41741
+ });
41742
+ return writing;
41534
41743
  };
41535
- }
41536
- var LOG_LEVEL_CHOICES = ["error", "warn", "info", "debug", "trace"];
41537
- function diagnosticsMenuSection(options) {
41538
41744
  return {
41539
- title: "Diagnostics",
41540
- build() {
41541
- const level = options.settings.get().log_level;
41542
- const dumping = options.dump.isEnabled();
41543
- return {
41544
- lines: [
41545
- `Gemini request dump: ${dumping ? "on" : "off"}`,
41546
- `Log level: ${level}`
41547
- ],
41548
- actions: [
41549
- {
41550
- id: "dump",
41551
- label: dumping ? "Stop dumping requests" : "Dump requests",
41552
- run: async () => {
41553
- options.dump.setEnabled(!dumping);
41554
- return `Gemini request dump ${dumping ? "off" : "on"}`;
41555
- }
41556
- },
41557
- {
41558
- id: "logging",
41559
- label: "Change log level",
41560
- knobs: [
41561
- {
41562
- kind: "choice",
41563
- id: "level",
41564
- label: "Level",
41565
- choices: LOG_LEVEL_CHOICES.map((value) => ({
41566
- value,
41567
- label: value
41568
- })),
41569
- value: level
41570
- }
41571
- ],
41572
- run: async ({ values }) => {
41573
- const next = LOG_LEVEL_CHOICES.find(
41574
- (candidate) => candidate === values.level
41575
- );
41576
- if (next === void 0)
41577
- return {
41578
- ok: false,
41579
- text: "Choose a log level",
41580
- code: "invalid-input"
41581
- };
41582
- await options.settings.update((draft) => {
41583
- draft.log_level = next;
41584
- });
41585
- options.applyLogLevel(next);
41586
- return `Log level set to ${next}`;
41587
- }
41588
- }
41589
- ]
41590
- };
41745
+ sink: {
41746
+ rateLimit: mark,
41747
+ cooldown: mark,
41748
+ switched: mark,
41749
+ lastUsed: mark,
41750
+ usage: mark,
41751
+ accessVerdict: mark,
41752
+ fingerprint: mark,
41753
+ requestSave: () => {
41754
+ void flush();
41755
+ }
41756
+ },
41757
+ admitted(row, attribution) {
41758
+ attributions.set(row, attribution);
41759
+ },
41760
+ async hydrate(rows) {
41761
+ const file = await options.readState();
41762
+ for (const row of rows) {
41763
+ const identity = row.route.accountIdentity;
41764
+ if (!Object.hasOwn(file.accounts, identity)) continue;
41765
+ const state = file.accounts[identity];
41766
+ if (state === void 0 || !stateBelongsTo(state, row)) continue;
41767
+ if (state.metadata !== void 0)
41768
+ applyDurableSelection(row, state.metadata);
41769
+ if (state.quota !== void 0) {
41770
+ const cached = cachedQuotaOf(state.quota);
41771
+ if (cached !== void 0) row.cachedQuota = cached;
41772
+ const updatedAt = present4(state.quota.cachedQuotaUpdatedAt);
41773
+ if (updatedAt !== void 0) row.cachedQuotaUpdatedAt = updatedAt;
41774
+ }
41775
+ }
41776
+ },
41777
+ flush,
41778
+ recordQuota(attribution, quota) {
41779
+ return options.source.commitState(attribution, (current) => ({
41780
+ ...current?.metadata !== void 0 ? { metadata: current.metadata } : {},
41781
+ quota,
41782
+ ...current?.extensions !== void 0 ? { extensions: current.extensions } : {}
41783
+ }));
41591
41784
  }
41592
41785
  };
41593
41786
  }
41594
- var STALE_FAILURES = /* @__PURE__ */ new Set(["attribution", "unknown-row", "id-removed"]);
41595
- function createStoreAccountLimits(input2) {
41787
+ function createVaultAccountPool(options) {
41788
+ const { source, durable } = options;
41789
+ const state = durable ? createVaultSelectionState({
41790
+ source: durable.source,
41791
+ readState: durable.readState,
41792
+ ...options.now ? { now: options.now } : {},
41793
+ ...durable.onError ? { onError: durable.onError } : {}
41794
+ }) : void 0;
41795
+ const selector = new AccountSelector({
41796
+ ...options.now ? { now: options.now } : {},
41797
+ ...state ? { sink: state.sink } : {}
41798
+ });
41799
+ const credentials = createVaultRequestCredentials(
41800
+ source,
41801
+ state && durable ? {
41802
+ source: durable.source,
41803
+ admitted: (row, attribution) => state.admitted(row, attribution)
41804
+ } : void 0
41805
+ );
41806
+ const rowsFromSource = async () => {
41807
+ const rows = vaultAccountRows(source.routes());
41808
+ if (state) {
41809
+ const kept = new Set(selector.rows.map(vaultAccountRowKey));
41810
+ const added = rows.filter((row) => !kept.has(vaultAccountRowKey(row)));
41811
+ if (added.length > 0) await state.hydrate(added);
41812
+ }
41813
+ return rows;
41814
+ };
41815
+ const replace = async () => {
41816
+ selector.replaceAccounts(await rowsFromSource(), {
41817
+ keyOf: vaultAccountRowKey,
41818
+ refresh: refreshVaultAccountRow
41819
+ });
41820
+ };
41821
+ let firstRead = null;
41822
+ const readOnce = () => {
41823
+ firstRead ??= (async () => {
41824
+ await source.refresh();
41825
+ selector.resetAccounts(await rowsFromSource());
41826
+ })().catch((error) => {
41827
+ firstRead = null;
41828
+ throw error;
41829
+ });
41830
+ return firstRead;
41831
+ };
41596
41832
  return {
41597
- async read(ref) {
41598
- const read = await input2.repository.read();
41599
- if (read.status !== "ready") return null;
41600
- const row = read.rows.find((candidate) => sameRowRef(candidate.ref, ref));
41601
- const token2 = row?.credential?.refreshToken;
41602
- if (token2 === void 0) return null;
41603
- return input2.settings.get().killswitch.accounts?.[accountKeyForRefreshToken(token2)] ?? null;
41833
+ selector,
41834
+ credentials,
41835
+ state,
41836
+ async sync() {
41837
+ const pending = firstRead;
41838
+ await readOnce();
41839
+ if (pending !== null) await replace();
41604
41840
  },
41605
- async write(ref, minimumRemainingPercent) {
41606
- try {
41607
- await input2.repository.updateMetadata(ref, async (_current, row) => {
41608
- const token2 = row.credential?.refreshToken;
41609
- if (token2 === void 0)
41610
- throw new Error("The account holds no stored credential");
41611
- const key = accountKeyForRefreshToken(token2);
41612
- await input2.settings.update((draft) => {
41613
- const accounts = { ...draft.killswitch.accounts ?? {} };
41614
- if (minimumRemainingPercent === null) delete accounts[key];
41615
- else accounts[key] = minimumRemainingPercent;
41616
- draft.killswitch.accounts = accounts;
41617
- });
41618
- return { kind: "keep" };
41619
- });
41620
- } catch (error) {
41621
- if (error instanceof AccountRepositoryError && STALE_FAILURES.has(error.failure.kind))
41622
- return "stale";
41623
- throw error;
41624
- }
41625
- return "applied";
41841
+ async refresh() {
41842
+ await readOnce();
41843
+ await source.refresh();
41844
+ await replace();
41845
+ },
41846
+ flush: async () => {
41847
+ await state?.flush();
41626
41848
  }
41627
41849
  };
41628
41850
  }
41629
-
41630
- // src/plugin/prompt-context.ts
41631
- function isRecord15(value) {
41632
- return typeof value === "object" && value !== null;
41633
- }
41634
- function extractMessages(response) {
41635
- if (Array.isArray(response)) return response;
41636
- if (isRecord15(response) && Array.isArray(response.data)) return response.data;
41637
- return [];
41851
+ function vaultQuotaState(quota, at) {
41852
+ const cachedQuota = {};
41853
+ for (const [name, group] of Object.entries(quota.groups)) {
41854
+ if (group === void 0) continue;
41855
+ cachedQuota[name] = {
41856
+ modelCount: group.modelCount,
41857
+ ...group.remainingFraction !== void 0 ? { remainingFraction: group.remainingFraction } : {},
41858
+ ...group.resetTime !== void 0 ? { resetTime: group.resetTime } : {},
41859
+ ...group.windows !== void 0 ? { windows: group.windows.map((window) => ({ ...window })) } : {}
41860
+ };
41861
+ }
41862
+ return { schemaVersion: 1, cachedQuota, cachedQuotaUpdatedAt: at };
41638
41863
  }
41639
- function getRole(message) {
41640
- if (!isRecord15(message) || !isRecord15(message.info)) return void 0;
41641
- return typeof message.info.role === "string" ? message.info.role : void 0;
41864
+ async function checkVaultQuota(input2) {
41865
+ const state = input2.pool.state;
41866
+ const rows = [...input2.pool.selector.rows];
41867
+ const now = input2.now ?? (() => Date.now());
41868
+ let checked = 0;
41869
+ for (const row of rows) {
41870
+ if (input2.signal.aborted || state === void 0) break;
41871
+ try {
41872
+ const answer = await input2.fetchReading(row.route, input2.signal);
41873
+ const attribution = answer.quotaAttribution;
41874
+ if (attribution === void 0 || answer.quota.error !== void 0)
41875
+ continue;
41876
+ const reading = vaultQuotaState(answer.quota, now());
41877
+ const result = await state.recordQuota(attribution, reading);
41878
+ if (result.status !== "written") continue;
41879
+ checked += 1;
41880
+ const live = input2.pool.selector.rows.find(
41881
+ (candidate) => candidate.route.routeId === attribution.routeId && candidate.route.credentialId === attribution.credentialId && candidate.route.accountIdentity === attribution.accountIdentity
41882
+ );
41883
+ if (live !== void 0) {
41884
+ const cached = cachedQuotaOf(reading);
41885
+ if (cached !== void 0) live.cachedQuota = cached;
41886
+ live.cachedQuotaUpdatedAt = reading.cachedQuotaUpdatedAt ?? void 0;
41887
+ }
41888
+ } catch (error) {
41889
+ try {
41890
+ input2.onError?.(error);
41891
+ } catch {
41892
+ }
41893
+ }
41894
+ }
41895
+ return { checked, notChecked: rows.length - checked };
41642
41896
  }
41643
- function extractFromMessage(message) {
41644
- if (!isRecord15(message) || !isRecord15(message.info)) return null;
41645
- const info = message.info;
41646
- const modelInfo = isRecord15(info.model) ? info.model : void 0;
41647
- const agent = typeof info.agent === "string" ? info.agent : void 0;
41648
- const providerID = typeof modelInfo?.providerID === "string" ? modelInfo.providerID : typeof info.providerID === "string" ? info.providerID : void 0;
41649
- const modelID = typeof modelInfo?.modelID === "string" ? modelInfo.modelID : typeof info.modelID === "string" ? info.modelID : void 0;
41650
- const variant = typeof modelInfo?.variant === "string" ? modelInfo.variant : typeof info.variant === "string" ? info.variant : void 0;
41651
- if (!agent && (!providerID || !modelID) && !variant) return null;
41652
- const context = {};
41653
- if (agent) context.agent = agent;
41654
- if (providerID && modelID) context.model = { providerID, modelID };
41655
- if (variant) context.variant = variant;
41656
- return context;
41897
+
41898
+ // src/plugin/vault-quota-refresh.ts
41899
+ async function checkAndPublishVaultQuota(input2, publishSidebar) {
41900
+ const report = await checkVaultQuota(input2);
41901
+ if (report.checked > 0 && !input2.signal.aborted) await publishSidebar();
41902
+ return report;
41657
41903
  }
41658
- function mergeContexts(base, patch) {
41904
+
41905
+ // src/plugin/vault-sidebar-projection.ts
41906
+ function quotaReadingForVaultRoute(route, state) {
41907
+ const stored = state.accounts[route.accountIdentity];
41908
+ return stored?.observed.routeId === route.routeId && stored.observed.credentialId === route.credentialId ? stored.quota : void 0;
41909
+ }
41910
+ function buildVaultSidebarProjection(pool, state, checkedAt = Date.now()) {
41911
+ const projection = buildSidebarMachineStateFromAccounts(
41912
+ pool.selector.rows.map((row) => {
41913
+ const quota = quotaReadingForVaultRoute(row.route, state);
41914
+ return {
41915
+ index: row.index,
41916
+ email: row.route.email,
41917
+ enabled: row.enabled,
41918
+ current: false,
41919
+ coolingDownUntil: row.coolingDownUntil,
41920
+ healthScore: pool.selector.healthTracker.getScore(row.index),
41921
+ cachedQuota: quota ? cachedQuotaOf(quota) : void 0,
41922
+ cachedQuotaUpdatedAt: quota?.cachedQuotaUpdatedAt ?? void 0
41923
+ };
41924
+ }),
41925
+ { checkedAt }
41926
+ );
41659
41927
  return {
41660
- agent: base.agent ?? patch.agent,
41661
- model: base.model ?? patch.model,
41662
- variant: base.variant ?? patch.variant
41928
+ ...projection,
41929
+ accounts: projection.accounts.map((account) => ({
41930
+ ...account,
41931
+ id: `vault-${account.id}`
41932
+ }))
41663
41933
  };
41664
41934
  }
41665
- function isComplete(context) {
41666
- return Boolean(context.agent && context.model && context.variant);
41667
- }
41668
- async function resolvePromptContext(client, sessionId) {
41669
- if (!client || !sessionId) return null;
41670
- const typedClient = client;
41671
- if (typeof typedClient.session?.messages !== "function") return null;
41672
- let messages = [];
41673
- try {
41674
- messages = extractMessages(
41675
- await Promise.resolve(
41676
- typedClient.session.messages({
41677
- path: { id: sessionId },
41678
- query: { limit: 100 }
41679
- })
41680
- )
41681
- );
41682
- } catch {
41683
- return null;
41935
+
41936
+ // src/plugin/background-vault-quota-refresh.ts
41937
+ var BackgroundVaultQuotaRefresh = class {
41938
+ constructor(options) {
41939
+ this.options = options;
41940
+ this.now = options.now ?? Date.now;
41941
+ this.random = options.random ?? Math.random;
41942
+ this.acquireLock = options.acquireLock ?? acquireFencedFileLock;
41684
41943
  }
41685
- if (messages.length === 0) return null;
41686
- let result = {};
41687
- for (let index = messages.length - 1; index >= 0; index--) {
41688
- if (getRole(messages[index]) !== "assistant") continue;
41689
- const context = extractFromMessage(messages[index]);
41690
- if (!context) continue;
41691
- result = mergeContexts(result, context);
41692
- if (isComplete(result)) return result;
41944
+ options;
41945
+ timer = null;
41946
+ inFlight = null;
41947
+ controller = null;
41948
+ disposed = false;
41949
+ started = false;
41950
+ now;
41951
+ random;
41952
+ acquireLock;
41953
+ start() {
41954
+ if (this.disposed || this.started) return;
41955
+ this.started = true;
41956
+ this.schedule(Math.floor(this.random() * 3e4));
41693
41957
  }
41694
- for (let index = messages.length - 1; index >= 0; index--) {
41695
- const context = extractFromMessage(messages[index]);
41696
- if (!context) continue;
41697
- result = mergeContexts(result, context);
41698
- if (isComplete(result)) return result;
41958
+ /** Custody notifications cancel admitted work as soon as authority changes. */
41959
+ abortTick() {
41960
+ this.controller?.abort();
41699
41961
  }
41700
- if (!result.agent && !result.model && !result.variant) return null;
41701
- return result;
41702
- }
41703
-
41704
- // src/plugin/commands.ts
41705
- var HANDLED_COMMAND_SENTINEL = "ANTIGRAVITY_COMMAND_HANDLED";
41706
- async function sendIgnoredMessage(client, sessionID, text2) {
41707
- const session = client.session;
41708
- const promptContext = await resolvePromptContext(client, sessionID);
41709
- const request = {
41710
- path: { id: sessionID },
41711
- body: {
41712
- noReply: true,
41713
- parts: [{ type: "text", text: text2, ignored: true }],
41714
- ...promptContext?.agent ? { agent: promptContext.agent } : {},
41715
- ...promptContext?.model ? { model: promptContext.model } : {},
41716
- ...promptContext?.variant ? { variant: promptContext.variant } : {}
41717
- }
41718
- };
41719
- if (typeof session?.promptAsync === "function") {
41720
- await session.promptAsync(request);
41721
- return;
41962
+ async dispose() {
41963
+ this.disposed = true;
41964
+ if (this.timer !== null) clearTimeout(this.timer);
41965
+ this.timer = null;
41966
+ this.abortTick();
41967
+ await this.inFlight;
41722
41968
  }
41723
- if (typeof session?.prompt === "function") {
41724
- await Promise.resolve(session.prompt(request));
41725
- return;
41969
+ schedule(delay) {
41970
+ if (this.disposed || !this.started) return;
41971
+ this.timer = setTimeout(() => {
41972
+ this.timer = null;
41973
+ void this.tick();
41974
+ }, delay);
41975
+ this.timer.unref?.();
41726
41976
  }
41727
- throw new Error(
41728
- "OpenCode session prompt API is unavailable for ignored replies."
41729
- );
41730
- }
41731
- function throwHandledCommandSentinel() {
41732
- throw new Error(HANDLED_COMMAND_SENTINEL);
41733
- }
41734
- function menuInvocation(push, sessionId) {
41735
- return {
41736
- ...sessionId !== void 0 ? { sessionId } : {},
41737
- notify(message, kind) {
41738
- push(
41977
+ /** One serialized tick; also used by deterministic composition tests. */
41978
+ tick() {
41979
+ if (this.disposed) return Promise.resolve();
41980
+ if (this.inFlight) return this.inFlight;
41981
+ const controller = new AbortController();
41982
+ this.controller = controller;
41983
+ let extraJitter = 0;
41984
+ this.inFlight = this.runTick(controller).catch(() => {
41985
+ extraJitter = 15e3;
41986
+ }).finally(() => {
41987
+ this.inFlight = null;
41988
+ this.controller = null;
41989
+ this.schedule(
41990
+ this.options.intervalMs + Math.floor(this.random() * this.options.intervalMs * 0.1) + extraJitter
41991
+ );
41992
+ });
41993
+ return this.inFlight;
41994
+ }
41995
+ async assertActive(controller) {
41996
+ if (this.disposed || await this.options.readAuthority() !== "vault")
41997
+ controller.abort();
41998
+ controller.signal.throwIfAborted();
41999
+ }
42000
+ async runTick(controller) {
42001
+ await this.assertActive(controller);
42002
+ ensureSidebarStateDir(this.options.sidebarStateFile);
42003
+ const lock = await this.acquireLock({
42004
+ path: this.options.sidebarStateFile,
42005
+ name: "bg-vault-quota-poll",
42006
+ ttlMs: 6e4,
42007
+ renew: true
42008
+ });
42009
+ if (!lock) return;
42010
+ let released = false;
42011
+ void lock.whenLost().then(() => {
42012
+ if (!released) controller.abort();
42013
+ });
42014
+ try {
42015
+ await this.assertActive(controller);
42016
+ await lock.assertOwned();
42017
+ const { source, pool } = await this.options.currentVaultPool();
42018
+ await this.assertActive(controller);
42019
+ await pool.sync();
42020
+ await this.assertActive(controller);
42021
+ const state = await this.options.readProviderState();
42022
+ await this.assertActive(controller);
42023
+ await lock.assertOwned();
42024
+ const threshold = Math.max(
42025
+ this.options.intervalMs - 6e4,
42026
+ Math.floor(this.options.intervalMs / 2)
42027
+ );
42028
+ const now = this.now();
42029
+ const due = pool.selector.rows.some((row) => {
42030
+ const quota = quotaReadingForVaultRoute(row.route, state);
42031
+ const at = quota?.cachedQuotaUpdatedAt;
42032
+ return quota?.cachedQuota == null || typeof at !== "number" || !Number.isFinite(at) || at < 0 || now - at >= threshold;
42033
+ });
42034
+ if (!due) return;
42035
+ await checkAndPublishVaultQuota(
41739
42036
  {
41740
- command: ANTIGRAVITY_MENU_COMMAND,
41741
- notify: { message, kind: kind ?? "info" }
42037
+ pool,
42038
+ signal: controller.signal,
42039
+ now: this.now,
42040
+ fetchReading: async (ref, signal) => {
42041
+ await this.assertActive(controller);
42042
+ const reading = await fetchVaultAccountQuota({
42043
+ source,
42044
+ ref,
42045
+ signal,
42046
+ logger: this.options.logger,
42047
+ transport: async (url, init, extra) => {
42048
+ await this.assertActive(controller);
42049
+ await lock.assertOwned();
42050
+ controller.signal.throwIfAborted();
42051
+ return this.options.transport(
42052
+ url,
42053
+ { ...init, signal: extra.signal ?? controller.signal },
42054
+ extra
42055
+ );
42056
+ }
42057
+ });
42058
+ await this.assertActive(controller);
42059
+ await lock.assertOwned();
42060
+ return reading;
42061
+ }
41742
42062
  },
41743
- sessionId
42063
+ async () => {
42064
+ await this.assertActive(controller);
42065
+ await lock.assertOwned();
42066
+ await this.options.publishSidebar();
42067
+ }
41744
42068
  );
42069
+ } finally {
42070
+ released = true;
42071
+ await lock.release().catch(() => {
42072
+ });
41745
42073
  }
42074
+ }
42075
+ };
42076
+
42077
+ // src/plugin/operator-settings.ts
42078
+ import { createHash as createHash18 } from "node:crypto";
42079
+ import { existsSync as existsSync14, readFileSync as readFileSync12 } from "node:fs";
42080
+ import { z as z4 } from "zod";
42081
+
42082
+ // src/plugin/config/operator-settings-schema.ts
42083
+ import { z as z2 } from "zod";
42084
+ var OperatorSettingsSchema = z2.object({
42085
+ routing: z2.object({
42086
+ cli_first: z2.boolean(),
42087
+ quota_style_fallback: z2.boolean()
42088
+ }),
42089
+ killswitch: z2.object({
42090
+ enabled: z2.boolean(),
42091
+ minimum_remaining_percent: z2.number().min(0).max(100),
42092
+ accounts: z2.record(z2.string(), z2.number().min(0).max(100)).optional()
42093
+ }),
42094
+ log_level: z2.enum(["error", "warn", "info", "debug", "trace"])
42095
+ });
42096
+ function emptyOperatorSettings() {
42097
+ return {
42098
+ routing: { cli_first: false, quota_style_fallback: false },
42099
+ killswitch: { enabled: false, minimum_remaining_percent: 5 },
42100
+ log_level: "info"
41746
42101
  };
41747
42102
  }
41748
- function createAntigravityCommandExecuteBefore(options) {
41749
- const connection = options.connection ?? {
41750
- isTuiConnected
41751
- };
41752
- return async (input2) => {
41753
- if (input2.command !== ANTIGRAVITY_MENU_COMMAND) return;
41754
- const opening = await options.open(input2.sessionID);
41755
- if (opening.kind === "menu") {
41756
- options.push(opening.payload, input2.sessionID);
41757
- } else {
41758
- options.push(
41759
- {
41760
- command: ANTIGRAVITY_MENU_COMMAND,
41761
- notify: { message: opening.message, kind: "warning" }
41762
- },
41763
- input2.sessionID
41764
- );
42103
+
42104
+ // src/plugin/config/writer.ts
42105
+ import { existsSync as existsSync13, readFileSync as readFileSync11 } from "node:fs";
42106
+ import { z as z3 } from "zod";
42107
+ async function writeOperatorConfig(options) {
42108
+ const target = existsSync13(options.projectConfigPath) ? options.projectConfigPath : options.userConfigPath;
42109
+ await writeOperatorConfigAt(target, options.operator);
42110
+ }
42111
+ async function writeOperatorConfigAt(target, settings) {
42112
+ const operator = OperatorSettingsSchema.parse(settings);
42113
+ const lock = await acquireFencedFileLock({
42114
+ path: target,
42115
+ name: "antigravity-operator",
42116
+ ttlMs: 5e3,
42117
+ renew: false
42118
+ });
42119
+ if (!lock) {
42120
+ throw new Error(
42121
+ `Could not acquire operator-config lock at ${target} (already held by another writer).`
42122
+ );
42123
+ }
42124
+ try {
42125
+ const existing = readExistingConfig(target);
42126
+ const merged = mergeOperator(existing, operator);
42127
+ await writeJsonAtomic(target, merged);
42128
+ } finally {
42129
+ await lock.release().catch(() => {
42130
+ });
42131
+ }
42132
+ }
42133
+ function readExistingConfig(target) {
42134
+ if (!existsSync13(target)) return {};
42135
+ try {
42136
+ const raw = readFileSync11(target, "utf-8");
42137
+ const parsed = JSON.parse(raw);
42138
+ if (parsed !== null && typeof parsed === "object" && !Array.isArray(parsed)) {
42139
+ return parsed;
41765
42140
  }
41766
- if (!connection.isTuiConnected(input2.sessionID)) {
41767
- await sendIgnoredMessage(
41768
- options.client,
41769
- input2.sessionID,
41770
- opening.kind === "menu" ? "The Antigravity menu opens in the OpenCode terminal interface." : opening.message
41771
- );
42141
+ return {};
42142
+ } catch {
42143
+ return {};
42144
+ }
42145
+ }
42146
+ function mergeOperator(existing, operator) {
42147
+ const next = { ...existing };
42148
+ next.operator = operator;
42149
+ return next;
42150
+ }
42151
+
42152
+ // src/plugin/operator-settings.ts
42153
+ var PartialOperatorSettingsSchema = z4.object({
42154
+ routing: z4.object({
42155
+ cli_first: z4.boolean().optional(),
42156
+ quota_style_fallback: z4.boolean().optional()
42157
+ }).optional(),
42158
+ killswitch: z4.object({
42159
+ enabled: z4.boolean().optional(),
42160
+ minimum_remaining_percent: z4.number().min(0).max(100).optional(),
42161
+ accounts: z4.record(z4.string(), z4.number().min(0).max(100)).optional()
42162
+ }).optional(),
42163
+ log_level: z4.enum(["error", "warn", "info", "debug", "trace"]).optional()
42164
+ });
42165
+ function createOperatorSettingsController(options) {
42166
+ let cached = null;
42167
+ let disposed = false;
42168
+ let pending = null;
42169
+ const loadFromDisk = () => {
42170
+ const existing = readOperatorFile(options.projectConfigPath);
42171
+ if (existing) return existing;
42172
+ const fromUser = readOperatorFile(options.userConfigPath);
42173
+ if (fromUser) return fromUser;
42174
+ return emptyOperatorSettings();
42175
+ };
42176
+ const persist = async (next) => {
42177
+ if (pending) await pending;
42178
+ pending = writeOperatorConfig({
42179
+ projectConfigPath: options.projectConfigPath,
42180
+ userConfigPath: options.userConfigPath,
42181
+ operator: next
42182
+ });
42183
+ try {
42184
+ await pending;
42185
+ } finally {
42186
+ pending = null;
41772
42187
  }
41773
- throwHandledCommandSentinel();
41774
42188
  };
41775
- }
41776
- function signInMenuSection(oauth) {
41777
42189
  return {
41778
- id: "sign-in",
41779
- title: "Sign in",
41780
- build() {
41781
- return {
41782
- lines: [
41783
- "Start a sign-in, open the link, then paste the address the browser ends on."
41784
- ],
41785
- actions: [
42190
+ get() {
42191
+ if (!cached) cached = loadFromDisk();
42192
+ return cached;
42193
+ },
42194
+ async update(mutator) {
42195
+ if (disposed) throw new Error("OperatorSettingsController is disposed");
42196
+ const current = cached ?? loadFromDisk();
42197
+ const draft = JSON.parse(
42198
+ JSON.stringify(current)
42199
+ );
42200
+ mutator(draft);
42201
+ const validated = OperatorSettingsSchema.parse(draft);
42202
+ cached = validated;
42203
+ await persist(validated);
42204
+ },
42205
+ async dispose() {
42206
+ if (disposed) return;
42207
+ disposed = true;
42208
+ if (pending) {
42209
+ try {
42210
+ await pending;
42211
+ } catch {
42212
+ }
42213
+ }
42214
+ }
42215
+ };
42216
+ }
42217
+ function createOperatorSettingsRegistry() {
42218
+ const entries = /* @__PURE__ */ new Map();
42219
+ const createEntry = (path5) => {
42220
+ let state;
42221
+ let chain = Promise.resolve();
42222
+ const read = () => {
42223
+ if (state === void 0) state = readOperatorFile(path5);
42224
+ return state;
42225
+ };
42226
+ return {
42227
+ path: path5,
42228
+ refs: 0,
42229
+ read,
42230
+ update(seed, mutator) {
42231
+ const run = chain.then(async () => {
42232
+ const draft = cloneSettings(read() ?? seed());
42233
+ mutator(draft);
42234
+ const validated = OperatorSettingsSchema.parse(draft);
42235
+ state = validated;
42236
+ await writeOperatorConfigAt(path5, validated);
42237
+ });
42238
+ chain = run.catch(() => {
42239
+ });
42240
+ return run;
42241
+ }
42242
+ };
42243
+ };
42244
+ const registry = {
42245
+ livePaths: () => [...entries.keys()],
42246
+ acquire(path5) {
42247
+ const key = canonicalizeOwnedPath(path5);
42248
+ let entry = entries.get(key);
42249
+ if (!entry) {
42250
+ entry = createEntry(key);
42251
+ entries.set(key, entry);
42252
+ }
42253
+ entry.refs++;
42254
+ return entry;
42255
+ },
42256
+ release(entry) {
42257
+ entry.refs--;
42258
+ if (entry.refs <= 0 && entries.get(entry.path) === entry) {
42259
+ entries.delete(entry.path);
42260
+ }
42261
+ }
42262
+ };
42263
+ return registry;
42264
+ }
42265
+ var processOperatorSettingsRegistry = createOperatorSettingsRegistry();
42266
+ function cloneSettings(settings) {
42267
+ return JSON.parse(JSON.stringify(settings));
42268
+ }
42269
+ function readOperatorFile(path5) {
42270
+ try {
42271
+ const raw = readFileSync12(path5, "utf-8");
42272
+ const parsed = JSON.parse(raw);
42273
+ if (parsed === null || typeof parsed !== "object" || !("operator" in parsed)) {
42274
+ return null;
42275
+ }
42276
+ const partial = PartialOperatorSettingsSchema.safeParse(
42277
+ parsed.operator
42278
+ );
42279
+ if (!partial.success) return null;
42280
+ return mergeWithDefaults(partial.data);
42281
+ } catch {
42282
+ return null;
42283
+ }
42284
+ }
42285
+ function mergeWithDefaults(partial) {
42286
+ const defaults = emptyOperatorSettings();
42287
+ return {
42288
+ routing: { ...defaults.routing, ...partial.routing ?? {} },
42289
+ killswitch: {
42290
+ ...defaults.killswitch,
42291
+ ...partial.killswitch ?? {},
42292
+ accounts: {
42293
+ ...defaults.killswitch.accounts ?? {},
42294
+ ...partial.killswitch?.accounts ?? {}
42295
+ }
42296
+ },
42297
+ log_level: partial.log_level ?? defaults.log_level
42298
+ };
42299
+ }
42300
+ function accountKeyForRefreshToken(refreshToken) {
42301
+ return createHash18("sha256").update(refreshToken).digest("hex").slice(0, 12);
42302
+ }
42303
+
42304
+ // src/plugin/command-apply.ts
42305
+ function operatorMenuSettings(settings) {
42306
+ return {
42307
+ read() {
42308
+ const current = settings.get();
42309
+ return {
42310
+ routing: {
42311
+ cliFirst: current.routing.cli_first,
42312
+ quotaStyleFallback: current.routing.quota_style_fallback
42313
+ },
42314
+ killswitch: {
42315
+ enabled: current.killswitch.enabled,
42316
+ minimumRemainingPercent: current.killswitch.minimum_remaining_percent
42317
+ }
42318
+ };
42319
+ },
42320
+ updateRouting: (next) => settings.update((draft) => {
42321
+ draft.routing.cli_first = next.cliFirst;
42322
+ draft.routing.quota_style_fallback = next.quotaStyleFallback;
42323
+ }),
42324
+ updateKillswitch: (next) => settings.update((draft) => {
42325
+ draft.killswitch.enabled = next.enabled;
42326
+ draft.killswitch.minimum_remaining_percent = next.minimumRemainingPercent;
42327
+ })
42328
+ };
42329
+ }
42330
+ var LOG_LEVEL_CHOICES = ["error", "warn", "info", "debug", "trace"];
42331
+ function diagnosticsMenuSection(options) {
42332
+ return {
42333
+ title: "Diagnostics",
42334
+ build() {
42335
+ const level = options.settings.get().log_level;
42336
+ const dumping = options.dump.isEnabled();
42337
+ return {
42338
+ lines: [
42339
+ `Gemini request dump: ${dumping ? "on" : "off"}`,
42340
+ `Log level: ${level}`
42341
+ ],
42342
+ actions: [
41786
42343
  {
41787
- id: "start",
41788
- label: "Start sign-in",
41789
- run: async ({ invocation }) => {
41790
- const sessionId = invocation.sessionId;
41791
- if (sessionId === void 0)
41792
- return {
41793
- ok: false,
41794
- text: "Sign-in needs a session; run /antigravity from one.",
41795
- code: "refused"
41796
- };
41797
- const started = await oauth.start(sessionId);
41798
- return `Open this link to sign in, then choose Finish sign-in:
41799
- ${started.url}`;
42344
+ id: "dump",
42345
+ label: dumping ? "Stop dumping requests" : "Dump requests",
42346
+ run: async () => {
42347
+ options.dump.setEnabled(!dumping);
42348
+ return `Gemini request dump ${dumping ? "off" : "on"}`;
41800
42349
  }
41801
42350
  },
41802
42351
  {
41803
- id: "finish",
41804
- label: "Finish sign-in",
42352
+ id: "logging",
42353
+ label: "Change log level",
41805
42354
  knobs: [
41806
42355
  {
41807
- kind: "text",
41808
- id: "callback",
41809
- label: "Address or code from the browser",
41810
- masked: true,
41811
- required: true
41812
- },
41813
- { kind: "text", id: "label", label: "Label (optional)" }
42356
+ kind: "choice",
42357
+ id: "level",
42358
+ label: "Level",
42359
+ choices: LOG_LEVEL_CHOICES.map((value) => ({
42360
+ value,
42361
+ label: value
42362
+ })),
42363
+ value: level
42364
+ }
41814
42365
  ],
41815
- run: async ({ values, invocation }) => {
41816
- const sessionId = invocation.sessionId;
41817
- const callback = values.callback;
41818
- if (sessionId === void 0 || typeof callback !== "string")
42366
+ run: async ({ values }) => {
42367
+ const next = LOG_LEVEL_CHOICES.find(
42368
+ (candidate) => candidate === values.level
42369
+ );
42370
+ if (next === void 0)
41819
42371
  return {
41820
42372
  ok: false,
41821
- text: "Paste the address the browser ended on.",
42373
+ text: "Choose a log level",
41822
42374
  code: "invalid-input"
41823
42375
  };
41824
- const label = typeof values.label === "string" && values.label.trim() !== "" ? values.label.trim() : void 0;
41825
- const finished = label === void 0 ? await oauth.finish(sessionId, callback) : await oauth.finish(sessionId, callback, label);
41826
- return finished.text;
42376
+ await options.settings.update((draft) => {
42377
+ draft.log_level = next;
42378
+ });
42379
+ options.applyLogLevel(next);
42380
+ return `Log level set to ${next}`;
41827
42381
  }
41828
42382
  }
41829
42383
  ]
@@ -41831,419 +42385,659 @@ ${started.url}`;
41831
42385
  }
41832
42386
  };
41833
42387
  }
41834
- async function createOpenCodeAntigravityMenu(options) {
41835
- return createAntigravityCommandMenu({
41836
- source: "repository",
41837
- commands: options.commands ?? await loadCommonAuthCommands(),
41838
- accounts: options.accounts,
41839
- settings: operatorMenuSettings(options.settings),
41840
- diagnostics: diagnosticsMenuSection(options),
41841
- ...options.refreshQuota ? { refreshQuota: options.refreshQuota } : {},
41842
- ...options.accountLimits ? { accountLimits: options.accountLimits } : {},
41843
- ...options.login ? { login: options.login } : {},
41844
- extras: [
41845
- ...options.signIn ? [signInMenuSection(options.signIn)] : [],
41846
- ...options.vault ? [options.vault] : []
41847
- ]
41848
- });
41849
- }
41850
- function storeRefusal(opening) {
41851
- return new Error(
41852
- opening.status === "refused" && typeof opening.message === "string" ? opening.message : "The Antigravity account store cannot be opened"
41853
- );
41854
- }
41855
- function createAccountTargets(loader) {
41856
- const isReady = (opening) => opening.status === "ready" && opening.repository !== void 0;
42388
+ var STALE_FAILURES = /* @__PURE__ */ new Set(["attribution", "unknown-row", "id-removed"]);
42389
+ function createStoreAccountLimits(input2) {
41857
42390
  return {
41858
- async accountSource() {
41859
- const opening = await loader.accountStore();
41860
- if (isReady(opening))
41861
- return { kind: "store", repository: opening.repository };
41862
- if (opening.status === "initialization-required") return { kind: "none" };
41863
- if (loader.usesPoolFile(opening)) return { kind: "pool-file" };
41864
- throw storeRefusal(opening);
42391
+ async read(ref) {
42392
+ const read = await input2.repository.read();
42393
+ if (read.status !== "ready") return null;
42394
+ const row = read.rows.find((candidate) => sameRowRef(candidate.ref, ref));
42395
+ const token2 = row?.credential?.refreshToken;
42396
+ if (token2 === void 0) return null;
42397
+ return input2.settings.get().killswitch.accounts?.[accountKeyForRefreshToken(token2)] ?? null;
41865
42398
  },
41866
- async loginTarget() {
41867
- const opening = await loader.initializeFreshStore();
41868
- if (isReady(opening)) return opening.repository;
41869
- if (opening.status !== "initialization-required" && loader.usesPoolFile(opening))
41870
- return "pool-file";
41871
- throw storeRefusal(opening);
41872
- }
42399
+ async write(ref, minimumRemainingPercent) {
42400
+ try {
42401
+ await input2.repository.updateMetadata(ref, async (_current, row) => {
42402
+ const token2 = row.credential?.refreshToken;
42403
+ if (token2 === void 0)
42404
+ throw new Error("The account holds no stored credential");
42405
+ const key = accountKeyForRefreshToken(token2);
42406
+ await input2.settings.update((draft) => {
42407
+ const accounts = { ...draft.killswitch.accounts ?? {} };
42408
+ if (minimumRemainingPercent === null) delete accounts[key];
42409
+ else accounts[key] = minimumRemainingPercent;
42410
+ draft.killswitch.accounts = accounts;
42411
+ });
42412
+ return { kind: "keep" };
42413
+ });
42414
+ } catch (error) {
42415
+ if (error instanceof AccountRepositoryError && STALE_FAILURES.has(error.failure.kind))
42416
+ return "stale";
42417
+ throw error;
42418
+ }
42419
+ return "applied";
42420
+ }
41873
42421
  };
41874
42422
  }
41875
- async function createOpenCodeVaultAntigravityMenu(options) {
41876
- return createAntigravityCommandMenu({
41877
- source: "sections",
41878
- commands: options.commands ?? await loadCommonAuthCommands(),
41879
- sections: {
41880
- ...options.sections,
41881
- ...antigravitySettingsSections(operatorMenuSettings(options.settings))
41882
- },
41883
- diagnostics: diagnosticsMenuSection(options),
41884
- extras: options.vault ? [options.vault] : []
41885
- });
41886
- }
41887
42423
 
41888
- // src/plugin/catalog.ts
41889
- function applyAntigravityProviderCatalog(config, providerId) {
41890
- const mutableConfig = config;
41891
- mutableConfig.provider ??= {};
41892
- const providerConfig = mutableConfig.provider[providerId] ?? {};
41893
- providerConfig.models = {
41894
- ...providerConfig.models ?? {},
41895
- ...OPENCODE_MODEL_DEFINITIONS
41896
- };
41897
- providerConfig.whitelist = getAntigravityOpencodeModelIds();
41898
- mutableConfig.provider[providerId] = providerConfig;
42424
+ // src/plugin/prompt-context.ts
42425
+ function isRecord15(value) {
42426
+ return typeof value === "object" && value !== null;
41899
42427
  }
41900
- function registerAntigravityCommands(config) {
41901
- const mutableConfig = config;
41902
- mutableConfig.command = {
41903
- ...mutableConfig.command ?? {},
41904
- [ANTIGRAVITY_MENU_COMMAND]: {
41905
- template: ANTIGRAVITY_MENU_COMMAND,
41906
- description: "Open the Antigravity menu: accounts, quota, routing, limits and diagnostics."
41907
- }
41908
- };
42428
+ function extractMessages(response) {
42429
+ if (Array.isArray(response)) return response;
42430
+ if (isRecord15(response) && Array.isArray(response.data)) return response.data;
42431
+ return [];
41909
42432
  }
41910
-
41911
- // src/plugin/command-data.ts
41912
- import { createHash as createHash19 } from "node:crypto";
41913
- var QUOTA_GROUP_LABELS = {
41914
- gemini: "Gemini",
41915
- "non-gemini": "Non-Gemini"
41916
- };
41917
- var SUPPORTED_QUOTA_KEYS = [
41918
- "gemini",
41919
- "non-gemini"
41920
- ];
41921
- function toCommandAccountRow(entry) {
41922
- const rawCached = entry.cachedQuotaAccountId && entry.cachedQuotaAccountId !== quotaAccountIdentity3(entry.refreshToken) ? void 0 : entry.cachedQuota;
41923
- const cached = normalizeLegacyCachedQuota2(
41924
- rawCached
41925
- );
41926
- const quota = [];
41927
- for (const key of SUPPORTED_QUOTA_KEYS) {
41928
- const cachedEntry = cached?.[key];
41929
- if (!cachedEntry) continue;
41930
- const fraction = cachedEntry.remainingFraction;
41931
- const remainingPercent = typeof fraction === "number" && Number.isFinite(fraction) ? Math.round(fraction * 100) : null;
41932
- let resetAt;
41933
- if (typeof cachedEntry.resetTime === "string" && cachedEntry.resetTime.length > 0) {
41934
- const parsed = Date.parse(cachedEntry.resetTime);
41935
- if (Number.isFinite(parsed)) resetAt = parsed;
41936
- }
41937
- const windows = cachedEntry.windows?.length ? cachedEntry.windows.map((w) => ({
41938
- window: w.window,
41939
- remainingPercent: Math.round(w.remainingFraction * 100),
41940
- resetAt: typeof w.resetTime === "string" && w.resetTime.length > 0 ? (() => {
41941
- const parsed = Date.parse(w.resetTime);
41942
- return Number.isFinite(parsed) ? parsed : void 0;
41943
- })() : void 0
41944
- })) : void 0;
41945
- quota.push({
41946
- key,
41947
- label: QUOTA_GROUP_LABELS[key],
41948
- remainingPercent,
41949
- resetAt,
41950
- windows
41951
- });
41952
- }
41953
- const label = `Account ${entry.index + 1}`;
42433
+ function getRole(message) {
42434
+ if (!isRecord15(message) || !isRecord15(message.info)) return void 0;
42435
+ return typeof message.info.role === "string" ? message.info.role : void 0;
42436
+ }
42437
+ function extractFromMessage(message) {
42438
+ if (!isRecord15(message) || !isRecord15(message.info)) return null;
42439
+ const info = message.info;
42440
+ const modelInfo = isRecord15(info.model) ? info.model : void 0;
42441
+ const agent = typeof info.agent === "string" ? info.agent : void 0;
42442
+ const providerID = typeof modelInfo?.providerID === "string" ? modelInfo.providerID : typeof info.providerID === "string" ? info.providerID : void 0;
42443
+ const modelID = typeof modelInfo?.modelID === "string" ? modelInfo.modelID : typeof info.modelID === "string" ? info.modelID : void 0;
42444
+ const variant = typeof modelInfo?.variant === "string" ? modelInfo.variant : typeof info.variant === "string" ? info.variant : void 0;
42445
+ if (!agent && (!providerID || !modelID) && !variant) return null;
42446
+ const context = {};
42447
+ if (agent) context.agent = agent;
42448
+ if (providerID && modelID) context.model = { providerID, modelID };
42449
+ if (variant) context.variant = variant;
42450
+ return context;
42451
+ }
42452
+ function mergeContexts(base, patch) {
41954
42453
  return {
41955
- id: `acct-${entry.index}`,
41956
- index: entry.index,
41957
- label,
41958
- enabled: entry.enabled,
41959
- current: entry.active,
41960
- coolingDownUntil: entry.coolingDownUntil,
41961
- healthScore: entry.healthScore,
41962
- cachedQuotaUpdatedAt: entry.cachedQuotaUpdatedAt,
41963
- quota,
41964
- tier: toCapturedTier(entry)
42454
+ agent: base.agent ?? patch.agent,
42455
+ model: base.model ?? patch.model,
42456
+ variant: base.variant ?? patch.variant
41965
42457
  };
41966
42458
  }
41967
- function quotaAccountIdentity3(refreshToken) {
41968
- return createHash19("sha256").update(refreshToken).digest("hex").slice(0, 16);
42459
+ function isComplete(context) {
42460
+ return Boolean(context.agent && context.model && context.variant);
41969
42461
  }
41970
- function projectCommandAccountRows(storage) {
41971
- if (!storage) return [];
41972
- const activeIndex = storage.activeIndexByFamily?.claude ?? storage.activeIndex;
41973
- return storage.accounts.map(
41974
- (entry, index) => toCommandAccountRow({
41975
- index,
41976
- refreshToken: entry.refreshToken,
41977
- label: entry.label,
41978
- enabled: entry.enabled !== false,
41979
- active: index === activeIndex,
41980
- cachedQuota: entry.cachedQuota,
41981
- cachedQuotaUpdatedAt: entry.cachedQuotaUpdatedAt,
41982
- cachedQuotaAccountId: entry.cachedQuotaAccountId
41983
- })
41984
- );
42462
+ async function resolvePromptContext(client, sessionId) {
42463
+ if (!client || !sessionId) return null;
42464
+ const typedClient = client;
42465
+ if (typeof typedClient.session?.messages !== "function") return null;
42466
+ let messages = [];
42467
+ try {
42468
+ messages = extractMessages(
42469
+ await Promise.resolve(
42470
+ typedClient.session.messages({
42471
+ path: { id: sessionId },
42472
+ query: { limit: 100 }
42473
+ })
42474
+ )
42475
+ );
42476
+ } catch {
42477
+ return null;
42478
+ }
42479
+ if (messages.length === 0) return null;
42480
+ let result = {};
42481
+ for (let index = messages.length - 1; index >= 0; index--) {
42482
+ if (getRole(messages[index]) !== "assistant") continue;
42483
+ const context = extractFromMessage(messages[index]);
42484
+ if (!context) continue;
42485
+ result = mergeContexts(result, context);
42486
+ if (isComplete(result)) return result;
42487
+ }
42488
+ for (let index = messages.length - 1; index >= 0; index--) {
42489
+ const context = extractFromMessage(messages[index]);
42490
+ if (!context) continue;
42491
+ result = mergeContexts(result, context);
42492
+ if (isComplete(result)) return result;
42493
+ }
42494
+ if (!result.agent && !result.model && !result.variant) return null;
42495
+ return result;
41985
42496
  }
41986
42497
 
41987
- // src/plugin/dependencies.ts
41988
- import { homedir as homedir11 } from "node:os";
41989
- import { join as join26 } from "node:path";
41990
- function defaultFilesystemRoots() {
41991
- const xdgConfig2 = process.env.XDG_CONFIG_HOME ?? join26(homedir11(), ".config");
41992
- const xdgState2 = process.env.XDG_STATE_HOME ?? join26(homedir11(), ".local", "state");
41993
- return {
41994
- projectRoot: process.cwd(),
41995
- userConfigRoot: join26(xdgConfig2, "opencode"),
41996
- sidebarStateRoot: join26(xdgState2, "cortexkit", "antigravity-auth"),
41997
- rpcRoot: join26(xdgState2, "cortexkit", "antigravity-auth", "rpc")
42498
+ // src/plugin/commands.ts
42499
+ var HANDLED_COMMAND_SENTINEL = "ANTIGRAVITY_COMMAND_HANDLED";
42500
+ async function sendIgnoredMessage(client, sessionID, text2) {
42501
+ const session = client.session;
42502
+ const promptContext = await resolvePromptContext(client, sessionID);
42503
+ const request = {
42504
+ path: { id: sessionID },
42505
+ body: {
42506
+ noReply: true,
42507
+ parts: [{ type: "text", text: text2, ignored: true }],
42508
+ ...promptContext?.agent ? { agent: promptContext.agent } : {},
42509
+ ...promptContext?.model ? { model: promptContext.model } : {},
42510
+ ...promptContext?.variant ? { variant: promptContext.variant } : {}
42511
+ }
41998
42512
  };
42513
+ if (typeof session?.promptAsync === "function") {
42514
+ await session.promptAsync(request);
42515
+ return;
42516
+ }
42517
+ if (typeof session?.prompt === "function") {
42518
+ await Promise.resolve(session.prompt(request));
42519
+ return;
42520
+ }
42521
+ throw new Error(
42522
+ "OpenCode session prompt API is unavailable for ignored replies."
42523
+ );
41999
42524
  }
42000
- function resolvePluginDependencies(overrides = {}) {
42001
- const fetchImpl = overrides.fetchImpl ?? ((input2, init) => globalThis.fetch(input2, init));
42002
- const agyTransport = overrides.agyTransport ?? fetchWithAgyCliTransport;
42003
- const roots = {
42004
- ...defaultFilesystemRoots(),
42005
- ...overrides.filesystemRoots
42525
+ function throwHandledCommandSentinel() {
42526
+ throw new Error(HANDLED_COMMAND_SENTINEL);
42527
+ }
42528
+ function menuInvocation(push, sessionId) {
42529
+ return {
42530
+ ...sessionId !== void 0 ? { sessionId } : {},
42531
+ notify(message, kind) {
42532
+ push(
42533
+ {
42534
+ command: ANTIGRAVITY_MENU_COMMAND,
42535
+ notify: { message, kind: kind ?? "info" }
42536
+ },
42537
+ sessionId
42538
+ );
42539
+ }
42006
42540
  };
42007
- const oauth = {
42008
- authorize: overrides.oauth?.authorize ?? authorizeAntigravity,
42009
- exchange: overrides.oauth?.exchange ?? exchangeAntigravity
42541
+ }
42542
+ function createAntigravityCommandExecuteBefore(options) {
42543
+ const connection = options.connection ?? {
42544
+ isTuiConnected
42010
42545
  };
42011
- const clock = {
42012
- now: overrides.clock?.now ?? (() => Date.now()),
42013
- random: overrides.clock?.random ?? Math.random,
42014
- sleep: overrides.clock?.sleep ?? defaultSleep
42546
+ return async (input2) => {
42547
+ if (input2.command !== ANTIGRAVITY_MENU_COMMAND) return;
42548
+ const opening = await options.open(input2.sessionID);
42549
+ if (opening.kind === "menu") {
42550
+ options.push(opening.payload, input2.sessionID);
42551
+ } else {
42552
+ options.push(
42553
+ {
42554
+ command: ANTIGRAVITY_MENU_COMMAND,
42555
+ notify: { message: opening.message, kind: "warning" }
42556
+ },
42557
+ input2.sessionID
42558
+ );
42559
+ }
42560
+ if (!connection.isTuiConnected(input2.sessionID)) {
42561
+ await sendIgnoredMessage(
42562
+ options.client,
42563
+ input2.sessionID,
42564
+ opening.kind === "menu" ? "The Antigravity menu opens in the OpenCode terminal interface." : opening.message
42565
+ );
42566
+ }
42567
+ throwHandledCommandSentinel();
42015
42568
  };
42569
+ }
42570
+ function signInMenuSection(oauth) {
42016
42571
  return {
42017
- fetchImpl,
42018
- agyTransport,
42019
- filesystemRoots: roots,
42020
- oauth,
42021
- clock
42572
+ id: "sign-in",
42573
+ title: "Sign in",
42574
+ build() {
42575
+ return {
42576
+ lines: [
42577
+ "Start a sign-in, open the link, then paste the address the browser ends on."
42578
+ ],
42579
+ actions: [
42580
+ {
42581
+ id: "start",
42582
+ label: "Start sign-in",
42583
+ run: async ({ invocation }) => {
42584
+ const sessionId = invocation.sessionId;
42585
+ if (sessionId === void 0)
42586
+ return {
42587
+ ok: false,
42588
+ text: "Sign-in needs a session; run /antigravity from one.",
42589
+ code: "refused"
42590
+ };
42591
+ const started = await oauth.start(sessionId);
42592
+ return `Open this link to sign in, then choose Finish sign-in:
42593
+ ${started.url}`;
42594
+ }
42595
+ },
42596
+ {
42597
+ id: "finish",
42598
+ label: "Finish sign-in",
42599
+ knobs: [
42600
+ {
42601
+ kind: "text",
42602
+ id: "callback",
42603
+ label: "Address or code from the browser",
42604
+ masked: true,
42605
+ required: true
42606
+ },
42607
+ { kind: "text", id: "label", label: "Label (optional)" }
42608
+ ],
42609
+ run: async ({ values, invocation }) => {
42610
+ const sessionId = invocation.sessionId;
42611
+ const callback = values.callback;
42612
+ if (sessionId === void 0 || typeof callback !== "string")
42613
+ return {
42614
+ ok: false,
42615
+ text: "Paste the address the browser ended on.",
42616
+ code: "invalid-input"
42617
+ };
42618
+ const label = typeof values.label === "string" && values.label.trim() !== "" ? values.label.trim() : void 0;
42619
+ const finished = label === void 0 ? await oauth.finish(sessionId, callback) : await oauth.finish(sessionId, callback, label);
42620
+ return finished.text;
42621
+ }
42622
+ }
42623
+ ]
42624
+ };
42625
+ }
42022
42626
  };
42023
42627
  }
42024
- async function defaultSleep(ms, signal) {
42025
- if (ms <= 0) return;
42026
- await new Promise((resolve12, reject) => {
42027
- const timer = setTimeout(() => {
42028
- signal?.removeEventListener("abort", onAbort);
42029
- resolve12();
42030
- }, ms);
42031
- timer.unref?.();
42032
- const onAbort = () => {
42033
- clearTimeout(timer);
42034
- reject(
42035
- signal?.reason instanceof Error ? signal.reason : new Error("Aborted")
42036
- );
42037
- };
42038
- signal?.addEventListener("abort", onAbort, { once: true });
42628
+ async function createOpenCodeAntigravityMenu(options) {
42629
+ return createAntigravityCommandMenu({
42630
+ source: "repository",
42631
+ commands: options.commands ?? await loadCommonAuthCommands(),
42632
+ accounts: options.accounts,
42633
+ settings: operatorMenuSettings(options.settings),
42634
+ diagnostics: diagnosticsMenuSection(options),
42635
+ ...options.refreshQuota ? { refreshQuota: options.refreshQuota } : {},
42636
+ ...options.accountLimits ? { accountLimits: options.accountLimits } : {},
42637
+ ...options.login ? { login: options.login } : {},
42638
+ extras: [
42639
+ ...options.signIn ? [signInMenuSection(options.signIn)] : [],
42640
+ ...options.vault ? [options.vault] : []
42641
+ ]
42039
42642
  });
42040
42643
  }
42041
-
42042
- // src/plugin/event-handler.ts
42043
- function createEventHandler({
42044
- client,
42045
- config,
42046
- directory,
42047
- lifecycle,
42048
- sessionRegistry,
42049
- sessionRecovery,
42050
- updateChecker,
42051
- logger: logger2
42052
- }) {
42053
- return async (input2) => {
42054
- await updateChecker.event(input2);
42055
- if (input2.event.type === "session.created") {
42056
- const properties2 = input2.event.properties;
42057
- const sessionId = properties2?.info?.id;
42058
- const parentSessionId = properties2?.info?.parentID ?? null;
42059
- if (sessionId) {
42060
- sessionRegistry.register(sessionId, parentSessionId);
42061
- }
42062
- if (parentSessionId) {
42063
- logger2.debug("child-session-detected", {
42064
- sessionId,
42065
- parentID: parentSessionId
42066
- });
42067
- } else {
42068
- const previousSummary = lifecycle.getAccountManager()?.getSessionSummary();
42069
- if (previousSummary && (previousSummary.totalClaude > 0 || previousSummary.totalGemini > 0)) {
42070
- logger2.debug("prev-session-quota-summary", {
42071
- durationMinutes: previousSummary.durationMinutes,
42072
- totalClaude: previousSummary.totalClaude,
42073
- totalGemini: previousSummary.totalGemini,
42074
- requestsPerHour: previousSummary.requestsPerHour,
42075
- accountsUsed: previousSummary.accountsUsed
42076
- });
42077
- }
42078
- logger2.debug("root-session-detected", { sessionId });
42079
- }
42080
- }
42081
- if (input2.event.type === "session.deleted") {
42082
- const properties2 = input2.event.properties;
42083
- const sessionId = properties2?.sessionID ?? properties2?.info?.id;
42084
- if (sessionId) {
42085
- sessionRegistry.delete(sessionId);
42086
- lifecycle.getAccountManager()?.deleteSessionState(sessionId);
42087
- const eventLogger = logger2;
42088
- void removeSidebarActiveRouting(sessionId).catch((error2) => {
42089
- eventLogger.debug("sidebar-route-remove-failed", {
42090
- sessionId,
42091
- error: String(error2)
42092
- });
42093
- });
42094
- }
42095
- }
42096
- if (!sessionRecovery || input2.event.type !== "session.error") {
42097
- return;
42098
- }
42099
- const properties = input2.event.properties;
42100
- const sessionID = properties?.sessionID;
42101
- const messageID = properties?.messageID;
42102
- const error = properties?.error;
42103
- if (!sessionRecovery.isRecoverableError(error)) {
42104
- return;
42105
- }
42106
- const recovered = await sessionRecovery.handleSessionRecovery({
42107
- id: messageID,
42108
- role: "assistant",
42109
- sessionID,
42110
- error
42111
- });
42112
- if (!recovered || !sessionID || !config.auto_resume) {
42113
- return;
42114
- }
42115
- await client.session.prompt({
42116
- path: { id: sessionID },
42117
- body: { parts: [{ type: "text", text: config.resume_text }] },
42118
- query: { directory }
42119
- }).catch(() => {
42120
- });
42121
- const successToast = getRecoverySuccessToast();
42122
- const isChildSession = sessionRegistry.getParentSessionId(sessionID) !== null;
42123
- logger2.debug("recovery-toast", {
42124
- ...successToast,
42125
- isChildSession,
42126
- toastScope: config.toast_scope
42127
- });
42128
- if (config.toast_scope === "root_only" && isChildSession) {
42129
- return;
42644
+ function storeRefusal(opening) {
42645
+ return new Error(
42646
+ opening.status === "refused" && typeof opening.message === "string" ? opening.message : "The Antigravity account store cannot be opened"
42647
+ );
42648
+ }
42649
+ function createAccountTargets(loader) {
42650
+ const isReady = (opening) => opening.status === "ready" && opening.repository !== void 0;
42651
+ return {
42652
+ async accountSource() {
42653
+ const opening = await loader.accountStore();
42654
+ if (isReady(opening))
42655
+ return { kind: "store", repository: opening.repository };
42656
+ if (opening.status === "initialization-required") return { kind: "none" };
42657
+ if (loader.usesPoolFile(opening)) return { kind: "pool-file" };
42658
+ throw storeRefusal(opening);
42659
+ },
42660
+ async loginTarget() {
42661
+ const opening = await loader.initializeFreshStore();
42662
+ if (isReady(opening)) return opening.repository;
42663
+ if (opening.status !== "initialization-required" && loader.usesPoolFile(opening))
42664
+ return "pool-file";
42665
+ throw storeRefusal(opening);
42130
42666
  }
42131
- await client.tui.showToast({
42132
- body: {
42133
- title: successToast.title,
42134
- message: successToast.message,
42135
- variant: "success"
42136
- }
42137
- }).catch(() => {
42138
- });
42139
42667
  };
42140
42668
  }
42669
+ async function createOpenCodeVaultAntigravityMenu(options) {
42670
+ return createAntigravityCommandMenu({
42671
+ source: "sections",
42672
+ commands: options.commands ?? await loadCommonAuthCommands(),
42673
+ sections: {
42674
+ ...options.sections,
42675
+ ...antigravitySettingsSections(operatorMenuSettings(options.settings))
42676
+ },
42677
+ diagnostics: diagnosticsMenuSection(options),
42678
+ extras: options.vault ? [options.vault] : []
42679
+ });
42680
+ }
42141
42681
 
42142
- // src/plugin/errors.ts
42143
- var AntigravityKillswitchError = class extends Error {
42144
- family;
42145
- model;
42146
- thresholdPercent;
42147
- summaries;
42148
- constructor(input2) {
42149
- super(
42150
- input2.message ?? `Antigravity killswitch: all ${input2.summaries.length} account(s) under ${input2.thresholdPercent}% quota for ${input2.family}. Refresh quota or raise the threshold via /antigravity-killswitch.`
42151
- );
42152
- this.name = "AntigravityKillswitchError";
42153
- this.family = input2.family;
42154
- this.model = input2.model;
42155
- this.thresholdPercent = input2.thresholdPercent;
42156
- this.summaries = input2.summaries;
42157
- }
42158
- };
42682
+ // src/plugin/catalog.ts
42683
+ function applyAntigravityProviderCatalog(config, providerId) {
42684
+ const mutableConfig = config;
42685
+ mutableConfig.provider ??= {};
42686
+ const providerConfig = mutableConfig.provider[providerId] ?? {};
42687
+ providerConfig.models = {
42688
+ ...providerConfig.models ?? {},
42689
+ ...OPENCODE_MODEL_DEFINITIONS
42690
+ };
42691
+ providerConfig.whitelist = getAntigravityOpencodeModelIds();
42692
+ mutableConfig.provider[providerId] = providerConfig;
42693
+ }
42694
+ function registerAntigravityCommands(config) {
42695
+ const mutableConfig = config;
42696
+ mutableConfig.command = {
42697
+ ...mutableConfig.command ?? {},
42698
+ [ANTIGRAVITY_MENU_COMMAND]: {
42699
+ template: ANTIGRAVITY_MENU_COMMAND,
42700
+ description: "Open the Antigravity menu: accounts, quota, routing, limits and diagnostics."
42701
+ }
42702
+ };
42703
+ }
42159
42704
 
42160
- // src/plugin/fetch/retry-state.ts
42161
- var MAX_CONSECUTIVE_FAILURES = 5;
42162
- var FAILURE_COOLDOWN_MS = 3e4;
42163
- var FAILURE_STATE_RESET_MS = 12e4;
42164
- var RATE_LIMIT_DEDUP_WINDOW_MS = 2e3;
42165
- var RATE_LIMIT_STATE_RESET_MS = 12e4;
42166
- var RATE_LIMIT_TOAST_COOLDOWN_MS = 5e3;
42167
- var MAX_MAP_ENTRIES = 100;
42168
- var DISPOSED_BACKOFF = {
42169
- attempt: 1,
42170
- delayMs: 1e3,
42171
- isDuplicate: false
42172
- };
42173
- var DISPOSED_FAILURE = {
42174
- failures: 0,
42175
- shouldCooldown: false,
42176
- cooldownMs: 0
42705
+ // src/plugin/command-data.ts
42706
+ import { createHash as createHash19 } from "node:crypto";
42707
+ var QUOTA_GROUP_LABELS = {
42708
+ gemini: "Gemini",
42709
+ "non-gemini": "Non-Gemini"
42177
42710
  };
42178
- function evictOldestIfFull(map, key) {
42179
- if (map.has(key) || map.size < MAX_MAP_ENTRIES) return 0;
42180
- const oldest = map.keys().next().value;
42181
- if (oldest === void 0) return 0;
42182
- map.delete(oldest);
42183
- return 1;
42184
- }
42185
- function createRetryState() {
42186
- const rateLimitStateByAccountQuota = /* @__PURE__ */ new Map();
42187
- const accountFailureState = /* @__PURE__ */ new Map();
42188
- const rateLimitToastCooldowns = /* @__PURE__ */ new Map();
42189
- const emptyResponseAttempts = /* @__PURE__ */ new Map();
42190
- let softQuotaToastShownFlag = false;
42191
- let rateLimitToastShownFlag = false;
42192
- let disposed = false;
42193
- function isDisposed() {
42194
- return disposed;
42195
- }
42196
- function cleanupToastCooldowns() {
42197
- if (rateLimitToastCooldowns.size <= MAX_MAP_ENTRIES) return;
42198
- const now = Date.now();
42199
- for (const [key, time] of rateLimitToastCooldowns) {
42200
- if (now - time > RATE_LIMIT_TOAST_COOLDOWN_MS * 2) {
42201
- rateLimitToastCooldowns.delete(key);
42202
- }
42711
+ var SUPPORTED_QUOTA_KEYS = [
42712
+ "gemini",
42713
+ "non-gemini"
42714
+ ];
42715
+ function toCommandAccountRow(entry) {
42716
+ const rawCached = entry.cachedQuotaAccountId && entry.cachedQuotaAccountId !== quotaAccountIdentity3(entry.refreshToken) ? void 0 : entry.cachedQuota;
42717
+ const cached = normalizeLegacyCachedQuota2(
42718
+ rawCached
42719
+ );
42720
+ const quota = [];
42721
+ for (const key of SUPPORTED_QUOTA_KEYS) {
42722
+ const cachedEntry = cached?.[key];
42723
+ if (!cachedEntry) continue;
42724
+ const fraction = cachedEntry.remainingFraction;
42725
+ const remainingPercent = typeof fraction === "number" && Number.isFinite(fraction) ? Math.round(fraction * 100) : null;
42726
+ let resetAt;
42727
+ if (typeof cachedEntry.resetTime === "string" && cachedEntry.resetTime.length > 0) {
42728
+ const parsed = Date.parse(cachedEntry.resetTime);
42729
+ if (Number.isFinite(parsed)) resetAt = parsed;
42203
42730
  }
42731
+ const windows = cachedEntry.windows?.length ? cachedEntry.windows.map((w) => ({
42732
+ window: w.window,
42733
+ remainingPercent: Math.round(w.remainingFraction * 100),
42734
+ resetAt: typeof w.resetTime === "string" && w.resetTime.length > 0 ? (() => {
42735
+ const parsed = Date.parse(w.resetTime);
42736
+ return Number.isFinite(parsed) ? parsed : void 0;
42737
+ })() : void 0
42738
+ })) : void 0;
42739
+ quota.push({
42740
+ key,
42741
+ label: QUOTA_GROUP_LABELS[key],
42742
+ remainingPercent,
42743
+ resetAt,
42744
+ windows
42745
+ });
42204
42746
  }
42205
- function getRateLimitBackoff(accountIndex, quotaKey, serverRetryAfterMs, maxBackoffMs = 6e4) {
42206
- if (isDisposed()) return DISPOSED_BACKOFF;
42207
- const now = Date.now();
42208
- const stateKey = `${accountIndex}:${quotaKey}`;
42209
- const previous = rateLimitStateByAccountQuota.get(stateKey);
42210
- if (previous && now - previous.lastAt < RATE_LIMIT_DEDUP_WINDOW_MS) {
42211
- const baseDelay2 = serverRetryAfterMs ?? 1e3;
42212
- const backoffDelay2 = Math.min(
42213
- baseDelay2 * 2 ** (previous.consecutive429 - 1),
42214
- maxBackoffMs
42747
+ const label = `Account ${entry.index + 1}`;
42748
+ return {
42749
+ id: `acct-${entry.index}`,
42750
+ index: entry.index,
42751
+ label,
42752
+ enabled: entry.enabled,
42753
+ current: entry.active,
42754
+ coolingDownUntil: entry.coolingDownUntil,
42755
+ healthScore: entry.healthScore,
42756
+ cachedQuotaUpdatedAt: entry.cachedQuotaUpdatedAt,
42757
+ quota,
42758
+ tier: toCapturedTier(entry)
42759
+ };
42760
+ }
42761
+ function quotaAccountIdentity3(refreshToken) {
42762
+ return createHash19("sha256").update(refreshToken).digest("hex").slice(0, 16);
42763
+ }
42764
+ function projectCommandAccountRows(storage) {
42765
+ if (!storage) return [];
42766
+ const activeIndex = storage.activeIndexByFamily?.claude ?? storage.activeIndex;
42767
+ return storage.accounts.map(
42768
+ (entry, index) => toCommandAccountRow({
42769
+ index,
42770
+ refreshToken: entry.refreshToken,
42771
+ label: entry.label,
42772
+ enabled: entry.enabled !== false,
42773
+ active: index === activeIndex,
42774
+ cachedQuota: entry.cachedQuota,
42775
+ cachedQuotaUpdatedAt: entry.cachedQuotaUpdatedAt,
42776
+ cachedQuotaAccountId: entry.cachedQuotaAccountId
42777
+ })
42778
+ );
42779
+ }
42780
+
42781
+ // src/plugin/dependencies.ts
42782
+ import { homedir as homedir11 } from "node:os";
42783
+ import { join as join26 } from "node:path";
42784
+ function defaultFilesystemRoots() {
42785
+ const xdgConfig2 = process.env.XDG_CONFIG_HOME ?? join26(homedir11(), ".config");
42786
+ const xdgState2 = process.env.XDG_STATE_HOME ?? join26(homedir11(), ".local", "state");
42787
+ return {
42788
+ projectRoot: process.cwd(),
42789
+ userConfigRoot: join26(xdgConfig2, "opencode"),
42790
+ sidebarStateRoot: join26(xdgState2, "cortexkit", "antigravity-auth"),
42791
+ rpcRoot: join26(xdgState2, "cortexkit", "antigravity-auth", "rpc")
42792
+ };
42793
+ }
42794
+ function resolvePluginDependencies(overrides = {}) {
42795
+ const fetchImpl = overrides.fetchImpl ?? ((input2, init) => globalThis.fetch(input2, init));
42796
+ const agyTransport = overrides.agyTransport ?? fetchWithAgyCliTransport;
42797
+ const roots = {
42798
+ ...defaultFilesystemRoots(),
42799
+ ...overrides.filesystemRoots
42800
+ };
42801
+ const oauth = {
42802
+ authorize: overrides.oauth?.authorize ?? authorizeAntigravity,
42803
+ exchange: overrides.oauth?.exchange ?? exchangeAntigravity
42804
+ };
42805
+ const clock = {
42806
+ now: overrides.clock?.now ?? (() => Date.now()),
42807
+ random: overrides.clock?.random ?? Math.random,
42808
+ sleep: overrides.clock?.sleep ?? defaultSleep
42809
+ };
42810
+ return {
42811
+ fetchImpl,
42812
+ agyTransport,
42813
+ filesystemRoots: roots,
42814
+ oauth,
42815
+ clock
42816
+ };
42817
+ }
42818
+ async function defaultSleep(ms, signal) {
42819
+ if (ms <= 0) return;
42820
+ await new Promise((resolve12, reject) => {
42821
+ const timer = setTimeout(() => {
42822
+ signal?.removeEventListener("abort", onAbort);
42823
+ resolve12();
42824
+ }, ms);
42825
+ timer.unref?.();
42826
+ const onAbort = () => {
42827
+ clearTimeout(timer);
42828
+ reject(
42829
+ signal?.reason instanceof Error ? signal.reason : new Error("Aborted")
42215
42830
  );
42216
- return {
42217
- attempt: previous.consecutive429,
42218
- delayMs: Math.max(baseDelay2, backoffDelay2),
42219
- isDuplicate: true
42220
- };
42221
- }
42222
- const attempt = previous && now - previous.lastAt < RATE_LIMIT_STATE_RESET_MS ? previous.consecutive429 + 1 : 1;
42223
- evictOldestIfFull(rateLimitStateByAccountQuota, stateKey);
42224
- rateLimitStateByAccountQuota.set(stateKey, {
42225
- consecutive429: attempt,
42226
- lastAt: now,
42227
- quotaKey
42228
- });
42229
- const baseDelay = serverRetryAfterMs ?? 1e3;
42230
- const backoffDelay = Math.min(baseDelay * 2 ** (attempt - 1), maxBackoffMs);
42231
- return {
42232
- attempt,
42233
- delayMs: Math.max(baseDelay, backoffDelay),
42234
- isDuplicate: false
42235
42831
  };
42236
- }
42237
- function resetRateLimitState(accountIndex, quotaKey) {
42238
- if (isDisposed()) return;
42239
- const stateKey = `${accountIndex}:${quotaKey}`;
42240
- rateLimitStateByAccountQuota.delete(stateKey);
42241
- }
42242
- function resetAllRateLimitStateForAccount(accountIndex) {
42243
- if (isDisposed()) return;
42244
- for (const key of rateLimitStateByAccountQuota.keys()) {
42245
- if (key.startsWith(`${accountIndex}:`)) {
42246
- rateLimitStateByAccountQuota.delete(key);
42832
+ signal?.addEventListener("abort", onAbort, { once: true });
42833
+ });
42834
+ }
42835
+
42836
+ // src/plugin/event-handler.ts
42837
+ function createEventHandler({
42838
+ client,
42839
+ config,
42840
+ directory,
42841
+ lifecycle,
42842
+ sessionRegistry,
42843
+ sessionRecovery,
42844
+ updateChecker,
42845
+ logger: logger2
42846
+ }) {
42847
+ return async (input2) => {
42848
+ await updateChecker.event(input2);
42849
+ if (input2.event.type === "session.created") {
42850
+ const properties2 = input2.event.properties;
42851
+ const sessionId = properties2?.info?.id;
42852
+ const parentSessionId = properties2?.info?.parentID ?? null;
42853
+ if (sessionId) {
42854
+ sessionRegistry.register(sessionId, parentSessionId);
42855
+ }
42856
+ if (parentSessionId) {
42857
+ logger2.debug("child-session-detected", {
42858
+ sessionId,
42859
+ parentID: parentSessionId
42860
+ });
42861
+ } else {
42862
+ const previousSummary = lifecycle.getAccountManager()?.getSessionSummary();
42863
+ if (previousSummary && (previousSummary.totalClaude > 0 || previousSummary.totalGemini > 0)) {
42864
+ logger2.debug("prev-session-quota-summary", {
42865
+ durationMinutes: previousSummary.durationMinutes,
42866
+ totalClaude: previousSummary.totalClaude,
42867
+ totalGemini: previousSummary.totalGemini,
42868
+ requestsPerHour: previousSummary.requestsPerHour,
42869
+ accountsUsed: previousSummary.accountsUsed
42870
+ });
42871
+ }
42872
+ logger2.debug("root-session-detected", { sessionId });
42873
+ }
42874
+ }
42875
+ if (input2.event.type === "session.deleted") {
42876
+ const properties2 = input2.event.properties;
42877
+ const sessionId = properties2?.sessionID ?? properties2?.info?.id;
42878
+ if (sessionId) {
42879
+ sessionRegistry.delete(sessionId);
42880
+ lifecycle.getAccountManager()?.deleteSessionState(sessionId);
42881
+ const eventLogger = logger2;
42882
+ void removeSidebarActiveRouting(sessionId).catch((error2) => {
42883
+ eventLogger.debug("sidebar-route-remove-failed", {
42884
+ sessionId,
42885
+ error: String(error2)
42886
+ });
42887
+ });
42888
+ }
42889
+ }
42890
+ if (!sessionRecovery || input2.event.type !== "session.error") {
42891
+ return;
42892
+ }
42893
+ const properties = input2.event.properties;
42894
+ const sessionID = properties?.sessionID;
42895
+ const messageID = properties?.messageID;
42896
+ const error = properties?.error;
42897
+ if (!sessionRecovery.isRecoverableError(error)) {
42898
+ return;
42899
+ }
42900
+ const recovered = await sessionRecovery.handleSessionRecovery({
42901
+ id: messageID,
42902
+ role: "assistant",
42903
+ sessionID,
42904
+ error
42905
+ });
42906
+ if (!recovered || !sessionID || !config.auto_resume) {
42907
+ return;
42908
+ }
42909
+ await client.session.prompt({
42910
+ path: { id: sessionID },
42911
+ body: { parts: [{ type: "text", text: config.resume_text }] },
42912
+ query: { directory }
42913
+ }).catch(() => {
42914
+ });
42915
+ const successToast = getRecoverySuccessToast();
42916
+ const isChildSession = sessionRegistry.getParentSessionId(sessionID) !== null;
42917
+ logger2.debug("recovery-toast", {
42918
+ ...successToast,
42919
+ isChildSession,
42920
+ toastScope: config.toast_scope
42921
+ });
42922
+ if (config.toast_scope === "root_only" && isChildSession) {
42923
+ return;
42924
+ }
42925
+ await client.tui.showToast({
42926
+ body: {
42927
+ title: successToast.title,
42928
+ message: successToast.message,
42929
+ variant: "success"
42930
+ }
42931
+ }).catch(() => {
42932
+ });
42933
+ };
42934
+ }
42935
+
42936
+ // src/plugin/errors.ts
42937
+ var AntigravityKillswitchError = class extends Error {
42938
+ family;
42939
+ model;
42940
+ thresholdPercent;
42941
+ summaries;
42942
+ constructor(input2) {
42943
+ super(
42944
+ input2.message ?? `Antigravity killswitch: all ${input2.summaries.length} account(s) under ${input2.thresholdPercent}% quota for ${input2.family}. Refresh quota or raise the threshold via /antigravity-killswitch.`
42945
+ );
42946
+ this.name = "AntigravityKillswitchError";
42947
+ this.family = input2.family;
42948
+ this.model = input2.model;
42949
+ this.thresholdPercent = input2.thresholdPercent;
42950
+ this.summaries = input2.summaries;
42951
+ }
42952
+ };
42953
+
42954
+ // src/plugin/fetch/retry-state.ts
42955
+ var MAX_CONSECUTIVE_FAILURES = 5;
42956
+ var FAILURE_COOLDOWN_MS = 3e4;
42957
+ var FAILURE_STATE_RESET_MS = 12e4;
42958
+ var RATE_LIMIT_DEDUP_WINDOW_MS = 2e3;
42959
+ var RATE_LIMIT_STATE_RESET_MS = 12e4;
42960
+ var RATE_LIMIT_TOAST_COOLDOWN_MS = 5e3;
42961
+ var MAX_MAP_ENTRIES = 100;
42962
+ var DISPOSED_BACKOFF = {
42963
+ attempt: 1,
42964
+ delayMs: 1e3,
42965
+ isDuplicate: false
42966
+ };
42967
+ var DISPOSED_FAILURE = {
42968
+ failures: 0,
42969
+ shouldCooldown: false,
42970
+ cooldownMs: 0
42971
+ };
42972
+ function evictOldestIfFull(map, key) {
42973
+ if (map.has(key) || map.size < MAX_MAP_ENTRIES) return 0;
42974
+ const oldest = map.keys().next().value;
42975
+ if (oldest === void 0) return 0;
42976
+ map.delete(oldest);
42977
+ return 1;
42978
+ }
42979
+ function createRetryState() {
42980
+ const rateLimitStateByAccountQuota = /* @__PURE__ */ new Map();
42981
+ const accountFailureState = /* @__PURE__ */ new Map();
42982
+ const rateLimitToastCooldowns = /* @__PURE__ */ new Map();
42983
+ const emptyResponseAttempts = /* @__PURE__ */ new Map();
42984
+ let softQuotaToastShownFlag = false;
42985
+ let rateLimitToastShownFlag = false;
42986
+ let disposed = false;
42987
+ function isDisposed() {
42988
+ return disposed;
42989
+ }
42990
+ function cleanupToastCooldowns() {
42991
+ if (rateLimitToastCooldowns.size <= MAX_MAP_ENTRIES) return;
42992
+ const now = Date.now();
42993
+ for (const [key, time] of rateLimitToastCooldowns) {
42994
+ if (now - time > RATE_LIMIT_TOAST_COOLDOWN_MS * 2) {
42995
+ rateLimitToastCooldowns.delete(key);
42996
+ }
42997
+ }
42998
+ }
42999
+ function getRateLimitBackoff(accountIndex, quotaKey, serverRetryAfterMs, maxBackoffMs = 6e4) {
43000
+ if (isDisposed()) return DISPOSED_BACKOFF;
43001
+ const now = Date.now();
43002
+ const stateKey = `${accountIndex}:${quotaKey}`;
43003
+ const previous = rateLimitStateByAccountQuota.get(stateKey);
43004
+ if (previous && now - previous.lastAt < RATE_LIMIT_DEDUP_WINDOW_MS) {
43005
+ const baseDelay2 = serverRetryAfterMs ?? 1e3;
43006
+ const backoffDelay2 = Math.min(
43007
+ baseDelay2 * 2 ** (previous.consecutive429 - 1),
43008
+ maxBackoffMs
43009
+ );
43010
+ return {
43011
+ attempt: previous.consecutive429,
43012
+ delayMs: Math.max(baseDelay2, backoffDelay2),
43013
+ isDuplicate: true
43014
+ };
43015
+ }
43016
+ const attempt = previous && now - previous.lastAt < RATE_LIMIT_STATE_RESET_MS ? previous.consecutive429 + 1 : 1;
43017
+ evictOldestIfFull(rateLimitStateByAccountQuota, stateKey);
43018
+ rateLimitStateByAccountQuota.set(stateKey, {
43019
+ consecutive429: attempt,
43020
+ lastAt: now,
43021
+ quotaKey
43022
+ });
43023
+ const baseDelay = serverRetryAfterMs ?? 1e3;
43024
+ const backoffDelay = Math.min(baseDelay * 2 ** (attempt - 1), maxBackoffMs);
43025
+ return {
43026
+ attempt,
43027
+ delayMs: Math.max(baseDelay, backoffDelay),
43028
+ isDuplicate: false
43029
+ };
43030
+ }
43031
+ function resetRateLimitState(accountIndex, quotaKey) {
43032
+ if (isDisposed()) return;
43033
+ const stateKey = `${accountIndex}:${quotaKey}`;
43034
+ rateLimitStateByAccountQuota.delete(stateKey);
43035
+ }
43036
+ function resetAllRateLimitStateForAccount(accountIndex) {
43037
+ if (isDisposed()) return;
43038
+ for (const key of rateLimitStateByAccountQuota.keys()) {
43039
+ if (key.startsWith(`${accountIndex}:`)) {
43040
+ rateLimitStateByAccountQuota.delete(key);
42247
43041
  }
42248
43042
  }
42249
43043
  }
@@ -42850,7 +43644,8 @@ function routeTitleModel(url) {
42850
43644
  const model = extractModelFromUrl(url);
42851
43645
  if (model === null) return url;
42852
43646
  const registered = Object.hasOwn(getPublicModelDefinitions(), model) || Object.hasOwn(getResolverAliasMap(), model);
42853
- if (registered && !isImageGenerationModel(model)) return url;
43647
+ if (registered && !isImageGenerationModel(model) && !isRetiredAgyModel(model))
43648
+ return url;
42854
43649
  return url.replace(`/models/${model}`, `/models/${TITLE_FALLBACK_MODEL}`);
42855
43650
  }
42856
43651
  function agyMetadataIdentity(identity, kind) {
@@ -43052,6 +43847,19 @@ function createRequestExecutor(deps) {
43052
43847
  if (kind === "title") {
43053
43848
  input2 = routeTitleModel(input2);
43054
43849
  }
43850
+ const selectedModel = extractModelFromUrl(input2);
43851
+ if (selectedModel && isRetiredAgyModel(selectedModel)) {
43852
+ return new Response(
43853
+ JSON.stringify({
43854
+ error: {
43855
+ code: 412,
43856
+ status: "FAILED_PRECONDITION",
43857
+ message: RETIRED_AGY_MODEL_MESSAGE
43858
+ }
43859
+ }),
43860
+ { status: 412, headers: { "Content-Type": "application/json" } }
43861
+ );
43862
+ }
43055
43863
  const transport = options.transport ?? defaultTransport2;
43056
43864
  const requestSessionIdentity = options.session ?? extractOpenCodeSessionIdentity(init?.headers);
43057
43865
  const agyRequestScope = agySessionRegistry.beginRequest(
@@ -43591,9 +44399,7 @@ function createRequestExecutor(deps) {
43591
44399
  if (!warmupState.trackAttempt(prepared.sessionId)) return;
43592
44400
  const warmupBody = wire.buildThinkingWarmupBody(
43593
44401
  typeof prepared.init.body === "string" ? prepared.init.body : void 0,
43594
- Boolean(
43595
- prepared.effectiveModel?.toLowerCase().includes("claude") && prepared.effectiveModel?.toLowerCase().includes("thinking")
43596
- )
44402
+ isClaudeThinkingModel(prepared.effectiveModel ?? "")
43597
44403
  );
43598
44404
  if (!warmupBody) return;
43599
44405
  const warmupUrl = toWarmupStreamUrl(prepared.request);
@@ -44663,483 +45469,139 @@ function createRequestExecutor(deps) {
44663
45469
  response,
44664
45470
  cancellation
44665
45471
  );
44666
- inFlight.add(retained.settled);
44667
- void retained.settled.then(() => inFlight.delete(retained.settled));
44668
- return redactCredentialResponse(
44669
- preserveResponseMetadata2(retained.response, response),
44670
- [...selectedCredentials]
44671
- );
44672
- },
44673
- (error) => {
44674
- cancellation.release();
44675
- throw redactCredentialError(error, [...selectedCredentials]);
44676
- }
44677
- ).catch((error) => {
44678
- cancellation.release();
44679
- throw redactCredentialError(error, [...selectedCredentials]);
44680
- });
44681
- inFlight.add(pending);
44682
- void pending.then(
44683
- () => inFlight.delete(pending),
44684
- () => inFlight.delete(pending)
44685
- );
44686
- return pending;
44687
- },
44688
- retire: retire2,
44689
- dispose
44690
- };
44691
- }
44692
- function extractRateLimitBodyInfo(body) {
44693
- if (!body || typeof body !== "object") return { retryDelayMs: null };
44694
- const error = body.error;
44695
- const message = error && typeof error === "object" ? error.message : void 0;
44696
- const details = error && typeof error === "object" ? error.details : void 0;
44697
- let reason;
44698
- if (Array.isArray(details)) {
44699
- for (const detail of details) {
44700
- if (!detail || typeof detail !== "object") continue;
44701
- const type = detail["@type"];
44702
- if (typeof type === "string" && type.includes("google.rpc.ErrorInfo")) {
44703
- const detailReason = detail.reason;
44704
- if (typeof detailReason === "string") {
44705
- reason = detailReason;
44706
- break;
44707
- }
44708
- }
44709
- }
44710
- for (const detail of details) {
44711
- if (!detail || typeof detail !== "object") continue;
44712
- const type = detail["@type"];
44713
- if (typeof type === "string" && type.includes("google.rpc.RetryInfo")) {
44714
- const retryDelay = detail.retryDelay;
44715
- if (typeof retryDelay === "string") {
44716
- const retryDelayMs = parseDurationToMs(retryDelay);
44717
- if (retryDelayMs !== null) {
44718
- return { retryDelayMs, message, reason };
44719
- }
44720
- }
44721
- }
44722
- }
44723
- for (const detail of details) {
44724
- if (!detail || typeof detail !== "object") continue;
44725
- const metadata = detail.metadata;
44726
- if (metadata && typeof metadata === "object") {
44727
- const quotaResetDelay = metadata.quotaResetDelay;
44728
- const quotaResetTime = metadata.quotaResetTimeStamp;
44729
- if (typeof quotaResetDelay === "string") {
44730
- const quotaResetDelayMs = parseDurationToMs(quotaResetDelay);
44731
- if (quotaResetDelayMs !== null) {
44732
- return {
44733
- retryDelayMs: quotaResetDelayMs,
44734
- message,
44735
- quotaResetTime,
44736
- reason
44737
- };
44738
- }
44739
- }
44740
- }
44741
- }
44742
- }
44743
- if (message) {
44744
- const afterMatch = message.match(/reset after\s+([0-9hms.]+)/i);
44745
- const rawDuration = afterMatch?.[1];
44746
- if (rawDuration) {
44747
- const parsed = parseDurationToMs(rawDuration);
44748
- if (parsed !== null) {
44749
- return { retryDelayMs: parsed, message, reason };
44750
- }
44751
- }
44752
- }
44753
- return { retryDelayMs: null, message, reason };
44754
- }
44755
- function parseDurationToMs(duration) {
44756
- const simpleMatch = duration.match(/^(\d+(?:\.\d+)?)(ms|s|m|h)?$/i);
44757
- if (simpleMatch) {
44758
- const value = parseFloat(simpleMatch[1]);
44759
- const unit = (simpleMatch[2] || "s").toLowerCase();
44760
- switch (unit) {
44761
- case "h":
44762
- return value * 3600 * 1e3;
44763
- case "m":
44764
- return value * 60 * 1e3;
44765
- case "s":
44766
- return value * 1e3;
44767
- case "ms":
44768
- return value;
44769
- default:
44770
- return value * 1e3;
44771
- }
44772
- }
44773
- const compoundRegex = /(\d+(?:\.\d+)?)(h|m(?!s)|s|ms)/gi;
44774
- let totalMs = 0;
44775
- let matchFound = false;
44776
- let match = null;
44777
- while (true) {
44778
- match = compoundRegex.exec(duration);
44779
- if (match === null) break;
44780
- matchFound = true;
44781
- const value = parseFloat(match[1]);
44782
- const unit = match[2]?.toLowerCase();
44783
- switch (unit) {
44784
- case "h":
44785
- totalMs += value * 3600 * 1e3;
44786
- break;
44787
- case "m":
44788
- totalMs += value * 60 * 1e3;
44789
- break;
44790
- case "s":
44791
- totalMs += value * 1e3;
44792
- break;
44793
- case "ms":
44794
- totalMs += value;
44795
- break;
44796
- }
44797
- }
44798
- return matchFound ? totalMs : null;
44799
- }
44800
-
44801
- // src/plugin/shared/vault-request-credentials.ts
44802
- function vaultAccountRows(routes) {
44803
- return routes.map((route, index) => ({
44804
- index,
44805
- enabled: true,
44806
- lastUsed: 0,
44807
- rateLimitResetTimes: {},
44808
- touchedForQuota: {},
44809
- route,
44810
- ...route.email !== void 0 ? { email: route.email } : {}
44811
- }));
44812
- }
44813
- function vaultAccountRowKey(row) {
44814
- return JSON.stringify([
44815
- row.route.routeId,
44816
- row.route.credentialId,
44817
- row.route.accountIdentity
44818
- ]);
44819
- }
44820
- function refreshVaultAccountRow(prior, fresh) {
44821
- prior.route = fresh.route;
44822
- if (fresh.email === void 0) delete prior.email;
44823
- else prior.email = fresh.email;
44824
- }
44825
- var VaultSendGrant = class {
44826
- credentialId;
44827
- accountIdentity;
44828
- recordVersion;
44829
- projectId;
44830
- report401;
44831
- constructor(admission, report) {
44832
- Object.defineProperty(this, "accessToken", {
44833
- value: admission.accessToken,
44834
- enumerable: false
44835
- });
44836
- this.credentialId = admission.credentialId;
44837
- this.accountIdentity = admission.accountIdentity;
44838
- this.recordVersion = admission.recordVersion;
44839
- this.projectId = admission.projectId;
44840
- this.report401 = report;
44841
- }
44842
- };
44843
- function createVaultRequestCredentials(source, onAdmitted) {
44844
- return {
44845
- domain: "vault",
44846
- async admit({ account, signal }) {
44847
- const admission = await source.admit(account.route, signal);
44848
- if (onAdmitted)
44849
- onAdmitted.admitted(account, onAdmitted.source.attribution(admission));
44850
- return new VaultSendGrant(
44851
- admission,
44852
- (status) => source.reportServedStatus(admission, status)
44853
- );
44854
- }
44855
- };
44856
- }
44857
- function present4(value) {
44858
- return value === null ? void 0 : value;
44859
- }
44860
- function storedResets(resets) {
44861
- const stored = {};
44862
- for (const [key, at] of Object.entries(resets))
44863
- if (typeof at === "number") stored[key] = at;
44864
- return stored;
44865
- }
44866
- function cachedQuotaOf(quota) {
44867
- const groups = quota.cachedQuota;
44868
- if (groups == null) return void 0;
44869
- const out = {};
44870
- for (const name of ["gemini", "non-gemini"]) {
44871
- const group = groups[name];
44872
- if (group === void 0) continue;
44873
- out[name] = {
44874
- modelCount: group.modelCount,
44875
- ...group.remainingFraction != null ? { remainingFraction: group.remainingFraction } : {},
44876
- ...group.resetTime != null ? { resetTime: group.resetTime } : {},
44877
- ...group.windows != null ? {
44878
- windows: group.windows.map((window) => ({
44879
- window: window.window,
44880
- remainingFraction: window.remainingFraction,
44881
- resetTime: window.resetTime
44882
- }))
44883
- } : {}
44884
- };
44885
- }
44886
- return out;
44887
- }
44888
- function durableSelectionOf(row) {
44889
- return {
44890
- lastUsed: row.lastUsed,
44891
- ...row.lastSwitchReason !== void 0 ? { lastSwitchReason: row.lastSwitchReason } : {},
44892
- rateLimitResetTimes: storedResets(row.rateLimitResetTimes),
44893
- ...row.coolingDownUntil !== void 0 ? { coolingDownUntil: row.coolingDownUntil } : {},
44894
- ...row.cooldownReason !== void 0 ? { cooldownReason: row.cooldownReason } : {},
44895
- ...row.fingerprint !== void 0 ? { fingerprint: structuredClone(row.fingerprint) } : {},
44896
- ...row.fingerprintHistory !== void 0 ? { fingerprintHistory: structuredClone(row.fingerprintHistory) } : {},
44897
- ...row.verificationRequired !== void 0 ? { verificationRequired: row.verificationRequired } : {},
44898
- ...row.verificationRequiredAt !== void 0 ? { verificationRequiredAt: row.verificationRequiredAt } : {},
44899
- ...row.verificationRequiredReason !== void 0 ? { verificationRequiredReason: row.verificationRequiredReason } : {},
44900
- ...row.verificationUrl !== void 0 ? { verificationUrl: row.verificationUrl } : {},
44901
- ...row.accountIneligible !== void 0 ? { accountIneligible: row.accountIneligible } : {},
44902
- ...row.accountIneligibleAt !== void 0 ? { accountIneligibleAt: row.accountIneligibleAt } : {},
44903
- ...row.accountIneligibleReason !== void 0 ? { accountIneligibleReason: row.accountIneligibleReason } : {},
44904
- ...row.eligibilityStateUpdatedAt !== void 0 ? { eligibilityStateUpdatedAt: row.eligibilityStateUpdatedAt } : {},
44905
- ...row.dailyRequestCounts !== void 0 ? { dailyRequestCounts: { ...row.dailyRequestCounts } } : {}
44906
- };
44907
- }
44908
- function applyDurableSelection(row, metadata) {
44909
- row.lastUsed = metadata.lastUsed;
44910
- const reason = present4(metadata.lastSwitchReason);
44911
- if (reason !== void 0) row.lastSwitchReason = reason;
44912
- const resets = present4(metadata.rateLimitResetTimes);
44913
- if (resets !== void 0) {
44914
- const copy = {};
44915
- for (const [key, at] of Object.entries(resets))
44916
- if (typeof at === "number") copy[key] = at;
44917
- row.rateLimitResetTimes = copy;
44918
- }
44919
- const until = present4(metadata.coolingDownUntil);
44920
- const cooldownReason = present4(metadata.cooldownReason);
44921
- if (until !== void 0 && cooldownReason !== void 0) {
44922
- row.coolingDownUntil = until;
44923
- row.cooldownReason = cooldownReason;
44924
- }
44925
- const fingerprint = present4(metadata.fingerprint);
44926
- if (fingerprint !== void 0) row.fingerprint = structuredClone(fingerprint);
44927
- const history = present4(metadata.fingerprintHistory);
44928
- if (history !== void 0) row.fingerprintHistory = structuredClone(history);
44929
- const verification = present4(metadata.verificationRequired);
44930
- if (verification !== void 0) row.verificationRequired = verification;
44931
- const verificationAt = present4(metadata.verificationRequiredAt);
44932
- if (verificationAt !== void 0) row.verificationRequiredAt = verificationAt;
44933
- const verificationReason = present4(metadata.verificationRequiredReason);
44934
- if (verificationReason !== void 0)
44935
- row.verificationRequiredReason = verificationReason;
44936
- const verificationUrl = present4(metadata.verificationUrl);
44937
- if (verificationUrl !== void 0) row.verificationUrl = verificationUrl;
44938
- const ineligible = present4(metadata.accountIneligible);
44939
- if (ineligible !== void 0) row.accountIneligible = ineligible;
44940
- const ineligibleAt = present4(metadata.accountIneligibleAt);
44941
- if (ineligibleAt !== void 0) row.accountIneligibleAt = ineligibleAt;
44942
- const ineligibleReason = present4(metadata.accountIneligibleReason);
44943
- if (ineligibleReason !== void 0)
44944
- row.accountIneligibleReason = ineligibleReason;
44945
- const eligibilityAt = present4(metadata.eligibilityStateUpdatedAt);
44946
- if (eligibilityAt !== void 0) row.eligibilityStateUpdatedAt = eligibilityAt;
44947
- const counts = present4(metadata.dailyRequestCounts);
44948
- if (counts !== void 0) row.dailyRequestCounts = { ...counts };
44949
- }
44950
- function stateBelongsTo(state, row) {
44951
- return state.observed.routeId === row.route.routeId && state.observed.credentialId === row.route.credentialId;
44952
- }
44953
- function createVaultSelectionState(options) {
44954
- const now = options.now ?? (() => Date.now());
44955
- const attributions = /* @__PURE__ */ new WeakMap();
44956
- const changed = /* @__PURE__ */ new Set();
44957
- let writing = Promise.resolve();
44958
- const mark = (row) => {
44959
- changed.add(row);
44960
- };
44961
- const report = (error) => {
44962
- try {
44963
- options.onError?.(error);
44964
- } catch {
44965
- }
44966
- };
44967
- const writeRow = async (row) => {
44968
- const attribution = attributions.get(row);
44969
- if (attribution === void 0) return;
44970
- changed.delete(row);
44971
- const selection = durableSelectionOf(row);
44972
- try {
44973
- await options.source.commitState(attribution, (current) => ({
44974
- metadata: {
44975
- ...current?.metadata ?? { addedAt: now() },
44976
- ...selection
44977
- },
44978
- ...current?.quota !== void 0 ? { quota: current.quota } : {},
44979
- ...current?.extensions !== void 0 ? { extensions: current.extensions } : {}
44980
- }));
44981
- } catch (error) {
44982
- report(error);
44983
- }
44984
- };
44985
- const flush = () => {
44986
- writing = writing.then(async () => {
44987
- for (const row of [...changed]) await writeRow(row);
44988
- });
44989
- return writing;
44990
- };
44991
- return {
44992
- sink: {
44993
- rateLimit: mark,
44994
- cooldown: mark,
44995
- switched: mark,
44996
- lastUsed: mark,
44997
- usage: mark,
44998
- accessVerdict: mark,
44999
- fingerprint: mark,
45000
- requestSave: () => {
45001
- void flush();
45002
- }
45003
- },
45004
- admitted(row, attribution) {
45005
- attributions.set(row, attribution);
45006
- },
45007
- async hydrate(rows) {
45008
- const file = await options.readState();
45009
- for (const row of rows) {
45010
- const identity = row.route.accountIdentity;
45011
- if (!Object.hasOwn(file.accounts, identity)) continue;
45012
- const state = file.accounts[identity];
45013
- if (state === void 0 || !stateBelongsTo(state, row)) continue;
45014
- if (state.metadata !== void 0)
45015
- applyDurableSelection(row, state.metadata);
45016
- if (state.quota !== void 0) {
45017
- const cached = cachedQuotaOf(state.quota);
45018
- if (cached !== void 0) row.cachedQuota = cached;
45019
- const updatedAt = present4(state.quota.cachedQuotaUpdatedAt);
45020
- if (updatedAt !== void 0) row.cachedQuotaUpdatedAt = updatedAt;
45472
+ inFlight.add(retained.settled);
45473
+ void retained.settled.then(() => inFlight.delete(retained.settled));
45474
+ return redactCredentialResponse(
45475
+ preserveResponseMetadata2(retained.response, response),
45476
+ [...selectedCredentials]
45477
+ );
45478
+ },
45479
+ (error) => {
45480
+ cancellation.release();
45481
+ throw redactCredentialError(error, [...selectedCredentials]);
45021
45482
  }
45022
- }
45483
+ ).catch((error) => {
45484
+ cancellation.release();
45485
+ throw redactCredentialError(error, [...selectedCredentials]);
45486
+ });
45487
+ inFlight.add(pending);
45488
+ void pending.then(
45489
+ () => inFlight.delete(pending),
45490
+ () => inFlight.delete(pending)
45491
+ );
45492
+ return pending;
45023
45493
  },
45024
- flush,
45025
- recordQuota(attribution, quota) {
45026
- return options.source.commitState(attribution, (current) => ({
45027
- ...current?.metadata !== void 0 ? { metadata: current.metadata } : {},
45028
- quota,
45029
- ...current?.extensions !== void 0 ? { extensions: current.extensions } : {}
45030
- }));
45031
- }
45494
+ retire: retire2,
45495
+ dispose
45032
45496
  };
45033
45497
  }
45034
- function createVaultAccountPool(options) {
45035
- const { source, durable } = options;
45036
- const state = durable ? createVaultSelectionState({
45037
- source: durable.source,
45038
- readState: durable.readState,
45039
- ...options.now ? { now: options.now } : {},
45040
- ...durable.onError ? { onError: durable.onError } : {}
45041
- }) : void 0;
45042
- const selector = new AccountSelector({
45043
- ...options.now ? { now: options.now } : {},
45044
- ...state ? { sink: state.sink } : {}
45045
- });
45046
- const credentials = createVaultRequestCredentials(
45047
- source,
45048
- state && durable ? {
45049
- source: durable.source,
45050
- admitted: (row, attribution) => state.admitted(row, attribution)
45051
- } : void 0
45052
- );
45053
- const rowsFromSource = async () => {
45054
- const rows = vaultAccountRows(source.routes());
45055
- if (state) {
45056
- const kept = new Set(selector.rows.map(vaultAccountRowKey));
45057
- const added = rows.filter((row) => !kept.has(vaultAccountRowKey(row)));
45058
- if (added.length > 0) await state.hydrate(added);
45498
+ function extractRateLimitBodyInfo(body) {
45499
+ if (!body || typeof body !== "object") return { retryDelayMs: null };
45500
+ const error = body.error;
45501
+ const message = error && typeof error === "object" ? error.message : void 0;
45502
+ const details = error && typeof error === "object" ? error.details : void 0;
45503
+ let reason;
45504
+ if (Array.isArray(details)) {
45505
+ for (const detail of details) {
45506
+ if (!detail || typeof detail !== "object") continue;
45507
+ const type = detail["@type"];
45508
+ if (typeof type === "string" && type.includes("google.rpc.ErrorInfo")) {
45509
+ const detailReason = detail.reason;
45510
+ if (typeof detailReason === "string") {
45511
+ reason = detailReason;
45512
+ break;
45513
+ }
45514
+ }
45059
45515
  }
45060
- return rows;
45061
- };
45062
- const replace = async () => {
45063
- selector.replaceAccounts(await rowsFromSource(), {
45064
- keyOf: vaultAccountRowKey,
45065
- refresh: refreshVaultAccountRow
45066
- });
45067
- };
45068
- let firstRead = null;
45069
- const readOnce = () => {
45070
- firstRead ??= (async () => {
45071
- await source.refresh();
45072
- selector.resetAccounts(await rowsFromSource());
45073
- })().catch((error) => {
45074
- firstRead = null;
45075
- throw error;
45076
- });
45077
- return firstRead;
45078
- };
45079
- return {
45080
- selector,
45081
- credentials,
45082
- state,
45083
- async sync() {
45084
- const pending = firstRead;
45085
- await readOnce();
45086
- if (pending !== null) await replace();
45087
- },
45088
- async refresh() {
45089
- await readOnce();
45090
- await source.refresh();
45091
- await replace();
45092
- },
45093
- flush: async () => {
45094
- await state?.flush();
45516
+ for (const detail of details) {
45517
+ if (!detail || typeof detail !== "object") continue;
45518
+ const type = detail["@type"];
45519
+ if (typeof type === "string" && type.includes("google.rpc.RetryInfo")) {
45520
+ const retryDelay = detail.retryDelay;
45521
+ if (typeof retryDelay === "string") {
45522
+ const retryDelayMs = parseDurationToMs(retryDelay);
45523
+ if (retryDelayMs !== null) {
45524
+ return { retryDelayMs, message, reason };
45525
+ }
45526
+ }
45527
+ }
45095
45528
  }
45096
- };
45097
- }
45098
- function vaultQuotaState(quota, at) {
45099
- const cachedQuota = {};
45100
- for (const [name, group] of Object.entries(quota.groups)) {
45101
- if (group === void 0) continue;
45102
- cachedQuota[name] = {
45103
- modelCount: group.modelCount,
45104
- ...group.remainingFraction !== void 0 ? { remainingFraction: group.remainingFraction } : {},
45105
- ...group.resetTime !== void 0 ? { resetTime: group.resetTime } : {},
45106
- ...group.windows !== void 0 ? { windows: group.windows.map((window) => ({ ...window })) } : {}
45107
- };
45108
- }
45109
- return { schemaVersion: 1, cachedQuota, cachedQuotaUpdatedAt: at };
45110
- }
45111
- async function checkVaultQuota(input2) {
45112
- const state = input2.pool.state;
45113
- const rows = [...input2.pool.selector.rows];
45114
- const now = input2.now ?? (() => Date.now());
45115
- let checked = 0;
45116
- for (const row of rows) {
45117
- if (input2.signal.aborted || state === void 0) break;
45118
- try {
45119
- const answer = await input2.fetchReading(row.route, input2.signal);
45120
- const attribution = answer.quotaAttribution;
45121
- if (attribution === void 0 || answer.quota.error !== void 0)
45122
- continue;
45123
- const reading = vaultQuotaState(answer.quota, now());
45124
- const result = await state.recordQuota(attribution, reading);
45125
- if (result.status !== "written") continue;
45126
- checked += 1;
45127
- const live = input2.pool.selector.rows.find(
45128
- (candidate) => candidate.route.routeId === attribution.routeId && candidate.route.credentialId === attribution.credentialId && candidate.route.accountIdentity === attribution.accountIdentity
45129
- );
45130
- if (live !== void 0) {
45131
- const cached = cachedQuotaOf(reading);
45132
- if (cached !== void 0) live.cachedQuota = cached;
45133
- live.cachedQuotaUpdatedAt = reading.cachedQuotaUpdatedAt ?? void 0;
45529
+ for (const detail of details) {
45530
+ if (!detail || typeof detail !== "object") continue;
45531
+ const metadata = detail.metadata;
45532
+ if (metadata && typeof metadata === "object") {
45533
+ const quotaResetDelay = metadata.quotaResetDelay;
45534
+ const quotaResetTime = metadata.quotaResetTimeStamp;
45535
+ if (typeof quotaResetDelay === "string") {
45536
+ const quotaResetDelayMs = parseDurationToMs(quotaResetDelay);
45537
+ if (quotaResetDelayMs !== null) {
45538
+ return {
45539
+ retryDelayMs: quotaResetDelayMs,
45540
+ message,
45541
+ quotaResetTime,
45542
+ reason
45543
+ };
45544
+ }
45545
+ }
45134
45546
  }
45135
- } catch (error) {
45136
- try {
45137
- input2.onError?.(error);
45138
- } catch {
45547
+ }
45548
+ }
45549
+ if (message) {
45550
+ const afterMatch = message.match(/reset after\s+([0-9hms.]+)/i);
45551
+ const rawDuration = afterMatch?.[1];
45552
+ if (rawDuration) {
45553
+ const parsed = parseDurationToMs(rawDuration);
45554
+ if (parsed !== null) {
45555
+ return { retryDelayMs: parsed, message, reason };
45139
45556
  }
45140
45557
  }
45141
45558
  }
45142
- return { checked, notChecked: rows.length - checked };
45559
+ return { retryDelayMs: null, message, reason };
45560
+ }
45561
+ function parseDurationToMs(duration) {
45562
+ const simpleMatch = duration.match(/^(\d+(?:\.\d+)?)(ms|s|m|h)?$/i);
45563
+ if (simpleMatch) {
45564
+ const value = parseFloat(simpleMatch[1]);
45565
+ const unit = (simpleMatch[2] || "s").toLowerCase();
45566
+ switch (unit) {
45567
+ case "h":
45568
+ return value * 3600 * 1e3;
45569
+ case "m":
45570
+ return value * 60 * 1e3;
45571
+ case "s":
45572
+ return value * 1e3;
45573
+ case "ms":
45574
+ return value;
45575
+ default:
45576
+ return value * 1e3;
45577
+ }
45578
+ }
45579
+ const compoundRegex = /(\d+(?:\.\d+)?)(h|m(?!s)|s|ms)/gi;
45580
+ let totalMs = 0;
45581
+ let matchFound = false;
45582
+ let match = null;
45583
+ while (true) {
45584
+ match = compoundRegex.exec(duration);
45585
+ if (match === null) break;
45586
+ matchFound = true;
45587
+ const value = parseFloat(match[1]);
45588
+ const unit = match[2]?.toLowerCase();
45589
+ switch (unit) {
45590
+ case "h":
45591
+ totalMs += value * 3600 * 1e3;
45592
+ break;
45593
+ case "m":
45594
+ totalMs += value * 60 * 1e3;
45595
+ break;
45596
+ case "s":
45597
+ totalMs += value * 1e3;
45598
+ break;
45599
+ case "ms":
45600
+ totalMs += value;
45601
+ break;
45602
+ }
45603
+ }
45604
+ return matchFound ? totalMs : null;
45143
45605
  }
45144
45606
 
45145
45607
  // src/plugin/fetch-interceptor.ts
@@ -46242,6 +46704,7 @@ var createAntigravityPlugin = (providerId, options = {}) => async (input2) => {
46242
46704
  await drainSidebarWrites();
46243
46705
  }
46244
46706
  });
46707
+ let vaultQuotaPoller;
46245
46708
  const vaultCustody = createOpenCodeVaultCustody({
46246
46709
  accountFile: resolve11(getStoragePath()),
46247
46710
  readHostSlot: async () => {
@@ -46252,7 +46715,10 @@ var createAntigravityPlugin = (providerId, options = {}) => async (input2) => {
46252
46715
  // The request executor reports failed bearer authorization to Claustrum,
46253
46716
  // which decides whether its served credential needs replacement.
46254
46717
  reporterSource: "direct",
46255
- onAuthorityChanged: () => scheduleSidebarPublication(),
46718
+ onAuthorityChanged: (authority) => {
46719
+ if (authority !== "vault") vaultQuotaPoller?.abortTick();
46720
+ scheduleSidebarPublication();
46721
+ },
46256
46722
  onRosterChanged: () => scheduleSidebarPublication()
46257
46723
  });
46258
46724
  let vaultPool;
@@ -46299,6 +46765,7 @@ var createAntigravityPlugin = (providerId, options = {}) => async (input2) => {
46299
46765
  return manager.getAccounts().map((entry) => ({
46300
46766
  index: entry.index,
46301
46767
  label: entry.label,
46768
+ email: entry.email,
46302
46769
  enabled: entry.enabled,
46303
46770
  current: isAccountCurrent(entry.index, activeByFamily),
46304
46771
  coolingDownUntil: entry.coolingDownUntil,
@@ -46326,6 +46793,7 @@ var createAntigravityPlugin = (providerId, options = {}) => async (input2) => {
46326
46793
  return buildSidebarMachineStateFromAccounts(
46327
46794
  manager?.getAccounts().map((entry) => ({
46328
46795
  index: entry.index,
46796
+ email: entry.email,
46329
46797
  enabled: entry.enabled,
46330
46798
  current: active2 ? isAccountCurrent(entry.index, active2) : false,
46331
46799
  coolingDownUntil: entry.coolingDownUntil,
@@ -46343,23 +46811,13 @@ var createAntigravityPlugin = (providerId, options = {}) => async (input2) => {
46343
46811
  vault: async () => {
46344
46812
  const { pool } = await currentVaultPool();
46345
46813
  await pool.sync();
46346
- const projection = buildSidebarMachineStateFromAccounts(
46347
- pool.selector.rows.map((entry) => ({
46348
- index: entry.index,
46349
- enabled: entry.enabled,
46350
- current: false,
46351
- coolingDownUntil: entry.coolingDownUntil,
46352
- healthScore: pool.selector.healthTracker.getScore(entry.index),
46353
- cachedQuota: entry.cachedQuota,
46354
- cachedQuotaUpdatedAt: entry.cachedQuotaUpdatedAt
46355
- }))
46814
+ const projection = buildVaultSidebarProjection(
46815
+ pool,
46816
+ await vaultCustody.readState(),
46817
+ dependencies.clock.now()
46356
46818
  );
46357
46819
  return {
46358
46820
  ...projection,
46359
- accounts: projection.accounts.map((account) => ({
46360
- ...account,
46361
- id: `vault-${account.id}`
46362
- })),
46363
46821
  ...projection.accounts.length === 0 ? { lastError: VAULT_ACCOUNT_REMEDY } : {}
46364
46822
  };
46365
46823
  },
@@ -46438,6 +46896,21 @@ var createAntigravityPlugin = (providerId, options = {}) => async (input2) => {
46438
46896
  options._onPollerCreated?.(poller);
46439
46897
  poller.start();
46440
46898
  lifecycle.register({ dispose: () => poller.dispose() }, "producer");
46899
+ vaultQuotaPoller = new BackgroundVaultQuotaRefresh({
46900
+ intervalMs: config.background_quota_refresh_interval_minutes * 6e4,
46901
+ sidebarStateFile: getSidebarStateFile(),
46902
+ readAuthority,
46903
+ currentVaultPool,
46904
+ readProviderState: () => vaultCustody.readState(),
46905
+ publishSidebar: () => sidebarPublisher.publish(),
46906
+ transport: dependencies.fetchImpl,
46907
+ logger,
46908
+ now: dependencies.clock.now,
46909
+ random: dependencies.clock.random
46910
+ });
46911
+ options._onVaultPollerCreated?.(vaultQuotaPoller);
46912
+ vaultQuotaPoller.start();
46913
+ lifecycle.register(vaultQuotaPoller, "producer");
46441
46914
  }
46442
46915
  const operatorSettings = createOperatorSettingsController({
46443
46916
  projectConfigPath: join29(directory, ".opencode", "antigravity.json"),
@@ -46561,17 +47034,21 @@ var createAntigravityPlugin = (providerId, options = {}) => async (input2) => {
46561
47034
  vaultSelectors.set(key, selector);
46562
47035
  return selector;
46563
47036
  },
46564
- (signal) => checkVaultQuota({
46565
- pool,
46566
- signal,
46567
- fetchReading: (ref, check) => fetchVaultAccountQuota({
46568
- source,
46569
- ref,
46570
- signal: check,
46571
- logger,
46572
- transport: dependencies.fetchImpl
46573
- })
46574
- })
47037
+ (signal) => checkAndPublishVaultQuota(
47038
+ {
47039
+ pool,
47040
+ signal,
47041
+ now: dependencies.clock.now,
47042
+ fetchReading: (ref, check) => fetchVaultAccountQuota({
47043
+ source,
47044
+ ref,
47045
+ signal: check,
47046
+ logger,
47047
+ transport: dependencies.fetchImpl
47048
+ })
47049
+ },
47050
+ () => sidebarPublisher.publish()
47051
+ )
46575
47052
  )
46576
47053
  })
46577
47054
  };
@@ -46819,10 +47296,8 @@ var createAntigravityPlugin = (providerId, options = {}) => async (input2) => {
46819
47296
  apply: async (request) => {
46820
47297
  const current = await currentMenu();
46821
47298
  if (current.kind === "unavailable") throw new Error(current.message);
46822
- const result = await current.menu.apply(
46823
- request,
46824
- menuInvocation(pushNotification, request.sessionId)
46825
- );
47299
+ const invocation = menuInvocation(pushNotification, request.sessionId);
47300
+ const result = await current.menu.apply(request, invocation);
46826
47301
  try {
46827
47302
  if (await readAuthority() === "local")
46828
47303
  await lifecycle.getAccountManager()?.refreshFromRepository();
@@ -46839,6 +47314,11 @@ var createAntigravityPlugin = (providerId, options = {}) => async (input2) => {
46839
47314
  request.sessionId
46840
47315
  );
46841
47316
  }
47317
+ const refreshed = await currentMenu();
47318
+ if (refreshed.kind === "menu" && refreshed.menu !== current.menu) {
47319
+ const payload = await refreshed.menu.open(invocation);
47320
+ return { ...result, menu: payload.menu };
47321
+ }
46842
47322
  return result;
46843
47323
  },
46844
47324
  drain: drainNotifications