@expiren/opencode-antigravity-auth 1.6.15 → 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 -68
  2. package/dist/index.js.map +7 -1
  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 -122
  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,
@@ -1789,15 +1977,6 @@ var OPENCODE_MODEL_DEFINITIONS = {
1789
1977
  output: ["text", "image"]
1790
1978
  }
1791
1979
  }),
1792
- "gemini-3-pro-image-preview": defineModel("gemini-3-pro-image-preview", {
1793
- name: "Gemini 3 Pro Image Preview (Gemini CLI)",
1794
- reasoning: false,
1795
- limit: { context: 66e3, output: 33e3 },
1796
- modalities: {
1797
- input: ["text", "image"],
1798
- output: ["text", "image"]
1799
- }
1800
- }),
1801
1980
  "gemini-3.1-pro-preview-customtools": defineModel("gemini-3.1-pro-preview-customtools", {
1802
1981
  name: "Gemini 3.1 Pro Preview Custom Tools (Gemini CLI)",
1803
1982
  reasoning: true,
@@ -1805,6 +1984,63 @@ var OPENCODE_MODEL_DEFINITIONS = {
1805
1984
  modalities: DEFAULT_MODALITIES
1806
1985
  })
1807
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
+ }
1808
2044
 
1809
2045
  // src/plugin/config/updater.ts
1810
2046
  var PLUGIN_NAME = "@expiren/opencode-antigravity-auth@latest";
@@ -1915,7 +2151,7 @@ ${existingAccounts.length} account(s) saved:`);
1915
2151
  }
1916
2152
  console.log("");
1917
2153
  while (true) {
1918
- 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]: ");
1919
2155
  const normalized = answer.trim().toLowerCase();
1920
2156
  if (normalized === "a" || normalized === "add") {
1921
2157
  return { mode: "add" };
@@ -1926,13 +2162,16 @@ ${existingAccounts.length} account(s) saved:`);
1926
2162
  if (normalized === "c" || normalized === "check") {
1927
2163
  return { mode: "check" };
1928
2164
  }
2165
+ if (normalized === "d" || normalized === "doctor" || normalized === "auth-doctor") {
2166
+ return { mode: "doctor" };
2167
+ }
1929
2168
  if (normalized === "v" || normalized === "verify") {
1930
2169
  return { mode: "verify" };
1931
2170
  }
1932
2171
  if (normalized === "va" || normalized === "verify-all" || normalized === "all") {
1933
2172
  return { mode: "verify-all", verifyAll: true };
1934
2173
  }
1935
- console.log("Please enter 'a', 'f', 'c', 'v', or 'va'.");
2174
+ console.log("Please enter 'a', 'f', 'c', 'd', 'v', or 'va'.");
1936
2175
  }
1937
2176
  } finally {
1938
2177
  rl.close();
@@ -1949,7 +2188,12 @@ async function promptLoginMode(existingAccounts) {
1949
2188
  lastUsed: acc.lastUsed,
1950
2189
  status: acc.status,
1951
2190
  isCurrentAccount: acc.isCurrentAccount,
1952
- 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
1953
2197
  }));
1954
2198
  console.log("");
1955
2199
  while (true) {
@@ -1959,6 +2203,12 @@ async function promptLoginMode(existingAccounts) {
1959
2203
  return { mode: "add" };
1960
2204
  case "check":
1961
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" };
1962
2212
  case "verify":
1963
2213
  return { mode: "verify" };
1964
2214
  case "verify-all":
@@ -1977,6 +2227,18 @@ async function promptLoginMode(existingAccounts) {
1977
2227
  if (accountAction === "verify") {
1978
2228
  return { mode: "verify", verifyAccountIndex: action.account.index };
1979
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
+ }
1980
2242
  continue;
1981
2243
  }
1982
2244
  case "delete-all":
@@ -2759,9 +3021,9 @@ var AntigravityConfigSchema = z2.object({
2759
3021
  * When false: Only shows toast notification, user must manually continue.
2760
3022
  * When true: Automatically sends "continue" to resume the session.
2761
3023
  *
2762
- * @default false
3024
+ * @default true
2763
3025
  */
2764
- auto_resume: z2.boolean().default(false),
3026
+ auto_resume: z2.boolean().default(true),
2765
3027
  /**
2766
3028
  * Custom text to send when auto-resuming after recovery.
2767
3029
  * Only used when auto_resume is enabled.
@@ -5771,31 +6033,7 @@ var THINKING_TIER_BUDGETS = {
5771
6033
  "gemini-2.5-flash": { low: 6144, medium: 12288, high: 24576 },
5772
6034
  default: { low: 4096, medium: 8192, high: 16384 }
5773
6035
  };
5774
- var MODEL_ALIASES = {
5775
- // Gemini 3.x variants - for Gemini CLI only (tier stripped, thinkingLevel used)
5776
- // For Antigravity, these are bypassed and full model name is kept
5777
- "gemini-3.1-pro-low": "gemini-3.1-pro",
5778
- "gemini-3.1-pro-high": "gemini-3.1-pro",
5779
- "gemini-3-flash-low": "gemini-3-flash",
5780
- "gemini-3-flash-medium": "gemini-3-flash",
5781
- "gemini-3-flash-high": "gemini-3-flash",
5782
- // Gemini 3.5 Flash variants
5783
- "gemini-3.5-flash-low": "gemini-3.5-flash",
5784
- "gemini-3.5-flash-medium": "gemini-3.5-flash",
5785
- "gemini-3.5-flash-high": "gemini-3.5-flash",
5786
- // Claude proxy names (gemini- prefix for compatibility)
5787
- "gemini-claude-opus-4-6-thinking-low": "claude-opus-4-6-thinking",
5788
- "gemini-claude-opus-4-6-thinking-medium": "claude-opus-4-6-thinking",
5789
- "gemini-claude-opus-4-6-thinking-high": "claude-opus-4-6-thinking",
5790
- "gemini-claude-sonnet-4-6-thinking-low": "claude-sonnet-4-6-thinking",
5791
- "gemini-claude-sonnet-4-6-thinking-medium": "claude-sonnet-4-6-thinking",
5792
- "gemini-claude-sonnet-4-6-thinking-high": "claude-sonnet-4-6-thinking",
5793
- "gemini-claude-sonnet-4-6": "claude-sonnet-4-6-thinking"
5794
- // Image generation models
5795
- // gemini-3.1-flash-image (Nano Banana 2) - available via Antigravity API and Gemini CLI
5796
- // gemini-2.5-flash-image (Nano Banana) - NOT supported by Antigravity, only Google AI API
5797
- // Reference: Antigravity-Manager/src-tauri/src/proxy/common/model_mapping.rs
5798
- };
6036
+ var MODEL_ALIASES = getResolverAliasMap();
5799
6037
  var TIER_REGEX = /-(minimal|low|medium|high)$/;
5800
6038
  var QUOTA_PREFIX_REGEX = /^antigravity-/i;
5801
6039
  var GEMINI_3_PRO_REGEX = /^gemini-3(?:\.\d+)?-pro/i;
@@ -5838,7 +6076,7 @@ function isGemini35FlashModel(model) {
5838
6076
  return /^gemini-3\.5-flash/i.test(model);
5839
6077
  }
5840
6078
  function resolveGemini35FlashAntigravityModel(tier) {
5841
- return tier === "low" || tier === "medium" ? "gemini-3.5-flash-low" : "gemini-3-flash-agent";
6079
+ return getGemini35FlashAntigravityModel(tier);
5842
6080
  }
5843
6081
  function resolveModelWithTier(requestedModel, options = {}) {
5844
6082
  const isAntigravity = QUOTA_PREFIX_REGEX.test(requestedModel);
@@ -5965,7 +6203,7 @@ function resolveModelForHeaderStyle(requestedModel, headerStyle) {
5965
6203
  const hasPreviewSuffix = /-preview($|-)/i.test(transformedModel);
5966
6204
  const isGemini35Flash = isGemini35FlashModel(transformedModel);
5967
6205
  if (isGemini35Flash) {
5968
- transformedModel = "gemini-3-flash-preview";
6206
+ transformedModel = getGemini35FlashGeminiCliFallbackModel();
5969
6207
  } else if (!hasPreviewSuffix) {
5970
6208
  transformedModel = `${transformedModel}-preview`;
5971
6209
  }
@@ -7548,9 +7786,10 @@ function prepareAntigravityRequest(input2, init, accessToken, projectId, endpoin
7548
7786
  const fingerprintHeaders = buildFingerprintHeaders(fingerprint);
7549
7787
  headers.set("User-Agent", fingerprintHeaders["User-Agent"] || selectedHeaders["User-Agent"]);
7550
7788
  } else {
7551
- headers.set("User-Agent", GEMINI_CLI_HEADERS["User-Agent"]);
7552
- headers.set("X-Goog-Api-Client", GEMINI_CLI_HEADERS["X-Goog-Api-Client"]);
7553
- 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"]);
7554
7793
  }
7555
7794
  return {
7556
7795
  request: transformedUrl,
@@ -9690,6 +9929,219 @@ async function showLocalDevToast(client, version) {
9690
9929
  logAutoUpdate(`Local dev toast shown: v${version}`);
9691
9930
  }
9692
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
+
9693
10145
  // src/plugin/quota.ts
9694
10146
  var FETCH_TIMEOUT_MS2 = 1e4;
9695
10147
  function buildAuthFromAccount(account) {
@@ -9721,6 +10173,10 @@ function parseResetTime(resetTime) {
9721
10173
  return timestamp;
9722
10174
  }
9723
10175
  function classifyQuotaGroup(modelName, displayName) {
10176
+ const registryGroup = getQuotaGroupForModel(modelName);
10177
+ if (registryGroup) {
10178
+ return registryGroup;
10179
+ }
9724
10180
  const combined = `${modelName} ${displayName ?? ""}`.toLowerCase();
9725
10181
  if (combined.includes("claude")) {
9726
10182
  return "claude";
@@ -9805,9 +10261,7 @@ async function fetchAvailableModels(accessToken, projectId) {
9805
10261
  }
9806
10262
  async function fetchGeminiCliQuota(accessToken, projectId) {
9807
10263
  const endpoint = ANTIGRAVITY_ENDPOINT_PROD;
9808
- const platform = process.platform || "darwin";
9809
- const arch = process.arch || "arm64";
9810
- const geminiCliUserAgent = `GeminiCLI/1.0.0/gemini-2.5-pro (${platform}; ${arch})`;
10264
+ const geminiCliUserAgent = buildGeminiCliUserAgent();
9811
10265
  const body = projectId ? { project: projectId } : {};
9812
10266
  try {
9813
10267
  const response = await fetchWithTimeout2(`${endpoint}/v1internal:retrieveUserQuota`, {
@@ -10139,6 +10593,7 @@ var CHANGELOG_URL = "https://antigravity.google/changelog";
10139
10593
  var FETCH_TIMEOUT_MS3 = 5e3;
10140
10594
  var CHANGELOG_SCAN_CHARS = 5e3;
10141
10595
  var VERSION_REGEX = /\d+\.\d+\.\d+/;
10596
+ var lastResolution = null;
10142
10597
  function parseVersion(text) {
10143
10598
  const match = text.match(VERSION_REGEX);
10144
10599
  return match ? match[0] : null;
@@ -10158,6 +10613,9 @@ async function tryFetchVersion(url, maxChars) {
10158
10613
  clearTimeout(timeout);
10159
10614
  }
10160
10615
  }
10616
+ function getAntigravityVersionResolution() {
10617
+ return lastResolution ?? { version: getAntigravityVersion(), source: "fallback" };
10618
+ }
10161
10619
  async function initAntigravityVersion() {
10162
10620
  const log11 = createLogger("version");
10163
10621
  const fallback = getAntigravityVersion();
@@ -10174,7 +10632,8 @@ async function initAntigravityVersion() {
10174
10632
  source = "fallback";
10175
10633
  setAntigravityVersion(fallback);
10176
10634
  log11.info("version-fetch-failed", { fallback });
10177
- return;
10635
+ lastResolution = { version: fallback, source };
10636
+ return lastResolution;
10178
10637
  }
10179
10638
  }
10180
10639
  if (version !== fallback) {
@@ -10183,6 +10642,8 @@ async function initAntigravityVersion() {
10183
10642
  log11.debug("version-unchanged", { version, source });
10184
10643
  }
10185
10644
  setAntigravityVersion(version);
10645
+ lastResolution = { version, source };
10646
+ return lastResolution;
10186
10647
  }
10187
10648
 
10188
10649
  // src/plugin/search.ts
@@ -10975,6 +11436,13 @@ function buildAuthSuccessFromStoredAccount(account) {
10975
11436
  projectId: account.projectId ?? ""
10976
11437
  };
10977
11438
  }
11439
+ function formatCachedQuotaSummary(account) {
11440
+ const quota = account.cachedQuota;
11441
+ if (!quota) {
11442
+ return void 0;
11443
+ }
11444
+ return formatCachedQuotaWithStatus(quota);
11445
+ }
10978
11446
  function retryAfterMsFromResponse(response, defaultRetryMs = 6e4) {
10979
11447
  const retryAfterMsHeader = response.headers.get("retry-after-ms");
10980
11448
  if (retryAfterMsHeader) {
@@ -11326,7 +11794,33 @@ var createAntigravityPlugin = (providerId) => async ({ client, directory }) => {
11326
11794
  provider: providerId,
11327
11795
  loader: async (getAuth, provider) => {
11328
11796
  cachedGetAuth = getAuth;
11329
- 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
+ }
11330
11824
  if (!isOAuthAuth(auth)) {
11331
11825
  try {
11332
11826
  await clearAccounts();
@@ -12234,7 +12728,8 @@ Alternatively, you can:
12234
12728
  lastUsed: acc.lastUsed,
12235
12729
  status,
12236
12730
  isCurrentAccount: idx === (existingStorage2.activeIndex ?? 0),
12237
- enabled: acc.enabled !== false
12731
+ enabled: acc.enabled !== false,
12732
+ quotaSummary: formatCachedQuotaSummary(acc)
12238
12733
  };
12239
12734
  });
12240
12735
  menuResult = await promptLoginMode(existingAccounts);
@@ -12303,8 +12798,10 @@ Alternatively, you can:
12303
12798
  const connector = isLast ? "\u2514\u2500" : "\u251C\u2500";
12304
12799
  const bar = createProgressBar(model.remainingFraction);
12305
12800
  const reset = formatReset(model.resetTime);
12801
+ const status = classifyGroupStatus({ remainingFraction: model.remainingFraction, resetTime: model.resetTime, modelCount: 1 });
12802
+ const badge = formatQuotaStatusBadge(status);
12306
12803
  const modelName = model.modelId.padEnd(29);
12307
- console.log(` \u2502 ${connector} ${modelName} ${bar}${reset}`);
12804
+ console.log(` \u2502 ${connector} ${modelName} ${bar} ${badge}${reset}`);
12308
12805
  });
12309
12806
  }
12310
12807
  const hasAntigravity = res.quota && Object.keys(res.quota.groups).length > 0;
@@ -12325,8 +12822,10 @@ Alternatively, you can:
12325
12822
  const connector = isLast ? "\u2514\u2500" : "\u251C\u2500";
12326
12823
  const bar = createProgressBar(g.data.remainingFraction);
12327
12824
  const reset = formatReset(g.data.resetTime);
12825
+ const status = classifyGroupStatus(g.data);
12826
+ const badge = formatQuotaStatusBadge(status);
12328
12827
  const modelName = g.name.padEnd(29);
12329
- console.log(` ${connector} ${modelName} ${bar}${reset}`);
12828
+ console.log(` ${connector} ${modelName} ${bar} ${badge}${reset}`);
12330
12829
  });
12331
12830
  }
12332
12831
  console.log("");
@@ -12353,6 +12852,22 @@ Alternatively, you can:
12353
12852
  console.log("");
12354
12853
  continue;
12355
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
+ }
12356
12871
  if (menuResult.mode === "manage") {
12357
12872
  if (menuResult.toggleAccountIndex !== void 0) {
12358
12873
  const acc = existingStorage2.accounts[menuResult.toggleAccountIndex];