@expiren/opencode-antigravity-auth 1.6.20 → 1.6.22

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 (33) hide show
  1. package/dist/index.js +105 -22
  2. package/dist/index.js.map +2 -2
  3. package/dist/src/constants.d.ts +4 -3
  4. package/dist/src/constants.d.ts.map +1 -1
  5. package/dist/src/constants.js +2 -3
  6. package/dist/src/constants.js.map +1 -1
  7. package/dist/src/plugin/config/schema.d.ts +3 -0
  8. package/dist/src/plugin/config/schema.d.ts.map +1 -1
  9. package/dist/src/plugin/config/schema.js +44 -11
  10. package/dist/src/plugin/config/schema.js.map +1 -1
  11. package/dist/src/plugin/request.d.ts.map +1 -1
  12. package/dist/src/plugin/request.js +4 -4
  13. package/dist/src/plugin/request.js.map +1 -1
  14. package/dist/src/plugin/transform/claude.d.ts +11 -0
  15. package/dist/src/plugin/transform/claude.d.ts.map +1 -1
  16. package/dist/src/plugin/transform/claude.js +17 -1
  17. package/dist/src/plugin/transform/claude.js.map +1 -1
  18. package/dist/src/plugin/transform/index.d.ts +1 -1
  19. package/dist/src/plugin/transform/index.d.ts.map +1 -1
  20. package/dist/src/plugin/transform/index.js +1 -1
  21. package/dist/src/plugin/transform/index.js.map +1 -1
  22. package/dist/src/plugin/transform/model-resolver.js +4 -3
  23. package/dist/src/plugin/transform/model-resolver.js.map +1 -1
  24. package/dist/src/plugin/ui/auth-menu.d.ts.map +1 -1
  25. package/dist/src/plugin/ui/auth-menu.js +13 -1
  26. package/dist/src/plugin/ui/auth-menu.js.map +1 -1
  27. package/dist/src/plugin/ui/quota-status.d.ts.map +1 -1
  28. package/dist/src/plugin/ui/quota-status.js +10 -2
  29. package/dist/src/plugin/ui/quota-status.js.map +1 -1
  30. package/dist/src/plugin.d.ts.map +1 -1
  31. package/dist/src/plugin.js +24 -5
  32. package/dist/src/plugin.js.map +1 -1
  33. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -27,17 +27,14 @@ var ANTIGRAVITY_SCOPES = [
27
27
  ];
28
28
  var ANTIGRAVITY_REDIRECT_URI = "http://localhost:51121/oauth-callback";
29
29
  var ANTIGRAVITY_ENDPOINT_DAILY = "https://daily-cloudcode-pa.sandbox.googleapis.com";
30
- var ANTIGRAVITY_ENDPOINT_AUTOPUSH = "https://autopush-cloudcode-pa.sandbox.googleapis.com";
31
30
  var ANTIGRAVITY_ENDPOINT_PROD = "https://cloudcode-pa.googleapis.com";
32
31
  var ANTIGRAVITY_ENDPOINT_FALLBACKS = [
33
32
  ANTIGRAVITY_ENDPOINT_DAILY,
34
- ANTIGRAVITY_ENDPOINT_AUTOPUSH,
35
33
  ANTIGRAVITY_ENDPOINT_PROD
36
34
  ];
37
35
  var ANTIGRAVITY_LOAD_ENDPOINTS = [
38
36
  ANTIGRAVITY_ENDPOINT_PROD,
39
- ANTIGRAVITY_ENDPOINT_DAILY,
40
- ANTIGRAVITY_ENDPOINT_AUTOPUSH
37
+ ANTIGRAVITY_ENDPOINT_DAILY
41
38
  ];
42
39
  var ANTIGRAVITY_ENDPOINT = ANTIGRAVITY_ENDPOINT_DAILY;
43
40
  var GEMINI_CLI_ENDPOINT = ANTIGRAVITY_ENDPOINT_PROD;
@@ -1641,7 +1638,7 @@ function formatQuotaStatusBadge(status) {
1641
1638
  return `${ANSI.yellow}[WAIT${suffix}]${ANSI.reset}`;
1642
1639
  }
1643
1640
  case "EXHAUSTED": {
1644
- const suffix = status.waitMs ? ` resets in ${formatWaitDuration(status.waitMs)}` : "";
1641
+ const suffix = status.waitMs ? ` resets in ${formatWaitDuration(status.waitMs)}` : " resets in ?h";
1645
1642
  return `${ANSI.red}[EXHAUSTED${suffix}]${ANSI.reset}`;
1646
1643
  }
1647
1644
  case "COOLDOWN": {
@@ -1667,7 +1664,7 @@ function formatQuotaStatusPlain(status) {
1667
1664
  return `WAIT${suffix}`;
1668
1665
  }
1669
1666
  case "EXHAUSTED": {
1670
- const suffix = status.waitMs ? ` resets in ${formatWaitDuration(status.waitMs)}` : "";
1667
+ const suffix = status.waitMs ? ` resets in ${formatWaitDuration(status.waitMs)}` : " resets in ?h";
1671
1668
  return `EXHAUSTED${suffix}`;
1672
1669
  }
1673
1670
  case "COOLDOWN": {
@@ -1697,9 +1694,15 @@ function formatCachedQuotaWithStatus(cachedQuota) {
1697
1694
  }
1698
1695
  const pct = Math.round(Math.max(0, Math.min(1, value)) * 100);
1699
1696
  const status = classifyGroupStatus(cachedQuota[key]);
1697
+ if (status.label === "READY" && pct >= 100) {
1698
+ return [];
1699
+ }
1700
1700
  if (status.label === "READY") {
1701
1701
  return [`${label} ${pct}%`];
1702
1702
  }
1703
+ if (status.label === "EXHAUSTED") {
1704
+ return [`${label} ${formatQuotaStatusPlain(status)}`];
1705
+ }
1703
1706
  return [`${label} ${formatQuotaStatusPlain(status)} ${pct}%`];
1704
1707
  });
1705
1708
  return entries.length > 0 ? entries.join(", ") : void 0;
@@ -1750,7 +1753,15 @@ async function showAuthMenu(accounts) {
1750
1753
  { label: "Configure models in opencode.json", value: { type: "configure-models" }, color: "cyan" },
1751
1754
  { label: "", value: { type: "cancel" }, separator: true },
1752
1755
  { label: "Accounts", value: { type: "cancel" }, kind: "heading" },
1753
- ...accounts.map((account) => {
1756
+ ...accounts.slice().sort((a, b) => {
1757
+ const statusOrder = (acc) => {
1758
+ if (acc.isCurrentAccount) return 0;
1759
+ if (acc.status === "active") return 1;
1760
+ if (acc.status === "rate-limited") return 2;
1761
+ return 3;
1762
+ };
1763
+ return statusOrder(a) - statusOrder(b);
1764
+ }).map((account) => {
1754
1765
  const statusBadge = getStatusBadge(account.status, account);
1755
1766
  const currentBadge = account.isCurrentAccount ? ` ${ANSI.cyan}[current]${ANSI.reset}` : "";
1756
1767
  const disabledBadge = account.enabled === false ? ` ${ANSI.red}[disabled]${ANSI.reset}` : "";
@@ -3023,9 +3034,21 @@ var AntigravityConfigSchema = z2.object({
3023
3034
  * @default false
3024
3035
  */
3025
3036
  keep_thinking: z2.boolean().default(false),
3037
+ /**
3038
+ * Enable thinking warmup requests for Claude thinking models.
3039
+ * When enabled, sends a separate API call at session start to warm up
3040
+ * thinking signature validation. Costs 1 full API call per session.
3041
+ *
3042
+ * Disable to save quota — most users don't need this unless using
3043
+ * keep_thinking with signature caching.
3044
+ *
3045
+ * Env override: OPENCODE_ANTIGRAVITY_THINKING_WARMUP=1
3046
+ * @default false
3047
+ */
3048
+ thinking_warmup: z2.boolean().default(false),
3026
3049
  // =========================================================================
3027
3050
  // Session Recovery
3028
- // =========================================================================
3051
+ // =========================================================================
3029
3052
  /**
3030
3053
  * Enable automatic session recovery from tool_result_missing errors.
3031
3054
  * When enabled, shows a toast notification when recoverable errors occur.
@@ -3065,9 +3088,9 @@ var AntigravityConfigSchema = z2.object({
3065
3088
  * Maximum retry attempts when Antigravity returns an empty response.
3066
3089
  * Empty responses occur when no candidates/choices are returned.
3067
3090
  *
3068
- * @default 4
3091
+ * @default 2
3069
3092
  */
3070
- empty_response_max_attempts: z2.number().min(1).max(10).default(4),
3093
+ empty_response_max_attempts: z2.number().min(1).max(10).default(2),
3071
3094
  /**
3072
3095
  * Delay in milliseconds between empty response retries.
3073
3096
  *
@@ -3188,8 +3211,28 @@ var AntigravityConfigSchema = z2.object({
3188
3211
  */
3189
3212
  switch_on_first_rate_limit: z2.boolean().default(true),
3190
3213
  /**
3191
- * Scheduling mode for rate limit behavior.
3214
+ * Maximum number of account switches per request before giving up.
3215
+ * Each switch re-sends the full request payload, consuming quota on the new account.
3216
+ * Lower values reduce quota waste from cascading rate limits across accounts.
3192
3217
  *
3218
+ * Env override: OPENCODE_ANTIGRAVITY_MAX_ACCOUNT_SWITCHES
3219
+ * @default 2
3220
+ */
3221
+ max_account_switches: z2.number().min(0).max(50).default(2),
3222
+ /**
3223
+ * Allow falling back between quota pools (antigravity ↔ gemini-cli) when rate-limited.
3224
+ * When enabled, if one quota pool is exhausted the plugin re-sends the SAME request
3225
+ * using the alternate header style, consuming tokens from BOTH pools.
3226
+ * Disable to prevent double-spending quota across pools — the plugin will only
3227
+ * rotate accounts instead.
3228
+ * Only applies to Gemini models (Claude always uses antigravity).
3229
+ *
3230
+ * Env override: OPENCODE_ANTIGRAVITY_QUOTA_STYLE_FALLBACK
3231
+ * @default false
3232
+ */
3233
+ quota_style_fallback: z2.boolean().default(false),
3234
+ /**
3235
+ * Scheduling mode for rate limit behavior. *
3193
3236
  * - `cache_first`: Wait for same account to recover (preserves prompt cache). Default.
3194
3237
  * - `balance`: Switch account immediately on rate limit. Maximum availability.
3195
3238
  * - `performance_first`: Round-robin distribution for maximum throughput.
@@ -3253,7 +3296,7 @@ var AntigravityConfigSchema = z2.object({
3253
3296
  *
3254
3297
  * @default 15
3255
3298
  */
3256
- quota_refresh_interval_minutes: z2.number().min(0).max(60).default(15),
3299
+ quota_refresh_interval_minutes: z2.number().min(0).max(120).default(30),
3257
3300
  /**
3258
3301
  * How long quota cache is considered fresh for threshold checks (in minutes).
3259
3302
  * After this time, cache is stale and account is allowed (fail-open).
@@ -3301,10 +3344,11 @@ var DEFAULT_CONFIG = {
3301
3344
  debug: false,
3302
3345
  debug_tui: false,
3303
3346
  keep_thinking: false,
3347
+ thinking_warmup: false,
3304
3348
  session_recovery: true,
3305
3349
  auto_resume: true,
3306
3350
  resume_text: "continue",
3307
- empty_response_max_attempts: 4,
3351
+ empty_response_max_attempts: 2,
3308
3352
  empty_response_retry_delay_ms: 2e3,
3309
3353
  tool_id_recovery: true,
3310
3354
  claude_tool_hardening: true,
@@ -3318,6 +3362,8 @@ var DEFAULT_CONFIG = {
3318
3362
  account_selection_strategy: "hybrid",
3319
3363
  pid_offset_enabled: false,
3320
3364
  switch_on_first_rate_limit: true,
3365
+ max_account_switches: 2,
3366
+ quota_style_fallback: false,
3321
3367
  scheduling_mode: "cache_first",
3322
3368
  max_cache_first_wait_seconds: 60,
3323
3369
  failure_ttl_seconds: 3600,
@@ -3325,7 +3371,7 @@ var DEFAULT_CONFIG = {
3325
3371
  max_backoff_seconds: 60,
3326
3372
  request_jitter_max_ms: 0,
3327
3373
  soft_quota_threshold_percent: 90,
3328
- quota_refresh_interval_minutes: 15,
3374
+ quota_refresh_interval_minutes: 30,
3329
3375
  soft_quota_cache_ttl_minutes: "auto",
3330
3376
  auto_update: true,
3331
3377
  signature_cache: {
@@ -5606,6 +5652,12 @@ function needsThinkingRecovery(state) {
5606
5652
 
5607
5653
  // src/plugin/transform/claude.ts
5608
5654
  var CLAUDE_THINKING_MAX_OUTPUT_TOKENS = 64e3;
5655
+ function computeClaudeMaxOutputTokens(thinkingBudget) {
5656
+ if (typeof thinkingBudget !== "number" || thinkingBudget <= 0) {
5657
+ return CLAUDE_THINKING_MAX_OUTPUT_TOKENS;
5658
+ }
5659
+ return Math.min(Math.max(thinkingBudget * 2, 32e3), CLAUDE_THINKING_MAX_OUTPUT_TOKENS);
5660
+ }
5609
5661
  function isClaudeModel(model) {
5610
5662
  return model.toLowerCase().includes("claude");
5611
5663
  }
@@ -6138,7 +6190,7 @@ function resolveModelWithTier(requestedModel, options = {}) {
6138
6190
  if (isClaudeThinking) {
6139
6191
  return {
6140
6192
  actualModel: resolvedModel,
6141
- thinkingBudget: THINKING_TIER_BUDGETS.claude.high,
6193
+ thinkingBudget: THINKING_TIER_BUDGETS.claude.medium,
6142
6194
  isThinkingModel: true,
6143
6195
  quotaPreference,
6144
6196
  explicitQuota
@@ -7510,7 +7562,7 @@ function prepareAntigravityRequest(input2, init, accessToken, projectId, endpoin
7510
7562
  if (isClaudeThinking && typeof thinkingBudget === "number" && thinkingBudget > 0) {
7511
7563
  const currentMax = rawGenerationConfig.maxOutputTokens ?? rawGenerationConfig.max_output_tokens;
7512
7564
  if (!currentMax || currentMax <= thinkingBudget) {
7513
- rawGenerationConfig.maxOutputTokens = CLAUDE_THINKING_MAX_OUTPUT_TOKENS;
7565
+ rawGenerationConfig.maxOutputTokens = computeClaudeMaxOutputTokens(thinkingBudget);
7514
7566
  if (rawGenerationConfig.max_output_tokens !== void 0) {
7515
7567
  delete rawGenerationConfig.max_output_tokens;
7516
7568
  }
@@ -7520,7 +7572,7 @@ function prepareAntigravityRequest(input2, init, accessToken, projectId, endpoin
7520
7572
  } else {
7521
7573
  const generationConfig = { thinkingConfig };
7522
7574
  if (isClaudeThinking && typeof thinkingBudget === "number" && thinkingBudget > 0) {
7523
- generationConfig.maxOutputTokens = CLAUDE_THINKING_MAX_OUTPUT_TOKENS;
7575
+ generationConfig.maxOutputTokens = computeClaudeMaxOutputTokens(thinkingBudget);
7524
7576
  }
7525
7577
  requestPayload.generationConfig = generationConfig;
7526
7578
  }
@@ -7830,7 +7882,7 @@ function buildThinkingWarmupBody(bodyText, isClaudeThinking) {
7830
7882
  include_thoughts: true,
7831
7883
  thinking_budget: DEFAULT_THINKING_BUDGET
7832
7884
  };
7833
- generationConfig.maxOutputTokens = CLAUDE_THINKING_MAX_OUTPUT_TOKENS;
7885
+ generationConfig.maxOutputTokens = computeClaudeMaxOutputTokens(DEFAULT_THINKING_BUDGET);
7834
7886
  req.generationConfig = generationConfig;
7835
7887
  };
7836
7888
  if (parsed.request && typeof parsed.request === "object") {
@@ -11917,6 +11969,8 @@ var createAntigravityPlugin = (providerId) => async ({ client, directory }) => {
11917
11969
  if (family !== "gemini") return false;
11918
11970
  return accountManager.hasOtherAccountWithAntigravityAvailable(currentAccount.index, family, model);
11919
11971
  };
11972
+ let accountSwitchCount = 0;
11973
+ const maxAccountSwitches = config.max_account_switches ?? 2;
11920
11974
  while (true) {
11921
11975
  checkAborted();
11922
11976
  const accountCount = accountManager.getAccountCount();
@@ -12137,6 +12191,9 @@ var createAntigravityPlugin = (providerId) => async ({ client, directory }) => {
12137
12191
  }
12138
12192
  }
12139
12193
  const runThinkingWarmup = async (prepared, projectId) => {
12194
+ if (!config.thinking_warmup) {
12195
+ return;
12196
+ }
12140
12197
  if (!prepared.needsSignedThinkingWarmup || !prepared.sessionId) {
12141
12198
  return;
12142
12199
  }
@@ -12248,6 +12305,7 @@ var createAntigravityPlugin = (providerId) => async ({ client, directory }) => {
12248
12305
  let tokenConsumed = false;
12249
12306
  let capacityRetryCount = 0;
12250
12307
  let lastEndpointIndex = -1;
12308
+ let apiRequestCount = 0;
12251
12309
  for (let i = 0; i < ANTIGRAVITY_ENDPOINT_FALLBACKS.length; i++) {
12252
12310
  if (i !== lastEndpointIndex) {
12253
12311
  capacityRetryCount = 0;
@@ -12310,7 +12368,8 @@ var createAntigravityPlugin = (providerId) => async ({ client, directory }) => {
12310
12368
  tokenConsumed = getTokenTracker().consume(account.index);
12311
12369
  }
12312
12370
  const response = await fetch(prepared.request, prepared.init);
12313
- pushDebug(`status=${response.status} ${response.statusText}`);
12371
+ apiRequestCount++;
12372
+ pushDebug(`status=${response.status} ${response.statusText} (api_request #${apiRequestCount})`);
12314
12373
  if (response.status === 429 || response.status === 503 || response.status === 529) {
12315
12374
  if (tokenConsumed) {
12316
12375
  getTokenTracker().refund(account.index);
@@ -12335,12 +12394,12 @@ var createAntigravityPlugin = (providerId) => async ({ client, directory }) => {
12335
12394
  "warning"
12336
12395
  );
12337
12396
  await sleep(waitMs, abortSignal);
12338
- if (capacityRetryCount < 3) {
12397
+ if (capacityRetryCount < 1) {
12339
12398
  capacityRetryCount++;
12340
12399
  i -= 1;
12341
12400
  continue;
12342
12401
  } else {
12343
- pushDebug(`Max capacity retries (3) exhausted for endpoint ${currentEndpoint}, regenerating fingerprint...`);
12402
+ pushDebug(`Max capacity retries (1) exhausted for endpoint ${currentEndpoint}, regenerating fingerprint...`);
12344
12403
  const newFingerprint = accountManager.regenerateAccountFingerprint(account.index);
12345
12404
  if (newFingerprint) {
12346
12405
  pushDebug(`Fingerprint regenerated for account ${account.index}`);
@@ -12592,6 +12651,9 @@ Alternatively, you can:
12592
12651
  );
12593
12652
  }
12594
12653
  }
12654
+ if (apiRequestCount > 1) {
12655
+ pushDebug(`[Quota] Total API requests for this user message: ${apiRequestCount} (${apiRequestCount - 1} retries)`);
12656
+ }
12595
12657
  return transformedResponse;
12596
12658
  } catch (error) {
12597
12659
  if (tokenConsumed) {
@@ -12638,6 +12700,27 @@ Alternatively, you can:
12638
12700
  }
12639
12701
  }
12640
12702
  if (shouldSwitchAccount) {
12703
+ accountSwitchCount++;
12704
+ if (accountSwitchCount > maxAccountSwitches) {
12705
+ pushDebug(`account-switch-cap: exceeded max_account_switches=${maxAccountSwitches}, giving up`);
12706
+ if (lastFailure) {
12707
+ return transformAntigravityResponse(
12708
+ lastFailure.response,
12709
+ lastFailure.streaming,
12710
+ lastFailure.debugContext,
12711
+ lastFailure.requestedModel,
12712
+ lastFailure.projectId,
12713
+ lastFailure.endpoint,
12714
+ lastFailure.effectiveModel,
12715
+ lastFailure.sessionId,
12716
+ lastFailure.toolDebugMissing,
12717
+ lastFailure.toolDebugSummary,
12718
+ lastFailure.toolDebugPayload,
12719
+ debugLines
12720
+ );
12721
+ }
12722
+ throw lastError || new Error(`Exceeded max account switches (${maxAccountSwitches}). All accounts rate-limited.`);
12723
+ }
12641
12724
  if (accountCount <= 1) {
12642
12725
  if (lastFailure) {
12643
12726
  return transformAntigravityResponse(
@@ -13481,7 +13564,7 @@ function resolveHeaderRoutingDecision(urlString, family, config) {
13481
13564
  cliFirst,
13482
13565
  preferredHeaderStyle,
13483
13566
  explicitQuota,
13484
- allowQuotaFallback: family === "gemini"
13567
+ allowQuotaFallback: family === "gemini" && !!(config.quota_style_fallback ?? false)
13485
13568
  };
13486
13569
  }
13487
13570
  function getCliFirst(config) {