@hashimkarim/usagestat-linux-x64-gnu 2.0.0-alpha.3 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (144) hide show
  1. package/native-manifest.json +735 -69
  2. package/package.json +112 -1
  3. package/plugins/UPSTREAM-LICENSES.md +6 -2
  4. package/plugins/_provider-icons/LICENSE +21 -0
  5. package/plugins/_provider-icons/NOTICE +12 -0
  6. package/plugins/_provider-icons/licenses/CodexBar-MIT.txt +21 -0
  7. package/plugins/_provider-icons/licenses/LobeHub-MIT.txt +21 -0
  8. package/plugins/_provider-icons/licenses/UsageStat-Bar-MIT.txt +21 -0
  9. package/plugins/_provider-icons/manifest.json +1219 -0
  10. package/plugins/_provider-icons/provenance.json +269 -0
  11. package/plugins/_provider-icons/source.json +4 -0
  12. package/plugins/abacus-ai/icon-color.svg +18 -0
  13. package/plugins/aixy/LICENSE +21 -0
  14. package/plugins/aixy/plugin.js +261 -0
  15. package/plugins/aixy/plugin.json +24 -0
  16. package/plugins/antigravity/plugin.js +168 -57
  17. package/plugins/antigravity-cli/icon-color.svg +1 -0
  18. package/plugins/antigravity-cli/icon.svg +1 -3
  19. package/plugins/antigravity-cli/plugin.js +18 -16
  20. package/plugins/antigravity-ide/icon-color.svg +1 -0
  21. package/plugins/antigravity-ide/icon.svg +1 -3
  22. package/plugins/antigravity-ide/plugin.js +15 -6
  23. package/plugins/atlascloud/LICENSE +21 -0
  24. package/plugins/atlascloud/icon-color.svg +1 -0
  25. package/plugins/atlascloud/icon.svg +1 -0
  26. package/plugins/atlascloud/plugin.js +49 -0
  27. package/plugins/atlascloud/plugin.json +23 -0
  28. package/plugins/augment/icon-color.svg +14 -0
  29. package/plugins/bifrost/LICENSE +21 -0
  30. package/plugins/bifrost/plugin.js +361 -0
  31. package/plugins/bifrost/plugin.json +23 -0
  32. package/plugins/claude/plugin.js +302 -152
  33. package/plugins/claude/plugin.json +1 -1
  34. package/plugins/clinepass/plugin.js +19 -3
  35. package/plugins/codebuff/icon-color.svg +92 -0
  36. package/plugins/coderabbit/plugin.js +25 -0
  37. package/plugins/coderabbit/plugin.json +12 -0
  38. package/plugins/codex/plugin.js +1 -0
  39. package/plugins/command-code/icon-color.svg +3 -0
  40. package/plugins/command-code/plugin.js +7 -3
  41. package/plugins/copilot/icon.svg +1 -1
  42. package/plugins/crof/icon-color.svg +3 -0
  43. package/plugins/crofai/icon-color.svg +3 -0
  44. package/plugins/crofai/icon.svg +2 -15
  45. package/plugins/cursor/icon-color.svg +1 -0
  46. package/plugins/deepinfra/icon-color.svg +1 -0
  47. package/plugins/deepinfra/icon.svg +1 -4
  48. package/plugins/deepseek/plugin.js +150 -59
  49. package/plugins/deepseek/plugin.json +3 -1
  50. package/plugins/devin/plugin.js +3 -0
  51. package/plugins/devpass/LICENSE +21 -0
  52. package/plugins/devpass/plugin.js +115 -0
  53. package/plugins/devpass/plugin.json +23 -0
  54. package/plugins/elevenlabs/icon-color.svg +4 -0
  55. package/plugins/factory/icon-color.svg +1 -0
  56. package/plugins/fireworks-ai/icon-color.svg +1 -0
  57. package/plugins/fireworks-ai/icon.svg +1 -6
  58. package/plugins/gemini-apps/LICENSE +22 -0
  59. package/plugins/gemini-apps/icon-color.svg +1 -0
  60. package/plugins/gemini-apps/icon.svg +1 -0
  61. package/plugins/gemini-apps/plugin.js +470 -0
  62. package/plugins/gemini-apps/plugin.json +19 -0
  63. package/plugins/gitkraken/LICENSE +21 -0
  64. package/plugins/gitkraken/plugin.js +153 -0
  65. package/plugins/gitkraken/plugin.json +24 -0
  66. package/plugins/grok/icon-color.svg +1 -0
  67. package/plugins/groqcloud/icon-color.svg +1 -0
  68. package/plugins/helmcode/LICENSE +21 -0
  69. package/plugins/helmcode/plugin.js +188 -0
  70. package/plugins/helmcode/plugin.json +24 -0
  71. package/plugins/huggingface/LICENSE +21 -0
  72. package/plugins/huggingface/icon-color.svg +1 -0
  73. package/plugins/huggingface/icon.svg +1 -0
  74. package/plugins/huggingface/plugin.js +293 -0
  75. package/plugins/huggingface/plugin.json +25 -0
  76. package/plugins/hyper/LICENSE +21 -0
  77. package/plugins/hyper/plugin.js +131 -0
  78. package/plugins/hyper/plugin.json +26 -0
  79. package/plugins/kilo/icon-color.svg +1 -0
  80. package/plugins/litellm/plugin.js +54 -3
  81. package/plugins/llmman/LICENSE +21 -0
  82. package/plugins/llmman/plugin.js +133 -0
  83. package/plugins/llmman/plugin.json +23 -0
  84. package/plugins/longcat/icon-color.svg +1 -0
  85. package/plugins/longcat/icon.svg +1 -4
  86. package/plugins/manus/icon-color.svg +6 -0
  87. package/plugins/mimo/icon-color.svg +4 -0
  88. package/plugins/mimo/icon.svg +4 -1
  89. package/plugins/mistral/plugin.js +164 -27
  90. package/plugins/moonshot/icon-color.svg +1 -0
  91. package/plugins/muse/LICENSE +21 -0
  92. package/plugins/muse/plugin.js +319 -0
  93. package/plugins/muse/plugin.json +26 -0
  94. package/plugins/nous/LICENSE +21 -0
  95. package/plugins/nous/icon-color.svg +1 -0
  96. package/plugins/nous/icon.svg +1 -0
  97. package/plugins/nous/plugin.js +124 -0
  98. package/plugins/nous/plugin.json +24 -0
  99. package/plugins/ollama/icon-color.svg +1 -0
  100. package/plugins/openai-api/icon-color.svg +1 -0
  101. package/plugins/opencode/icon-color.svg +1 -0
  102. package/plugins/opencode-go/icon-color.svg +1 -0
  103. package/plugins/opencode-go/plugin.js +30 -12
  104. package/plugins/openrouter/icon-color.svg +1 -0
  105. package/plugins/pi/plugin.js +113 -0
  106. package/plugins/pi/plugin.json +11 -0
  107. package/plugins/qwencloud/icon-color.svg +1 -0
  108. package/plugins/qwencloud/icon.svg +1 -4
  109. package/plugins/raycast/LICENSE +21 -0
  110. package/plugins/raycast/plugin.js +174 -0
  111. package/plugins/raycast/plugin.json +24 -0
  112. package/plugins/replicate/LICENSE +21 -0
  113. package/plugins/replicate/icon-color.svg +1 -0
  114. package/plugins/replicate/icon.svg +1 -0
  115. package/plugins/replicate/plugin.js +165 -0
  116. package/plugins/replicate/plugin.json +24 -0
  117. package/plugins/synthetic/icon-color.svg +14 -0
  118. package/plugins/typesafe/LICENSE +21 -0
  119. package/plugins/typesafe/plugin.js +225 -0
  120. package/plugins/typesafe/plugin.json +24 -0
  121. package/plugins/v0/LICENSE +21 -0
  122. package/plugins/v0/icon-color.svg +1 -0
  123. package/plugins/v0/icon.svg +1 -0
  124. package/plugins/v0/plugin.js +214 -0
  125. package/plugins/v0/plugin.json +24 -0
  126. package/plugins/venice/plugin.js +50 -1
  127. package/plugins/venice/plugin.json +2 -1
  128. package/plugins/vercel/LICENSE +21 -0
  129. package/plugins/vercel/icon-color.svg +1 -0
  130. package/plugins/vercel/icon.svg +1 -0
  131. package/plugins/vercel/plugin.js +55 -0
  132. package/plugins/vercel/plugin.json +23 -0
  133. package/plugins/windsurf/icon-color.svg +1 -0
  134. package/plugins/xai/icon-color.svg +1 -0
  135. package/plugins/xai/icon.svg +1 -7
  136. package/plugins/xkiro/LICENSE +21 -0
  137. package/plugins/xkiro/plugin.js +99 -0
  138. package/plugins/xkiro/plugin.json +23 -0
  139. package/plugins/zai/icon-color.svg +1 -0
  140. package/plugins/zai/plugin.js +5 -1
  141. package/plugins/zenmux/icon-color.svg +1 -0
  142. package/plugins/zenmux/icon.svg +1 -3
  143. package/usagestat +0 -0
  144. package/usagestatd +0 -0
@@ -155,6 +155,13 @@
155
155
  ctx.host.log.warn("refresh skipped: no refresh token")
156
156
  return null
157
157
  }
158
+ var retryPath = ctx.app.pluginDataDir + "/oauth-retry-" + ctx.host.crypto.sha256Hex(refreshTokenValue) + ".json"
159
+ try {
160
+ if (ctx.host.fs.exists(retryPath)) {
161
+ var rejection = ctx.util.tryParseJson(ctx.host.fs.readText(retryPath))
162
+ if (rejection && rejection.retryAfterMs > Date.now()) return null
163
+ }
164
+ } catch (_) { /* A missing/corrupt cooldown must not prevent login. */ }
158
165
  ctx.host.log.info("attempting Google OAuth token refresh")
159
166
  try {
160
167
  var resp = ctx.host.http.request({
@@ -169,6 +176,12 @@
169
176
  timeoutMs: 15000,
170
177
  })
171
178
  if (resp.status < 200 || resp.status >= 300) {
179
+ var failure = ctx.util.tryParseJson(resp.bodyText)
180
+ if (resp.status === 400 && failure && failure.error === "invalid_grant") {
181
+ // A revoked token will not recover on the next dashboard poll. Store
182
+ // only a deadline under its hash; a new login bypasses this cooldown.
183
+ try { ctx.host.fs.writeText(retryPath, JSON.stringify({ retryAfterMs: Date.now() + 60 * 60 * 1000 })) } catch (_) {}
184
+ }
172
185
  ctx.host.log.warn("Google OAuth refresh returned status: " + resp.status)
173
186
  return null
174
187
  }
@@ -188,22 +201,34 @@
188
201
 
189
202
  // --- Token cache ---
190
203
 
204
+ function tokenCachePath(ctx, profileKey) {
205
+ // Include another hash so the filename remains bounded even on older hosts
206
+ // or test callers with an opaque profile key.
207
+ return ctx.app.pluginDataDir + "/auth-" + ctx.host.crypto.sha256Hex(profileKey) + ".json"
208
+ }
209
+
191
210
  function loadCachedToken(ctx, profileKey) {
192
- var path = ctx.app.pluginDataDir + "/auth.json"
193
- try {
194
- if (!ctx.host.fs.exists(path)) return null
195
- var data = ctx.util.tryParseJson(ctx.host.fs.readText(path))
196
- if (!data || !profileKey || data.profileKey !== profileKey || !data.accessToken || !data.expiresAtMs) return null
197
- if (data.expiresAtMs <= Date.now()) return null
198
- return data.accessToken
199
- } catch (e) {
200
- ctx.host.log.warn("failed to read cached token: " + String(e))
201
- return null
211
+ if (!profileKey) return null
212
+ // Read the old single-slot cache for compatibility, but write only the
213
+ // per-profile file so the IDE and agy cannot evict each other's token.
214
+ var paths = [tokenCachePath(ctx, profileKey), ctx.app.pluginDataDir + "/auth.json"]
215
+ for (var i = 0; i < paths.length; i++) {
216
+ try {
217
+ if (!ctx.host.fs.exists(paths[i])) continue
218
+ var data = ctx.util.tryParseJson(ctx.host.fs.readText(paths[i]))
219
+ if (!data || data.profileKey !== profileKey || !data.accessToken || !data.expiresAtMs) continue
220
+ if (data.expiresAtMs <= Date.now()) continue
221
+ return data.accessToken
222
+ } catch (e) {
223
+ ctx.host.log.warn("failed to read cached token: " + String(e))
224
+ }
202
225
  }
226
+ return null
203
227
  }
204
228
 
205
229
  function cacheToken(ctx, accessToken, expiresInSeconds, profileKey) {
206
- var path = ctx.app.pluginDataDir + "/auth.json"
230
+ if (!profileKey) return
231
+ var path = tokenCachePath(ctx, profileKey)
207
232
  try {
208
233
  ctx.host.fs.writeText(path, JSON.stringify({
209
234
  accessToken: accessToken,
@@ -238,58 +263,126 @@
238
263
  return text || null
239
264
  }
240
265
 
241
- function extractTokenFromObject(obj) {
242
- if (!obj || typeof obj !== "object") return null
266
+ // agy stores {"token":{"access_token","refresh_token","expiry"},"id_token":...}.
267
+ // Search the whole payload for a bearer token before falling back to an ID
268
+ // token: Cloud Code rejects ID tokens, so a top-level id_token must not win.
269
+ var ACCESS_KEYS = ["access_token", "accessToken", "bearerToken", "auth_token", "authToken"]
270
+ var NESTED_KEYS = ["token", "tokens", "oauth", "oauth2", "credentials", "auth"]
243
271
 
244
- var directKeys = [
245
- "access_token",
246
- "accessToken",
247
- "token",
248
- "id_token",
249
- "idToken",
250
- "bearerToken",
251
- "auth_token",
252
- "authToken",
253
- ]
254
- for (var i = 0; i < directKeys.length; i++) {
255
- var value = obj[directKeys[i]]
272
+ function findStringDeep(obj, keys, depth) {
273
+ if (!obj || typeof obj !== "object" || depth > 4) return null
274
+ for (var i = 0; i < keys.length; i++) {
275
+ var value = obj[keys[i]]
256
276
  if (typeof value === "string" && value.trim()) return value.trim()
257
277
  }
258
-
259
- var nestedKeys = ["token", "tokens", "oauth", "oauth2", "credentials", "auth"]
260
- for (var j = 0; j < nestedKeys.length; j++) {
261
- var nested = extractTokenFromObject(obj[nestedKeys[j]])
278
+ for (var j = 0; j < NESTED_KEYS.length; j++) {
279
+ var nested = findStringDeep(obj[NESTED_KEYS[j]], keys, depth + 1)
262
280
  if (nested) return nested
263
281
  }
282
+ return null
283
+ }
264
284
 
285
+ function extractTokenFromObject(obj) {
286
+ if (!obj || typeof obj !== "object") return null
287
+ return findStringDeep(obj, ACCESS_KEYS, 0) || findStringDeep(obj, ["token"], 0) ||
288
+ findStringDeep(obj, ["id_token", "idToken"], 0)
289
+ }
290
+
291
+ function parseExpiryMs(value) {
292
+ if (typeof value === "number" && isFinite(value)) return value < 1e12 ? value * 1000 : value
293
+ if (typeof value === "string" && value.trim()) {
294
+ var ms = Date.parse(value.trim())
295
+ return isFinite(ms) ? ms : null
296
+ }
265
297
  return null
266
298
  }
267
299
 
268
- function extractAgyAccessToken(ctx, raw) {
300
+ // Returns {accessToken, refreshToken, expiryMs} from agy's keyring payload.
301
+ function parseAgyCredentials(ctx, raw) {
269
302
  var text = unwrapAgyKeychainText(ctx, raw)
270
303
  if (!text) return null
271
-
272
304
  var parsed = ctx.util.tryParseJson(text)
273
- if (typeof parsed === "string" && parsed.trim()) return parsed.trim()
274
- if (parsed) return extractTokenFromObject(parsed)
305
+ if (typeof parsed === "string" && parsed.trim()) return { accessToken: parsed.trim(), refreshToken: null, expiryMs: null }
306
+ if (parsed && typeof parsed === "object") {
307
+ var expiry = findStringDeep(parsed, ["expiry", "expires_at", "expiresAt"], 0)
308
+ var numericExpiry = parsed.token && typeof parsed.token === "object" ? parsed.token.expiry_date : null
309
+ return {
310
+ accessToken: extractTokenFromObject(parsed),
311
+ refreshToken: findStringDeep(parsed, ["refresh_token", "refreshToken"], 0),
312
+ expiryMs: parseExpiryMs(expiry) || parseExpiryMs(numericExpiry),
313
+ }
314
+ }
315
+ if (text.indexOf("Bearer ") === 0) return { accessToken: text.slice("Bearer ".length).trim() || null, refreshToken: null, expiryMs: null }
316
+ return { accessToken: text, refreshToken: null, expiryMs: null }
317
+ }
275
318
 
276
- if (text.indexOf("Bearer ") === 0) return text.slice("Bearer ".length).trim() || null
277
- return text
319
+ function extractAgyAccessToken(ctx, raw) {
320
+ var creds = parseAgyCredentials(ctx, raw)
321
+ return creds ? creds.accessToken : null
278
322
  }
279
323
 
280
- function loadAgyKeychainToken(ctx) {
324
+ function loadAgyCredentials(ctx) {
281
325
  if (!ctx.host.keychain || typeof ctx.host.keychain.readGenericPassword !== "function") {
282
326
  return null
283
327
  }
284
328
  try {
285
- var raw = ctx.host.keychain.readGenericPassword(AGY_KEYCHAIN_SERVICE, AGY_KEYCHAIN_ACCOUNT)
286
- return extractAgyAccessToken(ctx, raw)
329
+ return parseAgyCredentials(ctx, ctx.host.keychain.readGenericPassword(AGY_KEYCHAIN_SERVICE, AGY_KEYCHAIN_ACCOUNT))
287
330
  } catch (e) {
288
331
  ctx.host.log.info("agy keychain read failed: " + String(e))
289
332
  return null
290
333
  }
291
334
  }
292
335
 
336
+ function loadAgyKeychainToken(ctx) {
337
+ var creds = loadAgyCredentials(ctx)
338
+ return creds ? creds.accessToken : null
339
+ }
340
+
341
+ // Probe Cloud Code with agy's credentials, refreshing an expired or rejected
342
+ // access token with agy's refresh token (same Google OAuth client).
343
+ function probeAgyCredentials(ctx) {
344
+ var creds = loadAgyCredentials(ctx)
345
+ if (!creds || (!creds.accessToken && !creds.refreshToken)) return null
346
+ var profileKey = creds.refreshToken ? ctx.host.crypto.sha256Hex("agy\n" + creds.refreshToken) : null
347
+ var candidates = []
348
+ var cached = loadCachedToken(ctx, profileKey)
349
+ if (cached) candidates.push(cached)
350
+ var expired = creds.expiryMs != null && creds.expiryMs <= Date.now() + 60000
351
+ if (creds.accessToken && !expired && candidates.indexOf(creds.accessToken) === -1) candidates.push(creds.accessToken)
352
+ var last = null
353
+ for (var i = 0; i < candidates.length; i++) {
354
+ var result = probeAgyToken(ctx, candidates[i])
355
+ if (result && !result._authFailed) return result
356
+ if (result) last = result
357
+ }
358
+ if (creds.refreshToken && (last || !candidates.length)) {
359
+ var refreshed = refreshAccessToken(ctx, creds.refreshToken, profileKey)
360
+ if (refreshed) {
361
+ var refreshedResult = probeAgyToken(ctx, refreshed)
362
+ if (refreshedResult) return refreshedResult
363
+ }
364
+ }
365
+ return last
366
+ }
367
+
368
+ // Consumer agy accounts have no Cloud project, so retrieveUserQuota answers
369
+ // 403 "no valid license" even with a valid token. fetchAvailableModels still
370
+ // reports per-model quota, so use it before treating the token as rejected.
371
+ function probeAgyToken(ctx, token) {
372
+ var quota = probeAgyCloudCode(ctx, token)
373
+ if (quota && !quota._authFailed) return quota
374
+ var models = probeCloudCode(ctx, token, "agy", true)
375
+ if (models && !models._authFailed) {
376
+ if (models._summaryLines) return { plan: null, lines: models._summaryLines }
377
+ var lines = buildModelLines(ctx, parseCloudCodeModels(models))
378
+ if (lines.length > 0) return { plan: null, lines: lines }
379
+ return null
380
+ }
381
+ // A quota 403 can mean "no license", not an invalid bearer. If the model
382
+ // endpoint is temporarily unavailable, don't turn that into a token refresh.
383
+ return models
384
+ }
385
+
293
386
  // --- LS discovery ---
294
387
 
295
388
  function discoverNative(ctx, options) {
@@ -355,7 +448,7 @@
355
448
  return null
356
449
  }
357
450
 
358
- function callLs(ctx, port, scheme, csrf, method, body) {
451
+ function callLs(ctx, port, scheme, csrf, method, body, timeoutMs) {
359
452
  var resp = ctx.host.http.request({
360
453
  method: "POST",
361
454
  url: scheme + "://127.0.0.1:" + port + "/" + LS_SERVICE + "/" + method,
@@ -365,7 +458,7 @@
365
458
  "x-codeium-csrf-token": csrf,
366
459
  },
367
460
  bodyText: JSON.stringify(body || {}),
368
- timeoutMs: 10000,
461
+ timeoutMs: timeoutMs || 10000,
369
462
  dangerouslyIgnoreTls: scheme === "https",
370
463
  })
371
464
  if (resp.status < 200 || resp.status >= 300) {
@@ -422,7 +515,8 @@
422
515
  var label = (typeof c.label === "string") ? c.label.trim() : ""
423
516
  if (!label) continue
424
517
  var qi = c.quotaInfo
425
- var frac = (qi && typeof qi.remainingFraction === "number") ? qi.remainingFraction : 0
518
+ if (!qi || !Number.isFinite(qi.remainingFraction)) continue
519
+ var frac = qi.remainingFraction
426
520
  var rtime = (qi && qi.resetTime) || undefined
427
521
  var pool = poolLabel(normalizeLabel(label))
428
522
  if (!deduped[pool] || frac < deduped[pool].remainingFraction) {
@@ -455,7 +549,7 @@
455
549
 
456
550
  // --- Cloud Code API ---
457
551
 
458
- function requestCloudCodeJson(ctx, path, token, userAgent, body) {
552
+ function requestCloudCodeJson(ctx, path, token, userAgent, body, timeoutMs) {
459
553
  for (var i = 0; i < CLOUD_CODE_URLS.length; i++) {
460
554
  try {
461
555
  var resp = ctx.host.http.request({
@@ -468,7 +562,7 @@
468
562
  "User-Agent": userAgent || "antigravity",
469
563
  },
470
564
  bodyText: JSON.stringify(body || {}),
471
- timeoutMs: 15000,
565
+ timeoutMs: timeoutMs || 15000,
472
566
  })
473
567
  if (!resp || typeof resp.status !== "number" || !Number.isFinite(resp.status)) {
474
568
  ctx.host.log.warn("Cloud Code returned invalid response shape (" + CLOUD_CODE_URLS[i] + ")")
@@ -490,7 +584,12 @@
490
584
  return null
491
585
  }
492
586
 
493
- function probeCloudCode(ctx, token, userAgent) {
587
+ function probeCloudCode(ctx, token, userAgent, skipSummary) {
588
+ if (!skipSummary) {
589
+ var summary = requestCloudCodeJson(ctx, "/v1internal:retrieveUserQuotaSummary", token, userAgent, {}, 2000)
590
+ var lines = ctx.util.groupedQuotaLines(summary)
591
+ if (lines.length) return { _summaryLines: lines }
592
+ }
494
593
  return requestCloudCodeJson(ctx, FETCH_MODELS_PATH, token, userAgent, {})
495
594
  }
496
595
 
@@ -511,7 +610,8 @@
511
610
  ""
512
611
  if (!displayName) continue
513
612
  var qi = m.quotaInfo
514
- var frac = (qi && typeof qi.remainingFraction === "number") ? qi.remainingFraction : 0
613
+ if (!qi || !Number.isFinite(qi.remainingFraction)) continue
614
+ var frac = qi.remainingFraction
515
615
  var rtime = (qi && qi.resetTime) || undefined
516
616
  configs.push({
517
617
  label: displayName,
@@ -542,7 +642,8 @@
542
642
  if (!bucket || typeof bucket !== "object") continue
543
643
  var modelId = (typeof bucket.modelId === "string" && bucket.modelId.trim()) || ""
544
644
  if (!modelId) continue
545
- var frac = (typeof bucket.remainingFraction === "number") ? bucket.remainingFraction : 0
645
+ if (!Number.isFinite(bucket.remainingFraction)) continue
646
+ var frac = bucket.remainingFraction
546
647
  configs.push({
547
648
  label: modelId,
548
649
  quotaInfo: { remainingFraction: frac, resetTime: bucket.resetTime || undefined },
@@ -560,6 +661,9 @@
560
661
  ? loadData.cloudaicompanionProject.trim()
561
662
  : null
562
663
  var quotaData = null
664
+ var summary = requestCloudCodeJson(ctx, "/v1internal:retrieveUserQuotaSummary", token, "agy", project ? { project: project } : {}, 2000)
665
+ var summaryLines = ctx.util.groupedQuotaLines(summary)
666
+ if (summaryLines.length) return { plan: readAgyPlan(loadData), lines: summaryLines }
563
667
  if (project) {
564
668
  quotaData = requestCloudCodeJson(ctx, RETRIEVE_QUOTA_PATH, token, "agy", { project: project })
565
669
  }
@@ -590,7 +694,13 @@
590
694
  locale: "en",
591
695
  }
592
696
 
593
- // Try GetUserStatus first, fall back to GetCommandModelConfigs
697
+ var summaryLines = []
698
+ try {
699
+ summaryLines = ctx.util.groupedQuotaLines(callLs(ctx, found.port, found.scheme, discovery.csrf,
700
+ "RetrieveUserQuotaSummary", { forceRefresh: true }, 2000))
701
+ } catch (_) {}
702
+
703
+ // GetUserStatus also supplies identity when grouped quota is available.
594
704
  var data = null
595
705
  try {
596
706
  data = callLs(ctx, found.port, found.scheme, discovery.csrf, "GetUserStatus", { metadata: metadata })
@@ -599,7 +709,7 @@
599
709
  }
600
710
  var hasUserStatus = data && data.userStatus
601
711
 
602
- if (!hasUserStatus) {
712
+ if (!hasUserStatus && !summaryLines.length) {
603
713
  ctx.host.log.warn("GetUserStatus failed, trying GetCommandModelConfigs")
604
714
  data = callLs(ctx, found.port, found.scheme, discovery.csrf, "GetCommandModelConfigs", { metadata: metadata })
605
715
  }
@@ -610,6 +720,8 @@
610
720
  configs = (data.userStatus.cascadeModelConfigData || {}).clientModelConfigs || []
611
721
  } else if (data && data.clientModelConfigs) {
612
722
  configs = data.clientModelConfigs
723
+ } else if (summaryLines.length) {
724
+ configs = []
613
725
  } else {
614
726
  return null
615
727
  }
@@ -621,7 +733,7 @@
621
733
  filtered.push(configs[j])
622
734
  }
623
735
 
624
- var lines = buildModelLines(ctx, filtered)
736
+ var lines = summaryLines.length ? summaryLines : buildModelLines(ctx, filtered)
625
737
  if (lines.length === 0) return null
626
738
 
627
739
  var plan = null
@@ -682,7 +794,7 @@
682
794
 
683
795
  var profileKey = dbTokenCandidates.length ? dbTokenCandidates[0].profileKey : null
684
796
  var cached = loadCachedToken(ctx, profileKey)
685
- if (cached && tokens.indexOf(cached) === -1) tokens.push(cached)
797
+ if (cached && tokens.indexOf(cached) === -1) tokens.unshift(cached)
686
798
 
687
799
  var ccData = null
688
800
  var sawAuthFailure = false
@@ -717,16 +829,15 @@
717
829
  }
718
830
  }
719
831
 
720
- if (!dbTokenCandidates.length && (!ccData || ccData._authFailed)) {
721
- var agyToken = loadAgyKeychainToken(ctx)
722
- if (agyToken) {
723
- var agyResult = probeAgyCloudCode(ctx, agyToken)
724
- if (agyResult && !agyResult._authFailed) return agyResult
725
- if (agyResult && agyResult._authFailed) ccData = agyResult
726
- }
832
+ // agy's own login also covers users whose IDE database is stale or absent.
833
+ if (!explicitDb && (!ccData || ccData._authFailed)) {
834
+ var agyResult = probeAgyCredentials(ctx)
835
+ if (agyResult && !agyResult._authFailed) return agyResult
836
+ if (agyResult && agyResult._authFailed) ccData = agyResult
727
837
  }
728
838
 
729
839
  if (ccData && !ccData._authFailed) {
840
+ if (ccData._summaryLines) return { plan: null, lines: ccData._summaryLines }
730
841
  var configs = parseCloudCodeModels(ccData)
731
842
  var lines = buildModelLines(ctx, configs)
732
843
  if (lines.length > 0) return { plan: null, lines: lines }
@@ -0,0 +1 @@
1
+ <svg height="1em" style="flex:none;line-height:1" viewBox="0 0 24 24" width="1em" xmlns="http://www.w3.org/2000/svg"><title>Antigravity</title><mask height="23" id="lobe-icons-antigravity-0-_R_0_" maskUnits="userSpaceOnUse" width="24" x="0" y="1"><path d="M21.751 22.607c1.34 1.005 3.35.335 1.508-1.508C17.73 15.74 18.904 1 12.037 1 5.17 1 6.342 15.74.815 21.1c-2.01 2.009.167 2.511 1.507 1.506 5.192-3.517 4.857-9.714 9.715-9.714 4.857 0 4.522 6.197 9.714 9.715z" fill="#fff"></path></mask><g mask="url(#lobe-icons-antigravity-0-_R_0_)"><g filter="url(#lobe-icons-antigravity-1-_R_0_)"><path d="M-1.018-3.992c-.408 3.591 2.686 6.89 6.91 7.37 4.225.48 7.98-2.043 8.387-5.633.408-3.59-2.686-6.89-6.91-7.37-4.225-.479-7.98 2.043-8.387 5.633z" fill="#FFE432"></path></g><g filter="url(#lobe-icons-antigravity-2-_R_0_)"><path d="M15.269 7.747c1.058 4.557 5.691 7.374 10.348 6.293 4.657-1.082 7.575-5.653 6.516-10.21-1.058-4.556-5.691-7.374-10.348-6.292-4.657 1.082-7.575 5.653-6.516 10.21z" fill="#FC413D"></path></g><g filter="url(#lobe-icons-antigravity-3-_R_0_)"><path d="M-12.443 10.804c1.338 4.703 7.36 7.11 13.453 5.378 6.092-1.733 9.947-6.95 8.61-11.652C8.282-.173 2.26-2.58-3.833-.848-9.925.884-13.78 6.1-12.443 10.804z" fill="#00B95C"></path></g><g filter="url(#lobe-icons-antigravity-4-_R_0_)"><path d="M-12.443 10.804c1.338 4.703 7.36 7.11 13.453 5.378 6.092-1.733 9.947-6.95 8.61-11.652C8.282-.173 2.26-2.58-3.833-.848-9.925.884-13.78 6.1-12.443 10.804z" fill="#00B95C"></path></g><g filter="url(#lobe-icons-antigravity-5-_R_0_)"><path d="M-7.608 14.703c3.352 3.424 9.126 3.208 12.896-.483 3.77-3.69 4.108-9.459.756-12.883C2.69-2.087-3.083-1.871-6.853 1.82c-3.77 3.69-4.108 9.458-.755 12.883z" fill="#00B95C"></path></g><g filter="url(#lobe-icons-antigravity-6-_R_0_)"><path d="M9.932 27.617c1.04 4.482 5.384 7.303 9.7 6.3 4.316-1.002 6.971-5.448 5.93-9.93-1.04-4.483-5.384-7.304-9.7-6.301-4.316 1.002-6.971 5.448-5.93 9.93z" fill="#3186FF"></path></g><g filter="url(#lobe-icons-antigravity-7-_R_0_)"><path d="M2.572-8.185C.392-3.329 2.778 2.472 7.9 4.771c5.122 2.3 11.042.227 13.222-4.63 2.18-4.855-.205-10.656-5.327-12.955-5.122-2.3-11.042-.227-13.222 4.63z" fill="#FBBC04"></path></g><g filter="url(#lobe-icons-antigravity-8-_R_0_)"><path d="M-3.267 38.686c-5.277-2.072 3.742-19.117 5.984-24.83 2.243-5.712 8.34-8.664 13.616-6.592 5.278 2.071 11.533 13.482 9.29 19.195-2.242 5.713-23.613 14.298-28.89 12.227z" fill="#3186FF"></path></g><g filter="url(#lobe-icons-antigravity-9-_R_0_)"><path d="M28.71 17.471c-1.413 1.649-5.1.808-8.236-1.878-3.135-2.687-4.531-6.201-3.118-7.85 1.412-1.649 5.1-.808 8.235 1.878s4.532 6.2 3.119 7.85z" fill="#749BFF"></path></g><g filter="url(#lobe-icons-antigravity-10-_R_0_)"><path d="M18.163 9.077c5.81 3.93 12.502 4.19 14.946.577 2.443-3.612-.287-9.727-6.098-13.658-5.81-3.931-12.502-4.19-14.946-.577-2.443 3.612.287 9.727 6.098 13.658z" fill="#FC413D"></path></g><g filter="url(#lobe-icons-antigravity-11-_R_0_)"><path d="M-.915 2.684c-1.44 3.473-.97 6.967 1.05 7.804 2.02.837 4.824-1.3 6.264-4.772 1.44-3.473.97-6.967-1.05-7.804-2.02-.837-4.824 1.3-6.264 4.772z" fill="#FFEE48"></path></g></g><defs><filter color-interpolation-filters="sRGB" filterUnits="userSpaceOnUse" height="17.587" id="lobe-icons-antigravity-1-_R_0_" width="19.838" x="-3.288" y="-11.917"><feFlood flood-opacity="0" result="BackgroundImageFix"></feFlood><feBlend in="SourceGraphic" in2="BackgroundImageFix" result="shape"></feBlend><feGaussianBlur result="effect1_foregroundBlur_977_115" stdDeviation="1.117"></feGaussianBlur></filter><filter color-interpolation-filters="sRGB" filterUnits="userSpaceOnUse" height="38.565" id="lobe-icons-antigravity-2-_R_0_" width="38.9" x="4.251" y="-13.493"><feFlood flood-opacity="0" result="BackgroundImageFix"></feFlood><feBlend in="SourceGraphic" in2="BackgroundImageFix" result="shape"></feBlend><feGaussianBlur result="effect1_foregroundBlur_977_115" stdDeviation="5.4"></feGaussianBlur></filter><filter color-interpolation-filters="sRGB" filterUnits="userSpaceOnUse" height="36.517" id="lobe-icons-antigravity-3-_R_0_" width="40.955" x="-21.889" y="-10.592"><feFlood flood-opacity="0" result="BackgroundImageFix"></feFlood><feBlend in="SourceGraphic" in2="BackgroundImageFix" result="shape"></feBlend><feGaussianBlur result="effect1_foregroundBlur_977_115" stdDeviation="4.591"></feGaussianBlur></filter><filter color-interpolation-filters="sRGB" filterUnits="userSpaceOnUse" height="36.517" id="lobe-icons-antigravity-4-_R_0_" width="40.955" x="-21.889" y="-10.592"><feFlood flood-opacity="0" result="BackgroundImageFix"></feFlood><feBlend in="SourceGraphic" in2="BackgroundImageFix" result="shape"></feBlend><feGaussianBlur result="effect1_foregroundBlur_977_115" stdDeviation="4.591"></feGaussianBlur></filter><filter color-interpolation-filters="sRGB" filterUnits="userSpaceOnUse" height="36.595" id="lobe-icons-antigravity-5-_R_0_" width="36.632" x="-19.099" y="-10.278"><feFlood flood-opacity="0" result="BackgroundImageFix"></feFlood><feBlend in="SourceGraphic" in2="BackgroundImageFix" result="shape"></feBlend><feGaussianBlur result="effect1_foregroundBlur_977_115" stdDeviation="4.591"></feGaussianBlur></filter><filter color-interpolation-filters="sRGB" filterUnits="userSpaceOnUse" height="34.087" id="lobe-icons-antigravity-6-_R_0_" width="33.533" x=".981" y="8.758"><feFlood flood-opacity="0" result="BackgroundImageFix"></feFlood><feBlend in="SourceGraphic" in2="BackgroundImageFix" result="shape"></feBlend><feGaussianBlur result="effect1_foregroundBlur_977_115" stdDeviation="4.363"></feGaussianBlur></filter><filter color-interpolation-filters="sRGB" filterUnits="userSpaceOnUse" height="35.276" id="lobe-icons-antigravity-7-_R_0_" width="35.978" x="-6.143" y="-21.659"><feFlood flood-opacity="0" result="BackgroundImageFix"></feFlood><feBlend in="SourceGraphic" in2="BackgroundImageFix" result="shape"></feBlend><feGaussianBlur result="effect1_foregroundBlur_977_115" stdDeviation="3.954"></feGaussianBlur></filter><filter color-interpolation-filters="sRGB" filterUnits="userSpaceOnUse" height="46.523" id="lobe-icons-antigravity-8-_R_0_" width="45.114" x="-11.96" y="-.46"><feFlood flood-opacity="0" result="BackgroundImageFix"></feFlood><feBlend in="SourceGraphic" in2="BackgroundImageFix" result="shape"></feBlend><feGaussianBlur result="effect1_foregroundBlur_977_115" stdDeviation="3.531"></feGaussianBlur></filter><filter color-interpolation-filters="sRGB" filterUnits="userSpaceOnUse" height="24.054" id="lobe-icons-antigravity-9-_R_0_" width="25.094" x="10.485" y=".58"><feFlood flood-opacity="0" result="BackgroundImageFix"></feFlood><feBlend in="SourceGraphic" in2="BackgroundImageFix" result="shape"></feBlend><feGaussianBlur result="effect1_foregroundBlur_977_115" stdDeviation="3.159"></feGaussianBlur></filter><filter color-interpolation-filters="sRGB" filterUnits="userSpaceOnUse" height="30.007" id="lobe-icons-antigravity-10-_R_0_" width="33.508" x="5.833" y="-12.467"><feFlood flood-opacity="0" result="BackgroundImageFix"></feFlood><feBlend in="SourceGraphic" in2="BackgroundImageFix" result="shape"></feBlend><feGaussianBlur result="effect1_foregroundBlur_977_115" stdDeviation="2.669"></feGaussianBlur></filter><filter color-interpolation-filters="sRGB" filterUnits="userSpaceOnUse" height="26.151" id="lobe-icons-antigravity-11-_R_0_" width="22.194" x="-8.355" y="-8.876"><feFlood flood-opacity="0" result="BackgroundImageFix"></feFlood><feBlend in="SourceGraphic" in2="BackgroundImageFix" result="shape"></feBlend><feGaussianBlur result="effect1_foregroundBlur_977_115" stdDeviation="3.303"></feGaussianBlur></filter></defs></svg>
@@ -1,3 +1 @@
1
- <svg width="100" height="100" viewBox="0 0 100 100" fill="none" xmlns="http://www.w3.org/2000/svg">
2
- <path d="M85.2843 88.0301C90.1329 91.6664 97.4057 89.2422 90.7389 82.5755C70.7389 63.1816 74.9813 9.84827 50.1329 9.84827C25.2843 9.84827 29.5267 63.1816 9.52673 82.5755C2.25402 89.8483 10.1328 91.6664 14.9813 88.0301C33.7692 75.3028 32.5571 52.8786 50.1329 52.8786C67.7086 52.8786 66.4965 75.3028 85.2843 88.0301Z" fill="currentColor"/>
3
- </svg>
1
+ <svg fill="currentColor" fill-rule="evenodd" height="1em" style="flex:none;line-height:1" viewBox="0 0 24 24" width="1em" xmlns="http://www.w3.org/2000/svg"><title>Antigravity</title><path d="M21.751 22.607c1.34 1.005 3.35.335 1.508-1.508C17.73 15.74 18.904 1 12.037 1 5.17 1 6.342 15.74.815 21.1c-2.01 2.009.167 2.511 1.507 1.506 5.192-3.517 4.857-9.714 9.715-9.714 4.857 0 4.522 6.197 9.714 9.715z"></path></svg>
@@ -67,27 +67,23 @@
67
67
  function extractTokenFromObject(obj) {
68
68
  if (!obj || typeof obj !== "object") return null
69
69
 
70
- var directKeys = [
71
- "access_token",
72
- "accessToken",
73
- "token",
74
- "id_token",
75
- "idToken",
76
- "bearerToken",
77
- "auth_token",
78
- "authToken",
79
- ]
80
- for (var i = 0; i < directKeys.length; i += 1) {
81
- var value = obj[directKeys[i]]
70
+ // Prefer a bearer token anywhere in the payload; an ID token is a last resort
71
+ // (agy stores {"token":{"access_token":...},"id_token":...}).
72
+ return findTokenDeep(obj, ["access_token", "accessToken", "bearerToken", "auth_token", "authToken"], 0) ||
73
+ findTokenDeep(obj, ["token"], 0) || findTokenDeep(obj, ["id_token", "idToken"], 0)
74
+ }
75
+
76
+ function findTokenDeep(obj, keys, depth) {
77
+ if (!obj || typeof obj !== "object" || depth > 4) return null
78
+ for (var i = 0; i < keys.length; i += 1) {
79
+ var value = obj[keys[i]]
82
80
  if (typeof value === "string" && value.trim()) return value.trim()
83
81
  }
84
-
85
82
  var nestedKeys = ["token", "tokens", "oauth", "oauth2", "credentials", "auth"]
86
83
  for (var j = 0; j < nestedKeys.length; j += 1) {
87
- var nested = extractTokenFromObject(obj[nestedKeys[j]])
84
+ var nested = findTokenDeep(obj[nestedKeys[j]], keys, depth + 1)
88
85
  if (nested) return nested
89
86
  }
90
-
91
87
  return null
92
88
  }
93
89
 
@@ -298,7 +294,7 @@
298
294
  "User-Agent": "agy",
299
295
  },
300
296
  bodyText: JSON.stringify(body || {}),
301
- timeoutMs: 15000,
297
+ timeoutMs: opts.timeoutMs || 15000,
302
298
  })
303
299
  } catch (e) {
304
300
  if (opts.optional) {
@@ -544,6 +540,12 @@
544
540
  if (!loadData) throw REQUEST_FAILED_MESSAGE
545
541
  var plan = readPlan(loadData)
546
542
 
543
+ var project = typeof loadData.cloudaicompanionProject === "string" ? loadData.cloudaicompanionProject.trim() : ""
544
+ var summary = requestJsonAcrossBases(ctx, "/v1internal:retrieveUserQuotaSummary", authState.token,
545
+ project ? { project: project } : {}, { optional: true, timeoutMs: 2000 })
546
+ var summaryLines = ctx.util.groupedQuotaLines(summary)
547
+ if (summaryLines.length) return { plan: plan || undefined, lines: summaryLines }
548
+
547
549
  var buckets = []
548
550
  // fetchAvailableModels rejects `metadata` in the body (HTTP 400); use {} like Antigravity IDE.
549
551
  var fetchData = requestJsonAcrossBases(ctx, FETCH_MODELS_PATH, authState.token, {}, {
@@ -0,0 +1 @@
1
+ <svg height="1em" style="flex:none;line-height:1" viewBox="0 0 24 24" width="1em" xmlns="http://www.w3.org/2000/svg"><title>Antigravity</title><mask height="23" id="lobe-icons-antigravity-0-_R_0_" maskUnits="userSpaceOnUse" width="24" x="0" y="1"><path d="M21.751 22.607c1.34 1.005 3.35.335 1.508-1.508C17.73 15.74 18.904 1 12.037 1 5.17 1 6.342 15.74.815 21.1c-2.01 2.009.167 2.511 1.507 1.506 5.192-3.517 4.857-9.714 9.715-9.714 4.857 0 4.522 6.197 9.714 9.715z" fill="#fff"></path></mask><g mask="url(#lobe-icons-antigravity-0-_R_0_)"><g filter="url(#lobe-icons-antigravity-1-_R_0_)"><path d="M-1.018-3.992c-.408 3.591 2.686 6.89 6.91 7.37 4.225.48 7.98-2.043 8.387-5.633.408-3.59-2.686-6.89-6.91-7.37-4.225-.479-7.98 2.043-8.387 5.633z" fill="#FFE432"></path></g><g filter="url(#lobe-icons-antigravity-2-_R_0_)"><path d="M15.269 7.747c1.058 4.557 5.691 7.374 10.348 6.293 4.657-1.082 7.575-5.653 6.516-10.21-1.058-4.556-5.691-7.374-10.348-6.292-4.657 1.082-7.575 5.653-6.516 10.21z" fill="#FC413D"></path></g><g filter="url(#lobe-icons-antigravity-3-_R_0_)"><path d="M-12.443 10.804c1.338 4.703 7.36 7.11 13.453 5.378 6.092-1.733 9.947-6.95 8.61-11.652C8.282-.173 2.26-2.58-3.833-.848-9.925.884-13.78 6.1-12.443 10.804z" fill="#00B95C"></path></g><g filter="url(#lobe-icons-antigravity-4-_R_0_)"><path d="M-12.443 10.804c1.338 4.703 7.36 7.11 13.453 5.378 6.092-1.733 9.947-6.95 8.61-11.652C8.282-.173 2.26-2.58-3.833-.848-9.925.884-13.78 6.1-12.443 10.804z" fill="#00B95C"></path></g><g filter="url(#lobe-icons-antigravity-5-_R_0_)"><path d="M-7.608 14.703c3.352 3.424 9.126 3.208 12.896-.483 3.77-3.69 4.108-9.459.756-12.883C2.69-2.087-3.083-1.871-6.853 1.82c-3.77 3.69-4.108 9.458-.755 12.883z" fill="#00B95C"></path></g><g filter="url(#lobe-icons-antigravity-6-_R_0_)"><path d="M9.932 27.617c1.04 4.482 5.384 7.303 9.7 6.3 4.316-1.002 6.971-5.448 5.93-9.93-1.04-4.483-5.384-7.304-9.7-6.301-4.316 1.002-6.971 5.448-5.93 9.93z" fill="#3186FF"></path></g><g filter="url(#lobe-icons-antigravity-7-_R_0_)"><path d="M2.572-8.185C.392-3.329 2.778 2.472 7.9 4.771c5.122 2.3 11.042.227 13.222-4.63 2.18-4.855-.205-10.656-5.327-12.955-5.122-2.3-11.042-.227-13.222 4.63z" fill="#FBBC04"></path></g><g filter="url(#lobe-icons-antigravity-8-_R_0_)"><path d="M-3.267 38.686c-5.277-2.072 3.742-19.117 5.984-24.83 2.243-5.712 8.34-8.664 13.616-6.592 5.278 2.071 11.533 13.482 9.29 19.195-2.242 5.713-23.613 14.298-28.89 12.227z" fill="#3186FF"></path></g><g filter="url(#lobe-icons-antigravity-9-_R_0_)"><path d="M28.71 17.471c-1.413 1.649-5.1.808-8.236-1.878-3.135-2.687-4.531-6.201-3.118-7.85 1.412-1.649 5.1-.808 8.235 1.878s4.532 6.2 3.119 7.85z" fill="#749BFF"></path></g><g filter="url(#lobe-icons-antigravity-10-_R_0_)"><path d="M18.163 9.077c5.81 3.93 12.502 4.19 14.946.577 2.443-3.612-.287-9.727-6.098-13.658-5.81-3.931-12.502-4.19-14.946-.577-2.443 3.612.287 9.727 6.098 13.658z" fill="#FC413D"></path></g><g filter="url(#lobe-icons-antigravity-11-_R_0_)"><path d="M-.915 2.684c-1.44 3.473-.97 6.967 1.05 7.804 2.02.837 4.824-1.3 6.264-4.772 1.44-3.473.97-6.967-1.05-7.804-2.02-.837-4.824 1.3-6.264 4.772z" fill="#FFEE48"></path></g></g><defs><filter color-interpolation-filters="sRGB" filterUnits="userSpaceOnUse" height="17.587" id="lobe-icons-antigravity-1-_R_0_" width="19.838" x="-3.288" y="-11.917"><feFlood flood-opacity="0" result="BackgroundImageFix"></feFlood><feBlend in="SourceGraphic" in2="BackgroundImageFix" result="shape"></feBlend><feGaussianBlur result="effect1_foregroundBlur_977_115" stdDeviation="1.117"></feGaussianBlur></filter><filter color-interpolation-filters="sRGB" filterUnits="userSpaceOnUse" height="38.565" id="lobe-icons-antigravity-2-_R_0_" width="38.9" x="4.251" y="-13.493"><feFlood flood-opacity="0" result="BackgroundImageFix"></feFlood><feBlend in="SourceGraphic" in2="BackgroundImageFix" result="shape"></feBlend><feGaussianBlur result="effect1_foregroundBlur_977_115" stdDeviation="5.4"></feGaussianBlur></filter><filter color-interpolation-filters="sRGB" filterUnits="userSpaceOnUse" height="36.517" id="lobe-icons-antigravity-3-_R_0_" width="40.955" x="-21.889" y="-10.592"><feFlood flood-opacity="0" result="BackgroundImageFix"></feFlood><feBlend in="SourceGraphic" in2="BackgroundImageFix" result="shape"></feBlend><feGaussianBlur result="effect1_foregroundBlur_977_115" stdDeviation="4.591"></feGaussianBlur></filter><filter color-interpolation-filters="sRGB" filterUnits="userSpaceOnUse" height="36.517" id="lobe-icons-antigravity-4-_R_0_" width="40.955" x="-21.889" y="-10.592"><feFlood flood-opacity="0" result="BackgroundImageFix"></feFlood><feBlend in="SourceGraphic" in2="BackgroundImageFix" result="shape"></feBlend><feGaussianBlur result="effect1_foregroundBlur_977_115" stdDeviation="4.591"></feGaussianBlur></filter><filter color-interpolation-filters="sRGB" filterUnits="userSpaceOnUse" height="36.595" id="lobe-icons-antigravity-5-_R_0_" width="36.632" x="-19.099" y="-10.278"><feFlood flood-opacity="0" result="BackgroundImageFix"></feFlood><feBlend in="SourceGraphic" in2="BackgroundImageFix" result="shape"></feBlend><feGaussianBlur result="effect1_foregroundBlur_977_115" stdDeviation="4.591"></feGaussianBlur></filter><filter color-interpolation-filters="sRGB" filterUnits="userSpaceOnUse" height="34.087" id="lobe-icons-antigravity-6-_R_0_" width="33.533" x=".981" y="8.758"><feFlood flood-opacity="0" result="BackgroundImageFix"></feFlood><feBlend in="SourceGraphic" in2="BackgroundImageFix" result="shape"></feBlend><feGaussianBlur result="effect1_foregroundBlur_977_115" stdDeviation="4.363"></feGaussianBlur></filter><filter color-interpolation-filters="sRGB" filterUnits="userSpaceOnUse" height="35.276" id="lobe-icons-antigravity-7-_R_0_" width="35.978" x="-6.143" y="-21.659"><feFlood flood-opacity="0" result="BackgroundImageFix"></feFlood><feBlend in="SourceGraphic" in2="BackgroundImageFix" result="shape"></feBlend><feGaussianBlur result="effect1_foregroundBlur_977_115" stdDeviation="3.954"></feGaussianBlur></filter><filter color-interpolation-filters="sRGB" filterUnits="userSpaceOnUse" height="46.523" id="lobe-icons-antigravity-8-_R_0_" width="45.114" x="-11.96" y="-.46"><feFlood flood-opacity="0" result="BackgroundImageFix"></feFlood><feBlend in="SourceGraphic" in2="BackgroundImageFix" result="shape"></feBlend><feGaussianBlur result="effect1_foregroundBlur_977_115" stdDeviation="3.531"></feGaussianBlur></filter><filter color-interpolation-filters="sRGB" filterUnits="userSpaceOnUse" height="24.054" id="lobe-icons-antigravity-9-_R_0_" width="25.094" x="10.485" y=".58"><feFlood flood-opacity="0" result="BackgroundImageFix"></feFlood><feBlend in="SourceGraphic" in2="BackgroundImageFix" result="shape"></feBlend><feGaussianBlur result="effect1_foregroundBlur_977_115" stdDeviation="3.159"></feGaussianBlur></filter><filter color-interpolation-filters="sRGB" filterUnits="userSpaceOnUse" height="30.007" id="lobe-icons-antigravity-10-_R_0_" width="33.508" x="5.833" y="-12.467"><feFlood flood-opacity="0" result="BackgroundImageFix"></feFlood><feBlend in="SourceGraphic" in2="BackgroundImageFix" result="shape"></feBlend><feGaussianBlur result="effect1_foregroundBlur_977_115" stdDeviation="2.669"></feGaussianBlur></filter><filter color-interpolation-filters="sRGB" filterUnits="userSpaceOnUse" height="26.151" id="lobe-icons-antigravity-11-_R_0_" width="22.194" x="-8.355" y="-8.876"><feFlood flood-opacity="0" result="BackgroundImageFix"></feFlood><feBlend in="SourceGraphic" in2="BackgroundImageFix" result="shape"></feBlend><feGaussianBlur result="effect1_foregroundBlur_977_115" stdDeviation="3.303"></feGaussianBlur></filter></defs></svg>
@@ -1,3 +1 @@
1
- <svg width="100" height="100" viewBox="0 0 100 100" fill="none" xmlns="http://www.w3.org/2000/svg">
2
- <path d="M85.2843 88.0301C90.1329 91.6664 97.4057 89.2422 90.7389 82.5755C70.7389 63.1816 74.9813 9.84827 50.1329 9.84827C25.2843 9.84827 29.5267 63.1816 9.52673 82.5755C2.25402 89.8483 10.1328 91.6664 14.9813 88.0301C33.7692 75.3028 32.5571 52.8786 50.1329 52.8786C67.7086 52.8786 66.4965 75.3028 85.2843 88.0301Z" fill="currentColor"/>
3
- </svg>
1
+ <svg fill="currentColor" fill-rule="evenodd" height="1em" style="flex:none;line-height:1" viewBox="0 0 24 24" width="1em" xmlns="http://www.w3.org/2000/svg"><title>Antigravity</title><path d="M21.751 22.607c1.34 1.005 3.35.335 1.508-1.508C17.73 15.74 18.904 1 12.037 1 5.17 1 6.342 15.74.815 21.1c-2.01 2.009.167 2.511 1.507 1.506 5.192-3.517 4.857-9.714 9.715-9.714 4.857 0 4.522 6.197 9.714 9.715z"></path></svg>
@@ -82,7 +82,7 @@
82
82
  return null
83
83
  }
84
84
 
85
- function callLs(ctx, port, scheme, csrf, method, body) {
85
+ function callLs(ctx, port, scheme, csrf, method, body, timeoutMs) {
86
86
  var resp = ctx.host.http.request({
87
87
  method: "POST",
88
88
  url: scheme + "://127.0.0.1:" + port + "/" + LS_SERVICE + "/" + method,
@@ -92,7 +92,7 @@
92
92
  "x-codeium-csrf-token": csrf,
93
93
  },
94
94
  bodyText: JSON.stringify(body || {}),
95
- timeoutMs: 10000,
95
+ timeoutMs: timeoutMs || 10000,
96
96
  dangerouslyIgnoreTls: scheme === "https",
97
97
  })
98
98
  if (resp.status < 200 || resp.status >= 300) {
@@ -149,7 +149,8 @@
149
149
  var label = (typeof c.label === "string") ? c.label.trim() : ""
150
150
  if (!label) continue
151
151
  var qi = c.quotaInfo
152
- var frac = (qi && typeof qi.remainingFraction === "number") ? qi.remainingFraction : 0
152
+ if (!qi || !Number.isFinite(qi.remainingFraction)) continue
153
+ var frac = qi.remainingFraction
153
154
  var rtime = (qi && qi.resetTime) || undefined
154
155
  var pool = poolLabel(normalizeLabel(label))
155
156
  if (!deduped[pool] || frac < deduped[pool].remainingFraction) {
@@ -198,7 +199,13 @@
198
199
  locale: "en",
199
200
  }
200
201
 
201
- // Try GetUserStatus first, fall back to GetCommandModelConfigs
202
+ var summaryLines = []
203
+ try {
204
+ summaryLines = ctx.util.groupedQuotaLines(callLs(ctx, found.port, found.scheme, discovery.csrf,
205
+ "RetrieveUserQuotaSummary", { forceRefresh: true }, 2000))
206
+ } catch (_) {}
207
+
208
+ // GetUserStatus also supplies identity when grouped quota is available.
202
209
  var data = null
203
210
  try {
204
211
  data = callLs(ctx, found.port, found.scheme, discovery.csrf, "GetUserStatus", { metadata: metadata })
@@ -207,7 +214,7 @@
207
214
  }
208
215
  var hasUserStatus = data && data.userStatus
209
216
 
210
- if (!hasUserStatus) {
217
+ if (!hasUserStatus && !summaryLines.length) {
211
218
  ctx.host.log.warn("GetUserStatus failed, trying GetCommandModelConfigs")
212
219
  data = callLs(ctx, found.port, found.scheme, discovery.csrf, "GetCommandModelConfigs", { metadata: metadata })
213
220
  }
@@ -218,6 +225,8 @@
218
225
  configs = (data.userStatus.cascadeModelConfigData || {}).clientModelConfigs || []
219
226
  } else if (data && data.clientModelConfigs) {
220
227
  configs = data.clientModelConfigs
228
+ } else if (summaryLines.length) {
229
+ configs = []
221
230
  } else {
222
231
  throw "Start Antigravity IDE and try again."
223
232
  }
@@ -229,7 +238,7 @@
229
238
  filtered.push(configs[j])
230
239
  }
231
240
 
232
- var lines = buildModelLines(ctx, filtered)
241
+ var lines = summaryLines.length ? summaryLines : buildModelLines(ctx, filtered)
233
242
  if (lines.length === 0) throw "Start Antigravity IDE and try again."
234
243
 
235
244
  var plan = null
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Peter Steinberger
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1 @@
1
+ <svg fill="currentColor" fill-rule="evenodd" height="1em" style="flex:none;line-height:1" viewBox="0 0 24 24" width="1em" xmlns="http://www.w3.org/2000/svg"><title>Atlas Cloud</title><path d="M20.2,18.01L12,0.47,3.8,18.01l-2.58,5.52c1.62,-1.05,3.39,-1.86,5.26,-2.41,1.76,-0.51,3.61,-0.79,5.52,-0.79,0.98,0,1.95,0.08,2.9,0.22l-1.86,-4.3c-0.53,-0.1,-2.87,-0.1,-4.59,0.3l3.56,-8.28,5.52,12.85c0.01,0,0.02,0.01,0.03,0.01,1.86,0.55,3.62,1.36,5.23,2.4l-2.58,-5.52Z"></path></svg>
@@ -0,0 +1 @@
1
+ <svg fill="currentColor" fill-rule="evenodd" height="1em" style="flex:none;line-height:1" viewBox="0 0 24 24" width="1em" xmlns="http://www.w3.org/2000/svg"><title>Atlas Cloud</title><path d="M20.2,18.01L12,0.47,3.8,18.01l-2.58,5.52c1.62,-1.05,3.39,-1.86,5.26,-2.41,1.76,-0.51,3.61,-0.79,5.52,-0.79,0.98,0,1.95,0.08,2.9,0.22l-1.86,-4.3c-0.53,-0.1,-2.87,-0.1,-4.59,0.3l3.56,-8.28,5.52,12.85c0.01,0,0.02,0.01,0.03,0.01,1.86,0.55,3.62,1.36,5.23,2.4l-2.58,-5.52Z"></path></svg>