@expiren/opencode-antigravity-auth 1.6.17 → 1.6.18

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 (54) hide show
  1. package/dist/index.js +583 -59
  2. package/dist/index.js.map +4 -4
  3. package/dist/src/constants.d.ts +13 -0
  4. package/dist/src/constants.d.ts.map +1 -1
  5. package/dist/src/constants.js +19 -1
  6. package/dist/src/constants.js.map +1 -1
  7. package/dist/src/plugin/auth-doctor.d.ts +30 -0
  8. package/dist/src/plugin/auth-doctor.d.ts.map +1 -0
  9. package/dist/src/plugin/auth-doctor.js +144 -0
  10. package/dist/src/plugin/auth-doctor.js.map +1 -0
  11. package/dist/src/plugin/auth-drift.d.ts +13 -0
  12. package/dist/src/plugin/auth-drift.d.ts.map +1 -0
  13. package/dist/src/plugin/auth-drift.js +70 -0
  14. package/dist/src/plugin/auth-drift.js.map +1 -0
  15. package/dist/src/plugin/cli.d.ts +11 -2
  16. package/dist/src/plugin/cli.d.ts.map +1 -1
  17. package/dist/src/plugin/cli.js +31 -3
  18. package/dist/src/plugin/cli.js.map +1 -1
  19. package/dist/src/plugin/config/models.d.ts +2 -32
  20. package/dist/src/plugin/config/models.d.ts.map +1 -1
  21. package/dist/src/plugin/config/models.js +1 -113
  22. package/dist/src/plugin/config/models.js.map +1 -1
  23. package/dist/src/plugin/config/schema.js +2 -2
  24. package/dist/src/plugin/config/schema.js.map +1 -1
  25. package/dist/src/plugin/model-registry.d.ts +46 -0
  26. package/dist/src/plugin/model-registry.d.ts.map +1 -0
  27. package/dist/src/plugin/model-registry.js +180 -0
  28. package/dist/src/plugin/model-registry.js.map +1 -0
  29. package/dist/src/plugin/quota.d.ts +1 -0
  30. package/dist/src/plugin/quota.d.ts.map +1 -1
  31. package/dist/src/plugin/quota.js +8 -5
  32. package/dist/src/plugin/quota.js.map +1 -1
  33. package/dist/src/plugin/request.d.ts.map +1 -1
  34. package/dist/src/plugin/request.js +8 -5
  35. package/dist/src/plugin/request.js.map +1 -1
  36. package/dist/src/plugin/transform/model-resolver.d.ts.map +1 -1
  37. package/dist/src/plugin/transform/model-resolver.js +4 -26
  38. package/dist/src/plugin/transform/model-resolver.js.map +1 -1
  39. package/dist/src/plugin/ui/auth-menu.d.ts +25 -1
  40. package/dist/src/plugin/ui/auth-menu.d.ts.map +1 -1
  41. package/dist/src/plugin/ui/auth-menu.js +64 -13
  42. package/dist/src/plugin/ui/auth-menu.js.map +1 -1
  43. package/dist/src/plugin/ui/quota-status.d.ts +67 -0
  44. package/dist/src/plugin/ui/quota-status.d.ts.map +1 -0
  45. package/dist/src/plugin/ui/quota-status.js +194 -0
  46. package/dist/src/plugin/ui/quota-status.js.map +1 -0
  47. package/dist/src/plugin/version.d.ts +8 -1
  48. package/dist/src/plugin/version.d.ts.map +1 -1
  49. package/dist/src/plugin/version.js +8 -1
  50. package/dist/src/plugin/version.js.map +1 -1
  51. package/dist/src/plugin.d.ts.map +1 -1
  52. package/dist/src/plugin.js +66 -5
  53. package/dist/src/plugin.js.map +1 -1
  54. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -66,6 +66,14 @@ var ANTIGRAVITY_HEADERS = {
66
66
  "X-Goog-Api-Client": "google-cloud-sdk vscode_cloudshelleditor/0.1",
67
67
  "Client-Metadata": `{"ideType":"ANTIGRAVITY","platform":"${process.platform === "win32" ? "WINDOWS" : "MACOS"}","pluginType":"GEMINI"}`
68
68
  };
69
+ var GEMINI_CLI_VERSION = "1.0.0";
70
+ var GEMINI_CLI_DEFAULT_MODEL = "gemini-2.5-pro";
71
+ function buildGeminiCliUserAgent(model) {
72
+ const effectiveModel = model || GEMINI_CLI_DEFAULT_MODEL;
73
+ const platform = process.platform || "darwin";
74
+ const arch = process.arch || "arm64";
75
+ return `GeminiCLI/${GEMINI_CLI_VERSION}/${effectiveModel} (${platform}; ${arch})`;
76
+ }
69
77
  var GEMINI_CLI_HEADERS = {
70
78
  "User-Agent": "google-api-nodejs-client/9.15.1",
71
79
  "X-Goog-Api-Client": "gl-node/22.17.0",
@@ -83,7 +91,7 @@ function randomFrom(arr) {
83
91
  function getRandomizedHeaders(style, model) {
84
92
  if (style === "gemini-cli") {
85
93
  return {
86
- "User-Agent": GEMINI_CLI_HEADERS["User-Agent"],
94
+ "User-Agent": buildGeminiCliUserAgent(model),
87
95
  "X-Goog-Api-Client": GEMINI_CLI_HEADERS["X-Goog-Api-Client"],
88
96
  "Client-Metadata": GEMINI_CLI_HEADERS["Client-Metadata"]
89
97
  };
@@ -1574,6 +1582,129 @@ async function confirm(message, defaultYes = false) {
1574
1582
  return result ?? false;
1575
1583
  }
1576
1584
 
1585
+ // src/plugin/ui/quota-status.ts
1586
+ function formatWaitDuration(ms) {
1587
+ if (ms < 1e3) return `${ms}ms`;
1588
+ const seconds = Math.ceil(ms / 1e3);
1589
+ if (seconds < 60) return `${seconds}s`;
1590
+ const minutes = Math.floor(seconds / 60);
1591
+ const remainingSeconds = seconds % 60;
1592
+ if (minutes < 60) {
1593
+ return remainingSeconds > 0 ? `${minutes}m ${remainingSeconds}s` : `${minutes}m`;
1594
+ }
1595
+ const hours = Math.floor(minutes / 60);
1596
+ const remainingMinutes = minutes % 60;
1597
+ return remainingMinutes > 0 ? `${hours}h ${remainingMinutes}m` : `${hours}h`;
1598
+ }
1599
+ function classifyGroupStatus(group) {
1600
+ if (!group) {
1601
+ return { label: "READY" };
1602
+ }
1603
+ const remaining = group.remainingFraction;
1604
+ if (typeof remaining !== "number" || !Number.isFinite(remaining)) {
1605
+ return { label: "READY" };
1606
+ }
1607
+ if (remaining <= 0) {
1608
+ const waitMs = parseResetTimeToMs(group.resetTime);
1609
+ if (waitMs !== null && waitMs > 0) {
1610
+ return { label: "EXHAUSTED", waitMs };
1611
+ }
1612
+ return { label: "EXHAUSTED" };
1613
+ }
1614
+ if (remaining < 0.2) {
1615
+ return { label: "LOW" };
1616
+ }
1617
+ return { label: "READY" };
1618
+ }
1619
+ function parseResetTimeToMs(resetTime) {
1620
+ if (!resetTime) return null;
1621
+ const timestamp = Date.parse(resetTime);
1622
+ if (!Number.isFinite(timestamp)) return null;
1623
+ const ms = timestamp - Date.now();
1624
+ return ms > 0 ? ms : null;
1625
+ }
1626
+ function buildCooldownStatus(cooldownMs, reason) {
1627
+ return {
1628
+ label: "COOLDOWN",
1629
+ waitMs: cooldownMs > 0 ? cooldownMs : void 0,
1630
+ cooldownReason: reason
1631
+ };
1632
+ }
1633
+ function formatQuotaStatusBadge(status) {
1634
+ switch (status.label) {
1635
+ case "READY":
1636
+ return `${ANSI.green}[READY]${ANSI.reset}`;
1637
+ case "LOW":
1638
+ return `${ANSI.yellow}[LOW]${ANSI.reset}`;
1639
+ case "WAIT": {
1640
+ const suffix = status.waitMs ? ` ${formatWaitDuration(status.waitMs)}` : "";
1641
+ return `${ANSI.yellow}[WAIT${suffix}]${ANSI.reset}`;
1642
+ }
1643
+ case "EXHAUSTED": {
1644
+ const suffix = status.waitMs ? ` resets in ${formatWaitDuration(status.waitMs)}` : "";
1645
+ return `${ANSI.red}[EXHAUSTED${suffix}]${ANSI.reset}`;
1646
+ }
1647
+ case "COOLDOWN": {
1648
+ const parts = ["COOLDOWN"];
1649
+ if (status.cooldownReason) {
1650
+ parts.push(status.cooldownReason);
1651
+ }
1652
+ if (status.waitMs) {
1653
+ parts.push(formatWaitDuration(status.waitMs));
1654
+ }
1655
+ return `${ANSI.red}[${parts.join(" ")}]${ANSI.reset}`;
1656
+ }
1657
+ }
1658
+ }
1659
+ function formatQuotaStatusPlain(status) {
1660
+ switch (status.label) {
1661
+ case "READY":
1662
+ return "READY";
1663
+ case "LOW":
1664
+ return "LOW";
1665
+ case "WAIT": {
1666
+ const suffix = status.waitMs ? ` ${formatWaitDuration(status.waitMs)}` : "";
1667
+ return `WAIT${suffix}`;
1668
+ }
1669
+ case "EXHAUSTED": {
1670
+ const suffix = status.waitMs ? ` resets in ${formatWaitDuration(status.waitMs)}` : "";
1671
+ return `EXHAUSTED${suffix}`;
1672
+ }
1673
+ case "COOLDOWN": {
1674
+ const parts = ["COOLDOWN"];
1675
+ if (status.cooldownReason) {
1676
+ parts.push(status.cooldownReason);
1677
+ }
1678
+ if (status.waitMs) {
1679
+ parts.push(formatWaitDuration(status.waitMs));
1680
+ }
1681
+ return parts.join(" ");
1682
+ }
1683
+ }
1684
+ }
1685
+ function formatCachedQuotaWithStatus(cachedQuota) {
1686
+ if (!cachedQuota) {
1687
+ return void 0;
1688
+ }
1689
+ const entries = [
1690
+ { key: "claude", label: "Claude" },
1691
+ { key: "gemini-pro", label: "Gemini Pro" },
1692
+ { key: "gemini-flash", label: "Gemini Flash" }
1693
+ ].flatMap(({ key, label }) => {
1694
+ const value = cachedQuota[key]?.remainingFraction;
1695
+ if (typeof value !== "number" || !Number.isFinite(value)) {
1696
+ return [];
1697
+ }
1698
+ const pct = Math.round(Math.max(0, Math.min(1, value)) * 100);
1699
+ const status = classifyGroupStatus(cachedQuota[key]);
1700
+ if (status.label === "READY") {
1701
+ return [`${label} ${pct}%`];
1702
+ }
1703
+ return [`${label} ${formatQuotaStatusPlain(status)} ${pct}%`];
1704
+ });
1705
+ return entries.length > 0 ? entries.join(", ") : void 0;
1706
+ }
1707
+
1577
1708
  // src/plugin/ui/auth-menu.ts
1578
1709
  function formatRelativeTime(timestamp) {
1579
1710
  if (!timestamp) return "never";
@@ -1588,16 +1719,20 @@ function formatDate(timestamp) {
1588
1719
  if (!timestamp) return "unknown";
1589
1720
  return new Date(timestamp).toLocaleDateString();
1590
1721
  }
1591
- function getStatusBadge(status) {
1722
+ function getStatusBadge(status, account) {
1723
+ if (account?.cooldownMs !== void 0 && account.cooldownMs > 0) {
1724
+ const cooldownStatus = buildCooldownStatus(account.cooldownMs, account.cooldownReason);
1725
+ return ` ${formatQuotaStatusBadge(cooldownStatus)}`;
1726
+ }
1592
1727
  switch (status) {
1593
1728
  case "active":
1594
- return `${ANSI.green}[active]${ANSI.reset}`;
1729
+ return ` ${ANSI.green}[active]${ANSI.reset}`;
1595
1730
  case "rate-limited":
1596
- return `${ANSI.yellow}[rate-limited]${ANSI.reset}`;
1731
+ return ` ${ANSI.yellow}[rate-limited]${ANSI.reset}`;
1597
1732
  case "expired":
1598
- return `${ANSI.red}[expired]${ANSI.reset}`;
1733
+ return ` ${ANSI.red}[expired]${ANSI.reset}`;
1599
1734
  case "verification-required":
1600
- return `${ANSI.red}[needs verification]${ANSI.reset}`;
1735
+ return ` ${ANSI.red}[needs verification]${ANSI.reset}`;
1601
1736
  default:
1602
1737
  return "";
1603
1738
  }
@@ -1606,22 +1741,25 @@ async function showAuthMenu(accounts) {
1606
1741
  const items = [
1607
1742
  { label: "Actions", value: { type: "cancel" }, kind: "heading" },
1608
1743
  { label: "Add account", value: { type: "add" }, color: "cyan" },
1744
+ { label: "Auth current", value: { type: "current" }, color: "cyan" },
1609
1745
  { label: "Check quotas", value: { type: "check" }, color: "cyan" },
1746
+ { label: "Repair auth", value: { type: "repair" }, color: "yellow" },
1747
+ { label: "Auth doctor", value: { type: "doctor" }, color: "cyan" },
1610
1748
  { label: "Verify one account", value: { type: "verify" }, color: "cyan" },
1611
1749
  { label: "Verify all accounts", value: { type: "verify-all" }, color: "cyan" },
1612
1750
  { label: "Configure models in opencode.json", value: { type: "configure-models" }, color: "cyan" },
1613
1751
  { label: "", value: { type: "cancel" }, separator: true },
1614
1752
  { label: "Accounts", value: { type: "cancel" }, kind: "heading" },
1615
1753
  ...accounts.map((account) => {
1616
- const statusBadge = getStatusBadge(account.status);
1754
+ const statusBadge = getStatusBadge(account.status, account);
1617
1755
  const currentBadge = account.isCurrentAccount ? ` ${ANSI.cyan}[current]${ANSI.reset}` : "";
1618
1756
  const disabledBadge = account.enabled === false ? ` ${ANSI.red}[disabled]${ANSI.reset}` : "";
1619
1757
  const baseLabel = account.email || `Account ${account.index + 1}`;
1620
1758
  const numbered = `${account.index + 1}. ${baseLabel}`;
1621
- const fullLabel = `${numbered}${currentBadge}${statusBadge ? " " + statusBadge : ""}${disabledBadge}`;
1759
+ const fullLabel = `${numbered}${currentBadge}${statusBadge}${disabledBadge}`;
1622
1760
  return {
1623
1761
  label: fullLabel,
1624
- hint: account.lastUsed ? `used ${formatRelativeTime(account.lastUsed)}` : "",
1762
+ hint: account.quotaSummary ?? (account.lastUsed ? `used ${formatRelativeTime(account.lastUsed)}` : ""),
1625
1763
  value: { type: "select-account", account }
1626
1764
  };
1627
1765
  }),
@@ -1643,23 +1781,69 @@ async function showAuthMenu(accounts) {
1643
1781
  return result;
1644
1782
  }
1645
1783
  }
1784
+ function formatFingerprintReason(reason) {
1785
+ switch (reason) {
1786
+ case "initial":
1787
+ return "initial";
1788
+ case "regenerated":
1789
+ return "regenerated";
1790
+ case "restored":
1791
+ return "restored";
1792
+ }
1793
+ }
1794
+ async function showFingerprintHistory(history, accountLabel) {
1795
+ const items = [
1796
+ { label: "Back", value: null },
1797
+ { label: "", value: null, separator: true },
1798
+ { label: "Fingerprint history", value: null, kind: "heading" },
1799
+ ...history.map((entry, index) => {
1800
+ const deviceShort = entry.deviceId.slice(0, 8);
1801
+ const reasonBadge = `${ANSI.dim}[${formatFingerprintReason(entry.reason)}]${ANSI.reset}`;
1802
+ const label = `${index + 1}. ${deviceShort}... ${reasonBadge}`;
1803
+ const hint = formatRelativeTime(entry.timestamp);
1804
+ return {
1805
+ label,
1806
+ hint,
1807
+ value: index,
1808
+ color: "cyan"
1809
+ };
1810
+ })
1811
+ ];
1812
+ const result = await select(items, {
1813
+ message: `Restore fingerprint \u2014 ${accountLabel}`,
1814
+ subtitle: "Select a previous fingerprint to restore",
1815
+ clearScreen: true
1816
+ });
1817
+ return result ?? null;
1818
+ }
1646
1819
  async function showAccountDetails(account) {
1647
1820
  const label = account.email || `Account ${account.index + 1}`;
1648
- const badge = getStatusBadge(account.status);
1821
+ const badge = getStatusBadge(account.status, account);
1649
1822
  const disabledBadge = account.enabled === false ? ` ${ANSI.red}[disabled]${ANSI.reset}` : "";
1650
- const header = `${label}${badge ? " " + badge : ""}${disabledBadge}`;
1823
+ const header = `${label}${badge}${disabledBadge}`;
1651
1824
  const subtitleParts = [
1652
1825
  `Added: ${formatDate(account.addedAt)}`,
1653
1826
  `Last used: ${formatRelativeTime(account.lastUsed)}`
1654
1827
  ];
1828
+ const hasHistory = (account.fingerprintHistory?.length ?? 0) > 0;
1655
1829
  while (true) {
1656
- const result = await select([
1830
+ const menuItems = [
1657
1831
  { label: "Back", value: "back" },
1658
1832
  { label: "Verify account access", value: "verify", color: "cyan" },
1659
1833
  { label: account.enabled === false ? "Enable account" : "Disable account", value: "toggle", color: account.enabled === false ? "green" : "yellow" },
1660
- { label: "Refresh token", value: "refresh", color: "cyan" },
1834
+ { label: "Refresh token", value: "refresh", color: "cyan" }
1835
+ ];
1836
+ if (hasHistory) {
1837
+ menuItems.push({
1838
+ label: `Restore fingerprint (${account.fingerprintHistory.length} saved)`,
1839
+ value: "restore-fingerprint",
1840
+ color: "cyan"
1841
+ });
1842
+ }
1843
+ menuItems.push(
1661
1844
  { label: "Delete this account", value: "delete", color: "red" }
1662
- ], {
1845
+ );
1846
+ const result = await select(menuItems, {
1663
1847
  message: header,
1664
1848
  subtitle: subtitleParts.join(" | "),
1665
1849
  clearScreen: true
@@ -1681,12 +1865,14 @@ import { existsSync as existsSync2, readFileSync as readFileSync2, writeFileSync
1681
1865
  import { join as join3, dirname as dirname2 } from "node:path";
1682
1866
  import { homedir as homedir3 } from "node:os";
1683
1867
 
1684
- // src/plugin/config/models.ts
1868
+ // src/plugin/model-registry.ts
1685
1869
  var DEFAULT_MODALITIES = {
1686
1870
  input: ["text", "image", "pdf"],
1687
1871
  output: ["text"]
1688
1872
  };
1689
1873
  var MODEL_RELEASE_DATE = "";
1874
+ var DEFAULT_COST = { input: 0, output: 0 };
1875
+ var DEFAULT_OPTIONS = {};
1690
1876
  function defineModel(id, model) {
1691
1877
  return {
1692
1878
  id,
@@ -1694,10 +1880,12 @@ function defineModel(id, model) {
1694
1880
  attachment: model.modalities.input.some((modality) => modality !== "text"),
1695
1881
  temperature: true,
1696
1882
  tool_call: true,
1883
+ cost: { ...DEFAULT_COST },
1884
+ options: { ...DEFAULT_OPTIONS },
1697
1885
  ...model
1698
1886
  };
1699
1887
  }
1700
- var OPENCODE_MODEL_DEFINITIONS = {
1888
+ var PUBLIC_MODEL_DEFINITIONS = {
1701
1889
  "antigravity-gemini-3.1-pro": defineModel("antigravity-gemini-3.1-pro", {
1702
1890
  name: "Gemini 3.1 Pro (Antigravity)",
1703
1891
  reasoning: true,
@@ -1796,6 +1984,63 @@ var OPENCODE_MODEL_DEFINITIONS = {
1796
1984
  modalities: DEFAULT_MODALITIES
1797
1985
  })
1798
1986
  };
1987
+ var RESOLVER_ALIASES = {
1988
+ "gemini-3.1-pro-low": "gemini-3.1-pro",
1989
+ "gemini-3.1-pro-high": "gemini-3.1-pro",
1990
+ "gemini-3-flash-low": "gemini-3-flash",
1991
+ "gemini-3-flash-medium": "gemini-3-flash",
1992
+ "gemini-3-flash-high": "gemini-3-flash",
1993
+ "gemini-3.5-flash-low": "gemini-3.5-flash",
1994
+ "gemini-3.5-flash-medium": "gemini-3.5-flash",
1995
+ "gemini-3.5-flash-high": "gemini-3.5-flash",
1996
+ "gemini-claude-opus-4-6-thinking-low": "claude-opus-4-6-thinking",
1997
+ "gemini-claude-opus-4-6-thinking-medium": "claude-opus-4-6-thinking",
1998
+ "gemini-claude-opus-4-6-thinking-high": "claude-opus-4-6-thinking",
1999
+ "gemini-claude-sonnet-4-6-thinking-low": "claude-sonnet-4-6-thinking",
2000
+ "gemini-claude-sonnet-4-6-thinking-medium": "claude-sonnet-4-6-thinking",
2001
+ "gemini-claude-sonnet-4-6-thinking-high": "claude-sonnet-4-6-thinking",
2002
+ "gemini-claude-sonnet-4-6": "claude-sonnet-4-6-thinking"
2003
+ };
2004
+ var GEMINI_35_FLASH_ROUTES = {
2005
+ antigravity: {
2006
+ defaultModel: "gemini-3-flash-agent",
2007
+ byTier: {
2008
+ low: "gemini-3.5-flash-low",
2009
+ medium: "gemini-3.5-flash-low",
2010
+ high: "gemini-3-flash-agent"
2011
+ }
2012
+ },
2013
+ geminiCliFallbackModel: "gemini-3-flash-preview"
2014
+ };
2015
+ var QUOTA_GROUP_BY_MODEL_ID = {
2016
+ "claude-opus-4-6-thinking": "claude",
2017
+ "claude-opus-4-6": "claude",
2018
+ "claude-sonnet-4-6-thinking": "claude",
2019
+ "claude-sonnet-4-6": "claude",
2020
+ "gemini-pro-agent": "gemini-pro",
2021
+ "gemini-3.1-pro": "gemini-pro",
2022
+ "gemini-3.1-pro-low": "gemini-pro",
2023
+ "gemini-3.1-pro-high": "gemini-pro",
2024
+ "gemini-3-flash": "gemini-flash",
2025
+ "gemini-3-flash-agent": "gemini-flash",
2026
+ "gemini-3.5-flash-low": "gemini-flash"
2027
+ };
2028
+ var OPENCODE_MODEL_DEFINITIONS = PUBLIC_MODEL_DEFINITIONS;
2029
+ function getResolverAliasMap() {
2030
+ return RESOLVER_ALIASES;
2031
+ }
2032
+ function getGemini35FlashAntigravityModel(tier) {
2033
+ if (!tier) {
2034
+ return GEMINI_35_FLASH_ROUTES.antigravity.defaultModel;
2035
+ }
2036
+ return GEMINI_35_FLASH_ROUTES.antigravity.byTier[tier] ?? GEMINI_35_FLASH_ROUTES.antigravity.defaultModel;
2037
+ }
2038
+ function getGemini35FlashGeminiCliFallbackModel() {
2039
+ return GEMINI_35_FLASH_ROUTES.geminiCliFallbackModel;
2040
+ }
2041
+ function getQuotaGroupForModel(modelId) {
2042
+ return QUOTA_GROUP_BY_MODEL_ID[modelId.toLowerCase()];
2043
+ }
1799
2044
 
1800
2045
  // src/plugin/config/updater.ts
1801
2046
  var PLUGIN_NAME = "@expiren/opencode-antigravity-auth@latest";
@@ -1906,7 +2151,7 @@ ${existingAccounts.length} account(s) saved:`);
1906
2151
  }
1907
2152
  console.log("");
1908
2153
  while (true) {
1909
- const answer = await rl.question("(a)dd new, (f)resh start, (c)heck quotas, (v)erify account, (va) verify all? [a/f/c/v/va]: ");
2154
+ const answer = await rl.question("(a)dd new, (f)resh start, (c)heck quotas, auth (d)octor, (v)erify account, (va) verify all? [a/f/c/d/v/va]: ");
1910
2155
  const normalized = answer.trim().toLowerCase();
1911
2156
  if (normalized === "a" || normalized === "add") {
1912
2157
  return { mode: "add" };
@@ -1917,13 +2162,16 @@ ${existingAccounts.length} account(s) saved:`);
1917
2162
  if (normalized === "c" || normalized === "check") {
1918
2163
  return { mode: "check" };
1919
2164
  }
2165
+ if (normalized === "d" || normalized === "doctor" || normalized === "auth-doctor") {
2166
+ return { mode: "doctor" };
2167
+ }
1920
2168
  if (normalized === "v" || normalized === "verify") {
1921
2169
  return { mode: "verify" };
1922
2170
  }
1923
2171
  if (normalized === "va" || normalized === "verify-all" || normalized === "all") {
1924
2172
  return { mode: "verify-all", verifyAll: true };
1925
2173
  }
1926
- console.log("Please enter 'a', 'f', 'c', 'v', or 'va'.");
2174
+ console.log("Please enter 'a', 'f', 'c', 'd', 'v', or 'va'.");
1927
2175
  }
1928
2176
  } finally {
1929
2177
  rl.close();
@@ -1940,7 +2188,12 @@ async function promptLoginMode(existingAccounts) {
1940
2188
  lastUsed: acc.lastUsed,
1941
2189
  status: acc.status,
1942
2190
  isCurrentAccount: acc.isCurrentAccount,
1943
- enabled: acc.enabled
2191
+ enabled: acc.enabled,
2192
+ quotaSummary: acc.quotaSummary,
2193
+ cooldownMs: acc.cooldownMs,
2194
+ cooldownReason: acc.cooldownReason,
2195
+ cachedQuota: acc.cachedQuota,
2196
+ fingerprintHistory: acc.fingerprintHistory
1944
2197
  }));
1945
2198
  console.log("");
1946
2199
  while (true) {
@@ -1950,6 +2203,12 @@ async function promptLoginMode(existingAccounts) {
1950
2203
  return { mode: "add" };
1951
2204
  case "check":
1952
2205
  return { mode: "check" };
2206
+ case "doctor":
2207
+ return { mode: "doctor" };
2208
+ case "repair":
2209
+ return { mode: "repair" };
2210
+ case "current":
2211
+ return { mode: "current" };
1953
2212
  case "verify":
1954
2213
  return { mode: "verify" };
1955
2214
  case "verify-all":
@@ -1968,6 +2227,18 @@ async function promptLoginMode(existingAccounts) {
1968
2227
  if (accountAction === "verify") {
1969
2228
  return { mode: "verify", verifyAccountIndex: action.account.index };
1970
2229
  }
2230
+ if (accountAction === "restore-fingerprint") {
2231
+ const history = action.account.fingerprintHistory;
2232
+ if (!history || history.length === 0) continue;
2233
+ const accountLabel = action.account.email || `Account ${action.account.index + 1}`;
2234
+ const historyIndex = await showFingerprintHistory(history, accountLabel);
2235
+ if (historyIndex === null) continue;
2236
+ return {
2237
+ mode: "restore-fingerprint",
2238
+ restoreFingerprintAccountIndex: action.account.index,
2239
+ restoreFingerprintHistoryIndex: historyIndex
2240
+ };
2241
+ }
1971
2242
  continue;
1972
2243
  }
1973
2244
  case "delete-all":
@@ -2750,9 +3021,9 @@ var AntigravityConfigSchema = z2.object({
2750
3021
  * When false: Only shows toast notification, user must manually continue.
2751
3022
  * When true: Automatically sends "continue" to resume the session.
2752
3023
  *
2753
- * @default false
3024
+ * @default true
2754
3025
  */
2755
- auto_resume: z2.boolean().default(false),
3026
+ auto_resume: z2.boolean().default(true),
2756
3027
  /**
2757
3028
  * Custom text to send when auto-resuming after recovery.
2758
3029
  * Only used when auto_resume is enabled.
@@ -5762,31 +6033,7 @@ var THINKING_TIER_BUDGETS = {
5762
6033
  "gemini-2.5-flash": { low: 6144, medium: 12288, high: 24576 },
5763
6034
  default: { low: 4096, medium: 8192, high: 16384 }
5764
6035
  };
5765
- var MODEL_ALIASES = {
5766
- // Gemini 3.x variants - for Gemini CLI only (tier stripped, thinkingLevel used)
5767
- // For Antigravity, these are bypassed and full model name is kept
5768
- "gemini-3.1-pro-low": "gemini-3.1-pro",
5769
- "gemini-3.1-pro-high": "gemini-3.1-pro",
5770
- "gemini-3-flash-low": "gemini-3-flash",
5771
- "gemini-3-flash-medium": "gemini-3-flash",
5772
- "gemini-3-flash-high": "gemini-3-flash",
5773
- // Gemini 3.5 Flash variants
5774
- "gemini-3.5-flash-low": "gemini-3.5-flash",
5775
- "gemini-3.5-flash-medium": "gemini-3.5-flash",
5776
- "gemini-3.5-flash-high": "gemini-3.5-flash",
5777
- // Claude proxy names (gemini- prefix for compatibility)
5778
- "gemini-claude-opus-4-6-thinking-low": "claude-opus-4-6-thinking",
5779
- "gemini-claude-opus-4-6-thinking-medium": "claude-opus-4-6-thinking",
5780
- "gemini-claude-opus-4-6-thinking-high": "claude-opus-4-6-thinking",
5781
- "gemini-claude-sonnet-4-6-thinking-low": "claude-sonnet-4-6-thinking",
5782
- "gemini-claude-sonnet-4-6-thinking-medium": "claude-sonnet-4-6-thinking",
5783
- "gemini-claude-sonnet-4-6-thinking-high": "claude-sonnet-4-6-thinking",
5784
- "gemini-claude-sonnet-4-6": "claude-sonnet-4-6-thinking"
5785
- // Image generation models
5786
- // gemini-3.1-flash-image (Nano Banana 2) - available via Antigravity API and Gemini CLI
5787
- // gemini-2.5-flash-image (Nano Banana) - NOT supported by Antigravity, only Google AI API
5788
- // Reference: Antigravity-Manager/src-tauri/src/proxy/common/model_mapping.rs
5789
- };
6036
+ var MODEL_ALIASES = getResolverAliasMap();
5790
6037
  var TIER_REGEX = /-(minimal|low|medium|high)$/;
5791
6038
  var QUOTA_PREFIX_REGEX = /^antigravity-/i;
5792
6039
  var GEMINI_3_PRO_REGEX = /^gemini-3(?:\.\d+)?-pro/i;
@@ -5829,7 +6076,7 @@ function isGemini35FlashModel(model) {
5829
6076
  return /^gemini-3\.5-flash/i.test(model);
5830
6077
  }
5831
6078
  function resolveGemini35FlashAntigravityModel(tier) {
5832
- return tier === "low" || tier === "medium" ? "gemini-3.5-flash-low" : "gemini-3-flash-agent";
6079
+ return getGemini35FlashAntigravityModel(tier);
5833
6080
  }
5834
6081
  function resolveModelWithTier(requestedModel, options = {}) {
5835
6082
  const isAntigravity = QUOTA_PREFIX_REGEX.test(requestedModel);
@@ -5956,7 +6203,7 @@ function resolveModelForHeaderStyle(requestedModel, headerStyle) {
5956
6203
  const hasPreviewSuffix = /-preview($|-)/i.test(transformedModel);
5957
6204
  const isGemini35Flash = isGemini35FlashModel(transformedModel);
5958
6205
  if (isGemini35Flash) {
5959
- transformedModel = "gemini-3-flash-preview";
6206
+ transformedModel = getGemini35FlashGeminiCliFallbackModel();
5960
6207
  } else if (!hasPreviewSuffix) {
5961
6208
  transformedModel = `${transformedModel}-preview`;
5962
6209
  }
@@ -7539,9 +7786,10 @@ function prepareAntigravityRequest(input2, init, accessToken, projectId, endpoin
7539
7786
  const fingerprintHeaders = buildFingerprintHeaders(fingerprint);
7540
7787
  headers.set("User-Agent", fingerprintHeaders["User-Agent"] || selectedHeaders["User-Agent"]);
7541
7788
  } else {
7542
- headers.set("User-Agent", GEMINI_CLI_HEADERS["User-Agent"]);
7543
- headers.set("X-Goog-Api-Client", GEMINI_CLI_HEADERS["X-Goog-Api-Client"]);
7544
- headers.set("Client-Metadata", GEMINI_CLI_HEADERS["Client-Metadata"]);
7789
+ const geminiCliHeaders = getRandomizedHeaders("gemini-cli", requestedModel);
7790
+ headers.set("User-Agent", geminiCliHeaders["User-Agent"]);
7791
+ if (geminiCliHeaders["X-Goog-Api-Client"]) headers.set("X-Goog-Api-Client", geminiCliHeaders["X-Goog-Api-Client"]);
7792
+ if (geminiCliHeaders["Client-Metadata"]) headers.set("Client-Metadata", geminiCliHeaders["Client-Metadata"]);
7545
7793
  }
7546
7794
  return {
7547
7795
  request: transformedUrl,
@@ -9681,6 +9929,219 @@ async function showLocalDevToast(client, version) {
9681
9929
  logAutoUpdate(`Local dev toast shown: v${version}`);
9682
9930
  }
9683
9931
 
9932
+ // src/plugin/auth-drift.ts
9933
+ function isAccountEnabled(account) {
9934
+ return account.enabled !== false;
9935
+ }
9936
+ function selectRestorableAccount(storage) {
9937
+ if (!storage || storage.accounts.length === 0) {
9938
+ return void 0;
9939
+ }
9940
+ const activeAccount = storage.accounts[storage.activeIndex];
9941
+ if (activeAccount && isAccountEnabled(activeAccount)) {
9942
+ return activeAccount;
9943
+ }
9944
+ return storage.accounts.find(isAccountEnabled);
9945
+ }
9946
+ function buildAuthFromStoredAccount(account) {
9947
+ return {
9948
+ type: "oauth",
9949
+ refresh: formatRefreshParts({
9950
+ refreshToken: account.refreshToken,
9951
+ projectId: account.projectId,
9952
+ managedProjectId: account.managedProjectId
9953
+ }),
9954
+ access: "",
9955
+ expires: 0
9956
+ };
9957
+ }
9958
+ function detectAuthStorageDrift(auth, storage) {
9959
+ if (!storage || storage.accounts.length === 0) {
9960
+ return {
9961
+ status: "unavailable",
9962
+ reason: "no-account-storage"
9963
+ };
9964
+ }
9965
+ const restorableAccount = selectRestorableAccount(storage);
9966
+ if (!restorableAccount) {
9967
+ return {
9968
+ status: "unavailable",
9969
+ reason: "no-enabled-accounts"
9970
+ };
9971
+ }
9972
+ if (!auth) {
9973
+ return {
9974
+ status: "restorable",
9975
+ reason: "missing-opencode-auth",
9976
+ account: restorableAccount
9977
+ };
9978
+ }
9979
+ if (!isOAuthAuth(auth)) {
9980
+ return {
9981
+ status: "restorable",
9982
+ reason: "non-oauth-opencode-auth",
9983
+ account: restorableAccount
9984
+ };
9985
+ }
9986
+ const authRefreshToken = parseRefreshParts(auth.refresh).refreshToken;
9987
+ const matchedAccount = storage.accounts.find((account) => account.refreshToken === authRefreshToken);
9988
+ if (matchedAccount) {
9989
+ return {
9990
+ status: "healthy",
9991
+ reason: "auth-matches-storage",
9992
+ account: matchedAccount
9993
+ };
9994
+ }
9995
+ return {
9996
+ status: "drifted",
9997
+ reason: "refresh-token-not-in-storage",
9998
+ account: restorableAccount
9999
+ };
10000
+ }
10001
+
10002
+ // src/plugin/auth-doctor.ts
10003
+ function isEnabled(account) {
10004
+ return account.enabled !== false;
10005
+ }
10006
+ function statusFromFindings(findings) {
10007
+ if (findings.some((finding) => finding.repair && finding.severity === "error")) {
10008
+ return "repairable";
10009
+ }
10010
+ if (findings.some((finding) => finding.severity === "error")) {
10011
+ return "error";
10012
+ }
10013
+ if (findings.some((finding) => finding.severity === "warning")) {
10014
+ return "warning";
10015
+ }
10016
+ return "ok";
10017
+ }
10018
+ function summaryFromStatus(status) {
10019
+ switch (status) {
10020
+ case "ok":
10021
+ return "OpenCode auth and Antigravity account storage are in sync.";
10022
+ case "repairable":
10023
+ return "Auth drift detected. One or more safe repairs are available.";
10024
+ case "warning":
10025
+ return "Auth is usable, but one or more accounts need attention.";
10026
+ case "error":
10027
+ return "Auth state is not usable and no safe automatic repair is available.";
10028
+ }
10029
+ }
10030
+ function createAuthDoctorReport(input2) {
10031
+ const findings = [];
10032
+ const drift = detectAuthStorageDrift(input2.auth, input2.storage);
10033
+ switch (drift.reason) {
10034
+ case "auth-matches-storage":
10035
+ findings.push({
10036
+ code: "auth-matches-storage",
10037
+ severity: "info",
10038
+ message: "OpenCode OAuth refresh token exists in Antigravity account storage.",
10039
+ accountEmail: drift.account?.email
10040
+ });
10041
+ break;
10042
+ case "missing-opencode-auth":
10043
+ findings.push({
10044
+ code: "missing-opencode-auth",
10045
+ severity: "error",
10046
+ message: "OpenCode auth.json has no Google OAuth entry, but Antigravity account storage has a restorable account.",
10047
+ repair: "restore-opencode-auth",
10048
+ accountEmail: drift.account?.email
10049
+ });
10050
+ break;
10051
+ case "non-oauth-opencode-auth":
10052
+ findings.push({
10053
+ code: "non-oauth-opencode-auth",
10054
+ severity: "error",
10055
+ message: "OpenCode Google auth is not OAuth, but Antigravity account storage has a restorable OAuth account.",
10056
+ repair: "restore-opencode-auth",
10057
+ accountEmail: drift.account?.email
10058
+ });
10059
+ break;
10060
+ case "refresh-token-not-in-storage":
10061
+ findings.push({
10062
+ code: "refresh-token-not-in-storage",
10063
+ severity: "error",
10064
+ message: "OpenCode Google OAuth refresh token does not match any stored Antigravity account.",
10065
+ repair: "restore-opencode-auth",
10066
+ accountEmail: drift.account?.email
10067
+ });
10068
+ break;
10069
+ case "no-account-storage":
10070
+ findings.push({
10071
+ code: "no-account-storage",
10072
+ severity: "error",
10073
+ message: "No Antigravity account storage was found."
10074
+ });
10075
+ break;
10076
+ case "no-enabled-accounts":
10077
+ findings.push({
10078
+ code: "no-enabled-accounts",
10079
+ severity: "error",
10080
+ message: "Antigravity account storage exists, but all accounts are disabled."
10081
+ });
10082
+ break;
10083
+ }
10084
+ const storage = input2.storage;
10085
+ if (storage && storage.accounts.length > 0) {
10086
+ if (!Number.isInteger(storage.activeIndex) || storage.activeIndex < 0 || storage.activeIndex >= storage.accounts.length) {
10087
+ findings.push({
10088
+ code: "active-index-out-of-range",
10089
+ severity: "error",
10090
+ message: `Active account index ${storage.activeIndex} is outside the stored account range.`,
10091
+ repair: "clamp-active-index"
10092
+ });
10093
+ } else {
10094
+ const activeAccount = storage.accounts[storage.activeIndex];
10095
+ if (activeAccount && !isEnabled(activeAccount) && storage.accounts.some(isEnabled)) {
10096
+ findings.push({
10097
+ code: "active-account-disabled",
10098
+ severity: "error",
10099
+ message: "The active account is disabled while another enabled account is available.",
10100
+ repair: "select-enabled-account",
10101
+ accountEmail: activeAccount.email
10102
+ });
10103
+ }
10104
+ }
10105
+ for (const account of storage.accounts) {
10106
+ if (account.verificationRequired) {
10107
+ findings.push({
10108
+ code: "verification-required",
10109
+ severity: "warning",
10110
+ message: account.verificationRequiredReason ?? "Account requires Google verification before it can be used.",
10111
+ repair: "verify-account",
10112
+ accountEmail: account.email
10113
+ });
10114
+ }
10115
+ }
10116
+ }
10117
+ const status = statusFromFindings(findings);
10118
+ return {
10119
+ status,
10120
+ summary: summaryFromStatus(status),
10121
+ findings,
10122
+ runtime: input2.runtime
10123
+ };
10124
+ }
10125
+ function formatAuthDoctorReport(report) {
10126
+ const lines = [
10127
+ "Antigravity auth doctor",
10128
+ `Status: ${report.status}`,
10129
+ report.summary,
10130
+ ""
10131
+ ];
10132
+ if (report.runtime) {
10133
+ lines.push(`Antigravity version: ${report.runtime.antigravityVersion} (${report.runtime.antigravityVersionSource})`);
10134
+ lines.push("");
10135
+ }
10136
+ for (const finding of report.findings) {
10137
+ const repair = finding.repair ? ` | repair: ${finding.repair}` : "";
10138
+ const account = finding.accountEmail ? ` | account: ${finding.accountEmail}` : "";
10139
+ lines.push(`- [${finding.severity}] ${finding.code}${account}${repair}`);
10140
+ lines.push(` ${finding.message}`);
10141
+ }
10142
+ return lines.join("\n");
10143
+ }
10144
+
9684
10145
  // src/plugin/quota.ts
9685
10146
  var FETCH_TIMEOUT_MS2 = 1e4;
9686
10147
  function buildAuthFromAccount(account) {
@@ -9712,6 +10173,10 @@ function parseResetTime(resetTime) {
9712
10173
  return timestamp;
9713
10174
  }
9714
10175
  function classifyQuotaGroup(modelName, displayName) {
10176
+ const registryGroup = getQuotaGroupForModel(modelName);
10177
+ if (registryGroup) {
10178
+ return registryGroup;
10179
+ }
9715
10180
  const combined = `${modelName} ${displayName ?? ""}`.toLowerCase();
9716
10181
  if (combined.includes("claude")) {
9717
10182
  return "claude";
@@ -9796,9 +10261,7 @@ async function fetchAvailableModels(accessToken, projectId) {
9796
10261
  }
9797
10262
  async function fetchGeminiCliQuota(accessToken, projectId) {
9798
10263
  const endpoint = ANTIGRAVITY_ENDPOINT_PROD;
9799
- const platform = process.platform || "darwin";
9800
- const arch = process.arch || "arm64";
9801
- const geminiCliUserAgent = `GeminiCLI/1.0.0/gemini-2.5-pro (${platform}; ${arch})`;
10264
+ const geminiCliUserAgent = buildGeminiCliUserAgent();
9802
10265
  const body = projectId ? { project: projectId } : {};
9803
10266
  try {
9804
10267
  const response = await fetchWithTimeout2(`${endpoint}/v1internal:retrieveUserQuota`, {
@@ -10130,6 +10593,7 @@ var CHANGELOG_URL = "https://antigravity.google/changelog";
10130
10593
  var FETCH_TIMEOUT_MS3 = 5e3;
10131
10594
  var CHANGELOG_SCAN_CHARS = 5e3;
10132
10595
  var VERSION_REGEX = /\d+\.\d+\.\d+/;
10596
+ var lastResolution = null;
10133
10597
  function parseVersion(text) {
10134
10598
  const match = text.match(VERSION_REGEX);
10135
10599
  return match ? match[0] : null;
@@ -10149,6 +10613,9 @@ async function tryFetchVersion(url, maxChars) {
10149
10613
  clearTimeout(timeout);
10150
10614
  }
10151
10615
  }
10616
+ function getAntigravityVersionResolution() {
10617
+ return lastResolution ?? { version: getAntigravityVersion(), source: "fallback" };
10618
+ }
10152
10619
  async function initAntigravityVersion() {
10153
10620
  const log11 = createLogger("version");
10154
10621
  const fallback = getAntigravityVersion();
@@ -10165,7 +10632,8 @@ async function initAntigravityVersion() {
10165
10632
  source = "fallback";
10166
10633
  setAntigravityVersion(fallback);
10167
10634
  log11.info("version-fetch-failed", { fallback });
10168
- return;
10635
+ lastResolution = { version: fallback, source };
10636
+ return lastResolution;
10169
10637
  }
10170
10638
  }
10171
10639
  if (version !== fallback) {
@@ -10174,6 +10642,8 @@ async function initAntigravityVersion() {
10174
10642
  log11.debug("version-unchanged", { version, source });
10175
10643
  }
10176
10644
  setAntigravityVersion(version);
10645
+ lastResolution = { version, source };
10646
+ return lastResolution;
10177
10647
  }
10178
10648
 
10179
10649
  // src/plugin/search.ts
@@ -10966,6 +11436,13 @@ function buildAuthSuccessFromStoredAccount(account) {
10966
11436
  projectId: account.projectId ?? ""
10967
11437
  };
10968
11438
  }
11439
+ function formatCachedQuotaSummary(account) {
11440
+ const quota = account.cachedQuota;
11441
+ if (!quota) {
11442
+ return void 0;
11443
+ }
11444
+ return formatCachedQuotaWithStatus(quota);
11445
+ }
10969
11446
  function retryAfterMsFromResponse(response, defaultRetryMs = 6e4) {
10970
11447
  const retryAfterMsHeader = response.headers.get("retry-after-ms");
10971
11448
  if (retryAfterMsHeader) {
@@ -11317,7 +11794,33 @@ var createAntigravityPlugin = (providerId) => async ({ client, directory }) => {
11317
11794
  provider: providerId,
11318
11795
  loader: async (getAuth, provider) => {
11319
11796
  cachedGetAuth = getAuth;
11320
- const auth = await getAuth();
11797
+ let auth = await getAuth();
11798
+ if (!isOAuthAuth(auth)) {
11799
+ const storedAccounts2 = await loadAccounts();
11800
+ const drift = detectAuthStorageDrift(auth, storedAccounts2);
11801
+ if (drift.status === "restorable" && drift.account) {
11802
+ auth = buildAuthFromStoredAccount(drift.account);
11803
+ try {
11804
+ await client.auth.set({
11805
+ path: { id: providerId },
11806
+ body: {
11807
+ type: "oauth",
11808
+ refresh: auth.refresh,
11809
+ access: auth.access ?? "",
11810
+ expires: auth.expires ?? 0
11811
+ }
11812
+ });
11813
+ log10.info("Restored Antigravity OAuth auth from account storage", {
11814
+ reason: drift.reason,
11815
+ email: drift.account.email
11816
+ });
11817
+ } catch (storeError) {
11818
+ log10.warn("Failed to restore Antigravity OAuth auth from account storage", {
11819
+ error: String(storeError)
11820
+ });
11821
+ }
11822
+ }
11823
+ }
11321
11824
  if (!isOAuthAuth(auth)) {
11322
11825
  try {
11323
11826
  await clearAccounts();
@@ -12225,7 +12728,8 @@ Alternatively, you can:
12225
12728
  lastUsed: acc.lastUsed,
12226
12729
  status,
12227
12730
  isCurrentAccount: idx === (existingStorage2.activeIndex ?? 0),
12228
- enabled: acc.enabled !== false
12731
+ enabled: acc.enabled !== false,
12732
+ quotaSummary: formatCachedQuotaSummary(acc)
12229
12733
  };
12230
12734
  });
12231
12735
  menuResult = await promptLoginMode(existingAccounts);
@@ -12294,8 +12798,10 @@ Alternatively, you can:
12294
12798
  const connector = isLast ? "\u2514\u2500" : "\u251C\u2500";
12295
12799
  const bar = createProgressBar(model.remainingFraction);
12296
12800
  const reset = formatReset(model.resetTime);
12801
+ const status = classifyGroupStatus({ remainingFraction: model.remainingFraction, resetTime: model.resetTime, modelCount: 1 });
12802
+ const badge = formatQuotaStatusBadge(status);
12297
12803
  const modelName = model.modelId.padEnd(29);
12298
- console.log(` \u2502 ${connector} ${modelName} ${bar}${reset}`);
12804
+ console.log(` \u2502 ${connector} ${modelName} ${bar} ${badge}${reset}`);
12299
12805
  });
12300
12806
  }
12301
12807
  const hasAntigravity = res.quota && Object.keys(res.quota.groups).length > 0;
@@ -12316,8 +12822,10 @@ Alternatively, you can:
12316
12822
  const connector = isLast ? "\u2514\u2500" : "\u251C\u2500";
12317
12823
  const bar = createProgressBar(g.data.remainingFraction);
12318
12824
  const reset = formatReset(g.data.resetTime);
12825
+ const status = classifyGroupStatus(g.data);
12826
+ const badge = formatQuotaStatusBadge(status);
12319
12827
  const modelName = g.name.padEnd(29);
12320
- console.log(` ${connector} ${modelName} ${bar}${reset}`);
12828
+ console.log(` ${connector} ${modelName} ${bar} ${badge}${reset}`);
12321
12829
  });
12322
12830
  }
12323
12831
  console.log("");
@@ -12344,6 +12852,22 @@ Alternatively, you can:
12344
12852
  console.log("");
12345
12853
  continue;
12346
12854
  }
12855
+ if (menuResult.mode === "doctor") {
12856
+ const auth = cachedGetAuth ? await cachedGetAuth().catch(() => void 0) : void 0;
12857
+ const versionResolution = getAntigravityVersionResolution();
12858
+ const report = createAuthDoctorReport({
12859
+ auth,
12860
+ storage: existingStorage2,
12861
+ runtime: {
12862
+ antigravityVersion: versionResolution.version,
12863
+ antigravityVersionSource: versionResolution.source
12864
+ }
12865
+ });
12866
+ console.log(`
12867
+ ${formatAuthDoctorReport(report)}
12868
+ `);
12869
+ continue;
12870
+ }
12347
12871
  if (menuResult.mode === "manage") {
12348
12872
  if (menuResult.toggleAccountIndex !== void 0) {
12349
12873
  const acc = existingStorage2.accounts[menuResult.toggleAccountIndex];