@omnicross/daemon 0.4.2 → 0.4.3

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.
package/dist/index.cjs CHANGED
@@ -63,21 +63,23 @@ var import_node_path35 = require("path");
63
63
  var import_audit_types = require("@omnicross/contracts/audit-types");
64
64
  var import_billing_types = require("@omnicross/contracts/billing-types");
65
65
  var import_core7 = require("@omnicross/core");
66
- var import_GeminiCodeAssistProjectResolver2 = require("@omnicross/core/auth/GeminiCodeAssistProjectResolver");
66
+ var import_GeminiCodeAssistProjectResolver6 = require("@omnicross/core/auth/GeminiCodeAssistProjectResolver");
67
67
  var import_ApiKeyPoolService = require("@omnicross/core/completion/ApiKeyPoolService");
68
68
  var import_outbound_api10 = require("@omnicross/core/outbound-api");
69
69
  var import_subscriptionRegistryPort = require("@omnicross/core/outbound-api/subscriptionRegistryPort");
70
70
  var import_SubscriptionAccountHealth4 = require("@omnicross/core/pipeline/SubscriptionAccountHealth");
71
- var import_AccountAllowanceStore10 = require("@omnicross/core/pipeline/AccountAllowanceStore");
71
+ var import_AccountAllowanceStore11 = require("@omnicross/core/pipeline/AccountAllowanceStore");
72
72
  var import_AccountAllowanceScheduling5 = require("@omnicross/core/pipeline/AccountAllowanceScheduling");
73
- var import_upstreamFetch16 = require("@omnicross/core/pipeline/upstreamFetch");
73
+ var import_upstreamFetch18 = require("@omnicross/core/pipeline/upstreamFetch");
74
74
  var import_SubscriptionIdentityStore3 = require("@omnicross/core/provider-proxy/identity/SubscriptionIdentityStore");
75
75
  var import_gemini_code_assist_resolver = require("@omnicross/core/ports/gemini-code-assist-resolver");
76
+ var import_antigravityFailover = require("@omnicross/core/transformer/transformers/antigravityFailover");
77
+ var import_openCodeGoHeaders2 = require("@omnicross/core/provider-proxy/identity/openCodeGoHeaders");
76
78
  var import_provider_proxy4 = require("@omnicross/core/provider-proxy");
77
79
  var import_cli_launcher2 = require("@omnicross/cli-launcher");
78
80
  var import_outbound_api11 = require("@omnicross/core/outbound-api");
79
81
  var import_usage2 = require("@omnicross/core/usage");
80
- var import_subscriptions12 = require("@omnicross/subscriptions");
82
+ var import_subscriptions13 = require("@omnicross/subscriptions");
81
83
 
82
84
  // src/admin/accountsCodexOAuth.ts
83
85
  var import_node_crypto = __toESM(require("crypto"), 1);
@@ -439,7 +441,7 @@ function handleCopilotOAuthStatus(sessionId, deps) {
439
441
  }
440
442
 
441
443
  // src/allowance/AccountAllowanceService.ts
442
- var import_AccountAllowanceStore8 = require("@omnicross/core/pipeline/AccountAllowanceStore");
444
+ var import_AccountAllowanceStore9 = require("@omnicross/core/pipeline/AccountAllowanceStore");
443
445
  var import_AccountAllowanceScheduling = require("@omnicross/core/pipeline/AccountAllowanceScheduling");
444
446
 
445
447
  // src/allowance/ClaudeAllowanceCollector.ts
@@ -1809,9 +1811,321 @@ var GeminiAllowanceCollector = class {
1809
1811
  }
1810
1812
  };
1811
1813
 
1812
- // src/allowance/OpenCodeGoAllowanceCollector.ts
1814
+ // src/allowance/AntigravityAllowanceCollector.ts
1815
+ var import_GeminiCodeAssistProjectResolver2 = require("@omnicross/core/auth/GeminiCodeAssistProjectResolver");
1816
+ var import_antigravityQuotaFamily = require("@omnicross/core/pipeline/antigravityQuotaFamily");
1813
1817
  var import_AccountAllowanceStore7 = require("@omnicross/core/pipeline/AccountAllowanceStore");
1814
1818
  var import_upstreamFetch7 = require("@omnicross/core/pipeline/upstreamFetch");
1819
+ var import_antigravityIdentity = require("@omnicross/core/transformer/transformers/antigravityIdentity");
1820
+ var ANTIGRAVITY_ALLOWANCE_CACHE_MS = 5 * 6e4;
1821
+ var RETRIEVE_USER_QUOTA_SUMMARY_PATH = "/v1internal:retrieveUserQuotaSummary";
1822
+ var FETCH_AVAILABLE_MODELS_PATH = "/v1internal:fetchAvailableModels";
1823
+ var ANTIGRAVITY_DISCOVERY_DENYLIST = /* @__PURE__ */ new Set([
1824
+ "chat_20706",
1825
+ "chat_23310",
1826
+ "gemini-2.5-pro"
1827
+ ]);
1828
+ function isRecord5(value) {
1829
+ return !!value && typeof value === "object" && !Array.isArray(value);
1830
+ }
1831
+ function secondsUntil7(instant, now) {
1832
+ if (!instant) return void 0;
1833
+ return Math.max(0, Math.floor((Date.parse(instant) - now) / 1e3));
1834
+ }
1835
+ var WINDOW_LABELS = {
1836
+ "five-hour": "5 Hour",
1837
+ weekly: "Weekly",
1838
+ daily: "Daily"
1839
+ };
1840
+ function classifyWindowId(...sources) {
1841
+ for (const source of sources) {
1842
+ if (!source) continue;
1843
+ const text = source.toLowerCase();
1844
+ if (text.includes("week") || text.includes("7d") || /7[\s_-]*day/.test(text)) return "weekly";
1845
+ if (text.includes("5h") || text.includes("five hour") || /5[\s_-]*hour/.test(text)) return "five-hour";
1846
+ if (text.includes("day") || text.includes("daily") || text.includes("24h")) return "daily";
1847
+ }
1848
+ return void 0;
1849
+ }
1850
+ function inferWindowFromReset(resetsAt, now) {
1851
+ if (resetsAt !== void 0 && Date.parse(resetsAt) - now > 24 * 60 * 60 * 1e3) return "weekly";
1852
+ return "daily";
1853
+ }
1854
+ function clampFraction(value) {
1855
+ if (value === void 0 || !Number.isFinite(value)) return void 0;
1856
+ return Math.min(1, Math.max(0, value));
1857
+ }
1858
+ function usedPercentFromFraction(fraction) {
1859
+ const clamped = clampFraction(fraction);
1860
+ if (clamped === void 0) return null;
1861
+ return Math.round((1 - clamped) * 1e3) / 10;
1862
+ }
1863
+ function toResetsAt(resetTime) {
1864
+ if (!resetTime || !Number.isFinite(Date.parse(resetTime))) return void 0;
1865
+ return new Date(Date.parse(resetTime)).toISOString();
1866
+ }
1867
+ function parseAntigravityQuotaSummary(payload, now) {
1868
+ if (!isRecord5(payload)) return null;
1869
+ const groups = Array.isArray(payload["groups"]) ? payload["groups"] : [];
1870
+ const topBuckets = Array.isArray(payload["buckets"]) ? payload["buckets"] : [];
1871
+ const hasGrouped = groups.some((group) => Array.isArray(group.buckets) && group.buckets.length > 0);
1872
+ if (!hasGrouped && topBuckets.length === 0) return null;
1873
+ const windows = /* @__PURE__ */ new Map();
1874
+ const addBucket = (bucket, groupName) => {
1875
+ const families = (0, import_antigravityQuotaFamily.antigravityCounterFamiliesForBucketId)(bucket.bucketId, groupName);
1876
+ if (families.length === 0) return;
1877
+ const resetsAt = toResetsAt(bucket.resetTime);
1878
+ const windowId = classifyWindowId(bucket.window, bucket.displayName, bucket.bucketId) ?? (resetsAt !== void 0 ? inferWindowFromReset(resetsAt, now) : void 0);
1879
+ if (windowId === void 0) return;
1880
+ const usedPercent = usedPercentFromFraction(bucket.remainingFraction) ?? (bucket.disabled === true || bucket.resetTime ? bucket.disabled === true ? 100 : null : null);
1881
+ for (const family of families) {
1882
+ const id = `antigravity:${family}:${windowId}`;
1883
+ const candidate = {
1884
+ id,
1885
+ label: `${WINDOW_LABELS[windowId]} (${family})`,
1886
+ scope: "model-family",
1887
+ // The window carries the MODEL family (gemini/claude/gpt-oss) — the
1888
+ // scheduling gate compares it against the requested model's family.
1889
+ modelFamily: import_antigravityQuotaFamily.ANTIGRAVITY_COUNTER_TO_MODEL_FAMILY[family],
1890
+ usedPercent,
1891
+ ...resetsAt !== void 0 ? { resetsAt } : {},
1892
+ remainingSeconds: secondsUntil7(resetsAt, now),
1893
+ state: "fresh",
1894
+ ...bucket.disabled === true ? { disabled: true } : {}
1895
+ };
1896
+ const existing = windows.get(id);
1897
+ if (!existing || candidate.disabled === true || existing.disabled !== true && (candidate.usedPercent ?? -1) > (existing.usedPercent ?? -1)) {
1898
+ windows.set(id, candidate);
1899
+ }
1900
+ }
1901
+ };
1902
+ if (hasGrouped) {
1903
+ for (const group of groups) {
1904
+ for (const bucket of group.buckets ?? []) addBucket(bucket, group.displayName);
1905
+ }
1906
+ } else {
1907
+ for (const bucket of topBuckets) addBucket(bucket);
1908
+ }
1909
+ const result = [...windows.values()];
1910
+ return result.length > 0 ? result : null;
1911
+ }
1912
+ function legacyQuotaInfos(model) {
1913
+ const out = [];
1914
+ const source = {
1915
+ ...model.apiProvider ? { apiProvider: model.apiProvider } : {},
1916
+ ...model.modelProvider ? { modelProvider: model.modelProvider } : {}
1917
+ };
1918
+ const add = (value, windowDefault) => {
1919
+ if (!value) return;
1920
+ const list = Array.isArray(value) ? value : [value];
1921
+ for (const info of list) {
1922
+ out.push({ ...source, ...windowDefault ? { windowId: windowDefault } : {}, ...info });
1923
+ }
1924
+ };
1925
+ add(model.quotaInfo);
1926
+ add(model.quotaInfos);
1927
+ add(model.dailyQuotaInfo, "daily");
1928
+ add(model.dailyQuotaInfos, "daily");
1929
+ add(model.weeklyQuotaInfo, "weekly");
1930
+ add(model.weeklyQuotaInfos, "weekly");
1931
+ return out;
1932
+ }
1933
+ function legacyCounterFamily(info) {
1934
+ switch (info.modelProvider ?? info.apiProvider) {
1935
+ case "MODEL_PROVIDER_ANTHROPIC":
1936
+ case "API_PROVIDER_ANTHROPIC_VERTEX":
1937
+ return "anthropic";
1938
+ case "MODEL_PROVIDER_GOOGLE":
1939
+ case "API_PROVIDER_GOOGLE_GEMINI":
1940
+ return "google";
1941
+ case "MODEL_PROVIDER_OPENAI":
1942
+ case "API_PROVIDER_OPENAI_VERTEX":
1943
+ return "openai";
1944
+ default:
1945
+ return void 0;
1946
+ }
1947
+ }
1948
+ function parseAntigravityLegacyQuota(payload, now) {
1949
+ if (!isRecord5(payload)) return null;
1950
+ const models = payload["models"];
1951
+ if (!isRecord5(models)) return null;
1952
+ const windows = /* @__PURE__ */ new Map();
1953
+ for (const info of Object.values(models).flatMap(legacyQuotaInfos)) {
1954
+ const family = legacyCounterFamily(info);
1955
+ if (!family) continue;
1956
+ const resetsAt = toResetsAt(info.resetTime);
1957
+ const windowId = classifyWindowId(info.windowId, info.windowLabel) ?? (resetsAt !== void 0 ? inferWindowFromReset(resetsAt, now) : void 0);
1958
+ if (windowId === void 0) continue;
1959
+ const id = `antigravity:${family}:${windowId}`;
1960
+ const candidate = {
1961
+ id,
1962
+ label: `${WINDOW_LABELS[windowId]} (${family})`,
1963
+ scope: "model-family",
1964
+ modelFamily: import_antigravityQuotaFamily.ANTIGRAVITY_COUNTER_TO_MODEL_FAMILY[family],
1965
+ usedPercent: usedPercentFromFraction(info.remainingFraction),
1966
+ ...resetsAt !== void 0 ? { resetsAt } : {},
1967
+ remainingSeconds: secondsUntil7(resetsAt, now),
1968
+ state: "fresh"
1969
+ };
1970
+ const existing = windows.get(id);
1971
+ if (!existing || (candidate.usedPercent ?? -1) > (existing.usedPercent ?? -1)) {
1972
+ windows.set(id, candidate);
1973
+ }
1974
+ }
1975
+ const result = [...windows.values()];
1976
+ return result.length > 0 ? result : null;
1977
+ }
1978
+ var AntigravityAllowanceCollector = class {
1979
+ constructor(credentials, store = (0, import_AccountAllowanceStore7.getSharedAccountAllowanceStore)(), fetchImpl = (url, init, accountId) => (0, import_upstreamFetch7.fetchUpstream)(url, init, { providerId: "antigravity", accountId, redactBodies: true }), now = Date.now) {
1980
+ this.credentials = credentials;
1981
+ this.store = store;
1982
+ this.fetchImpl = fetchImpl;
1983
+ this.now = now;
1984
+ }
1985
+ credentials;
1986
+ store;
1987
+ fetchImpl;
1988
+ now;
1989
+ inFlight = /* @__PURE__ */ new Map();
1990
+ async collectMany(accounts, options = {}) {
1991
+ const settled = await Promise.allSettled(
1992
+ accounts.map((account) => this.collect(account, options))
1993
+ );
1994
+ return settled.flatMap((result) => result.status === "fulfilled" ? [result.value] : []);
1995
+ }
1996
+ collect(account, options = {}) {
1997
+ const now = this.now();
1998
+ if (account.tokens.authMethod !== "oauth") {
1999
+ const existing = this.store.get("antigravity", account.id, now);
2000
+ if (existing?.windows.every((window) => window.state === "unsupported")) {
2001
+ return Promise.resolve(existing);
2002
+ }
2003
+ const snapshot = this.unsupportedSnapshot(account.id, now);
2004
+ this.store.set(snapshot);
2005
+ return Promise.resolve(snapshot);
2006
+ }
2007
+ const cached = this.store.get("antigravity", account.id, now);
2008
+ if (!options.force && cached && this.isCacheValid(cached, now, options.refreshAheadMs)) {
2009
+ return Promise.resolve(cached);
2010
+ }
2011
+ const running = this.inFlight.get(account.id);
2012
+ if (running) return running;
2013
+ const promise = this.fetchAccount(account.id).catch(() => this.failureSnapshot(account.id, "antigravity_usage_request_failed", this.now())).finally(() => this.inFlight.delete(account.id));
2014
+ this.inFlight.set(account.id, promise);
2015
+ return promise;
2016
+ }
2017
+ isCacheValid(snapshot, now, refreshAheadMs) {
2018
+ if (snapshot.windows.every((window) => window.state === "unsupported")) return true;
2019
+ const expiresAt = snapshot.expiresAt ? Date.parse(snapshot.expiresAt) : 0;
2020
+ const ahead = typeof refreshAheadMs === "number" && Number.isFinite(refreshAheadMs) ? Math.max(0, refreshAheadMs) : 0;
2021
+ return Number.isFinite(expiresAt) && expiresAt > now + ahead;
2022
+ }
2023
+ async fetchAccount(accountId) {
2024
+ let accessToken = await this.credentials.getAccessTokenForAccount("antigravity", accountId);
2025
+ if (!accessToken) return this.failureSnapshot(accountId, "antigravity_usage_token_unavailable", this.now());
2026
+ let response = await this.request(accountId, accessToken, RETRIEVE_USER_QUOTA_SUMMARY_PATH, {
2027
+ project: void 0
2028
+ });
2029
+ if (response.status === 401 || response.status === 403) {
2030
+ const refreshed = await this.credentials.refreshAccountToken("antigravity", accountId);
2031
+ if (!refreshed) return this.failureSnapshot(accountId, "antigravity_usage_unauthorized", this.now());
2032
+ accessToken = await this.credentials.getAccessTokenForAccount("antigravity", accountId);
2033
+ if (!accessToken) return this.failureSnapshot(accountId, "antigravity_usage_token_unavailable", this.now());
2034
+ response = await this.request(accountId, accessToken, RETRIEVE_USER_QUOTA_SUMMARY_PATH, {
2035
+ project: void 0
2036
+ });
2037
+ if (response.status === 401 || response.status === 403) {
2038
+ return this.failureSnapshot(accountId, "antigravity_usage_unauthorized", this.now());
2039
+ }
2040
+ }
2041
+ if (response.ok) {
2042
+ const payload = await response.json().catch(() => null);
2043
+ const windows = parseAntigravityQuotaSummary(payload, this.now());
2044
+ if (windows) {
2045
+ const snapshot2 = this.snapshot(accountId, windows);
2046
+ this.store.set(snapshot2);
2047
+ return snapshot2;
2048
+ }
2049
+ }
2050
+ const legacy = await this.request(accountId, accessToken, FETCH_AVAILABLE_MODELS_PATH, {});
2051
+ if (!legacy.ok) {
2052
+ return this.failureSnapshot(accountId, "antigravity_usage_http_error", this.now());
2053
+ }
2054
+ const legacyPayload = await legacy.json().catch(() => null);
2055
+ const legacyWindows = parseAntigravityLegacyQuota(legacyPayload, this.now());
2056
+ if (!legacyWindows) {
2057
+ return this.failureSnapshot(accountId, "antigravity_usage_invalid_response", this.now());
2058
+ }
2059
+ const snapshot = this.snapshot(accountId, legacyWindows);
2060
+ this.store.set(snapshot);
2061
+ return snapshot;
2062
+ }
2063
+ /** One upstream round-trip with the antigravity/hub masquerade UA. */
2064
+ request(accountId, accessToken, path2, body) {
2065
+ return this.fetchImpl(`${import_GeminiCodeAssistProjectResolver2.ANTIGRAVITY_CODE_ASSIST_ENDPOINT}${path2}`, {
2066
+ method: "POST",
2067
+ headers: {
2068
+ Authorization: `Bearer ${accessToken}`,
2069
+ Accept: "application/json",
2070
+ "Content-Type": "application/json",
2071
+ "User-Agent": (0, import_antigravityIdentity.getAntigravityUserAgent)()
2072
+ },
2073
+ body: JSON.stringify(body),
2074
+ signal: AbortSignal.timeout(15e3)
2075
+ }, accountId);
2076
+ }
2077
+ snapshot(accountId, windows, now = this.now()) {
2078
+ return {
2079
+ providerId: "antigravity",
2080
+ accountId,
2081
+ source: "oauth-usage-api",
2082
+ observedAt: new Date(now).toISOString(),
2083
+ expiresAt: new Date(now + ANTIGRAVITY_ALLOWANCE_CACHE_MS).toISOString(),
2084
+ windows
2085
+ };
2086
+ }
2087
+ failureSnapshot(accountId, code, now) {
2088
+ const existing = this.store.get("antigravity", accountId, now);
2089
+ const snapshot = existing ? {
2090
+ ...existing,
2091
+ expiresAt: new Date(now + ANTIGRAVITY_ALLOWANCE_CACHE_MS).toISOString(),
2092
+ windows: existing.windows.map((window) => ({
2093
+ ...window,
2094
+ state: window.state === "unsupported" ? "unsupported" : window.usedPercent !== null || window.resetsAt || window.disabled ? "stale" : "unavailable"
2095
+ })),
2096
+ lastErrorCode: code
2097
+ } : {
2098
+ providerId: "antigravity",
2099
+ accountId,
2100
+ source: "oauth-usage-api",
2101
+ observedAt: new Date(now).toISOString(),
2102
+ expiresAt: new Date(now + ANTIGRAVITY_ALLOWANCE_CACHE_MS).toISOString(),
2103
+ windows: [
2104
+ { id: "antigravity-quota", label: "Antigravity quota", scope: "all", usedPercent: null, state: "unavailable" }
2105
+ ],
2106
+ lastErrorCode: code
2107
+ };
2108
+ this.store.set(snapshot);
2109
+ return snapshot;
2110
+ }
2111
+ unsupportedSnapshot(accountId, now) {
2112
+ return {
2113
+ providerId: "antigravity",
2114
+ accountId,
2115
+ source: "oauth-usage-api",
2116
+ observedAt: new Date(now).toISOString(),
2117
+ windows: [
2118
+ { id: "antigravity-quota", label: "Antigravity quota", scope: "all", usedPercent: null, state: "unsupported" }
2119
+ ],
2120
+ lastErrorCode: "antigravity_usage_unsupported_auth"
2121
+ };
2122
+ }
2123
+ };
2124
+
2125
+ // src/allowance/OpenCodeGoAllowanceCollector.ts
2126
+ var import_AccountAllowanceStore8 = require("@omnicross/core/pipeline/AccountAllowanceStore");
2127
+ var import_upstreamFetch8 = require("@omnicross/core/pipeline/upstreamFetch");
2128
+ var import_openCodeGoHeaders = require("@omnicross/core/provider-proxy/identity/openCodeGoHeaders");
1815
2129
  var import_subscriptions7 = require("@omnicross/subscriptions");
1816
2130
  var OPENCODEGO_ALLOWANCE_CACHE_MS = 5 * 6e4;
1817
2131
  var OPENCODEGO_DEFAULT_GO_BASE = "https://opencode.ai/zen/go";
@@ -1825,7 +2139,7 @@ function isoInstant2(value) {
1825
2139
  const time = Date.parse(value);
1826
2140
  return Number.isFinite(time) ? new Date(time).toISOString() : void 0;
1827
2141
  }
1828
- function secondsUntil7(instant, now) {
2142
+ function secondsUntil8(instant, now) {
1829
2143
  if (!instant) return void 0;
1830
2144
  return Math.max(0, Math.floor((Date.parse(instant) - now) / 1e3));
1831
2145
  }
@@ -1840,12 +2154,12 @@ function windowFromPayload3(id, label, minutes, payload, now) {
1840
2154
  usedPercent,
1841
2155
  windowMinutes: minutes,
1842
2156
  ...resetsAt !== void 0 ? { resetsAt } : {},
1843
- remainingSeconds: secondsUntil7(resetsAt, now),
2157
+ remainingSeconds: secondsUntil8(resetsAt, now),
1844
2158
  state: usedPercent !== null || resetsAt ? "fresh" : "unavailable"
1845
2159
  };
1846
2160
  }
1847
2161
  var OpenCodeGoAllowanceCollector = class {
1848
- constructor(credentials, store = (0, import_AccountAllowanceStore7.getSharedAccountAllowanceStore)(), fetchImpl = (url, init, accountId) => (0, import_upstreamFetch7.fetchUpstream)(url, init, { providerId: "opencodego", accountId, redactBodies: true }), now = Date.now) {
2162
+ constructor(credentials, store = (0, import_AccountAllowanceStore8.getSharedAccountAllowanceStore)(), fetchImpl = (url, init, accountId) => (0, import_upstreamFetch8.fetchUpstream)(url, init, { providerId: "opencodego", accountId, redactBodies: true }), now = Date.now) {
1849
2163
  this.credentials = credentials;
1850
2164
  this.store = store;
1851
2165
  this.fetchImpl = fetchImpl;
@@ -1878,7 +2192,14 @@ var OpenCodeGoAllowanceCollector = class {
1878
2192
  const base = account.tokens.baseUrl ? (0, import_subscriptions7.normalizeOpenCodeGoBaseUrl)(account.tokens.baseUrl) : OPENCODEGO_DEFAULT_GO_BASE;
1879
2193
  const response = await this.fetchImpl(`${base}/v1/usage`, {
1880
2194
  method: "GET",
1881
- headers: { Authorization: `Bearer ${apiKey}`, Accept: "application/json" },
2195
+ // opencodego-egress-identity: the background poll identifies itself with
2196
+ // the same configured/default UA the relay carries (no session header —
2197
+ // a poll has no conversation).
2198
+ headers: {
2199
+ Authorization: `Bearer ${apiKey}`,
2200
+ Accept: "application/json",
2201
+ "User-Agent": (0, import_openCodeGoHeaders.getOpenCodeGoUserAgent)()
2202
+ },
1882
2203
  signal: AbortSignal.timeout(15e3)
1883
2204
  }, account.id);
1884
2205
  if (response.status === 401 || response.status === 403) {
@@ -1950,7 +2271,7 @@ function codexUnavailable(accountId, now) {
1950
2271
  };
1951
2272
  }
1952
2273
  var AccountAllowanceService = class {
1953
- constructor(credentials, store = (0, import_AccountAllowanceStore8.getSharedAccountAllowanceStore)(), collector, codexCollector, kimiCollector, opencodegoCollector, grokCollector, copilotCollector, geminiCollector, now = Date.now) {
2274
+ constructor(credentials, store = (0, import_AccountAllowanceStore9.getSharedAccountAllowanceStore)(), collector, codexCollector, kimiCollector, opencodegoCollector, grokCollector, copilotCollector, geminiCollector, antigravityCollector, now = Date.now) {
1954
2275
  this.credentials = credentials;
1955
2276
  this.store = store;
1956
2277
  this.now = now;
@@ -1961,6 +2282,7 @@ var AccountAllowanceService = class {
1961
2282
  this.grokCollector = grokCollector ?? new GrokAllowanceCollector(credentials, store);
1962
2283
  this.copilotCollector = copilotCollector ?? new CopilotAllowanceCollector(credentials, store);
1963
2284
  this.geminiCollector = geminiCollector ?? new GeminiAllowanceCollector(credentials, store);
2285
+ this.antigravityCollector = antigravityCollector ?? new AntigravityAllowanceCollector(credentials, store);
1964
2286
  }
1965
2287
  credentials;
1966
2288
  store;
@@ -1972,6 +2294,7 @@ var AccountAllowanceService = class {
1972
2294
  copilotCollector;
1973
2295
  opencodegoCollector;
1974
2296
  geminiCollector;
2297
+ antigravityCollector;
1975
2298
  /**
1976
2299
  * Read all/filtered snapshots. Claude's and Codex's five-minute caches are
1977
2300
  * refreshed lazily on read (Codex polls `/backend-api/wham/usage`; the
@@ -2020,6 +2343,11 @@ var AccountAllowanceService = class {
2020
2343
  (account) => !filter.accountId || account.id === filter.accountId
2021
2344
  );
2022
2345
  if (wantsGemini) await this.geminiCollector.collectMany(geminiAccounts);
2346
+ const wantsAntigravity = !filter.providerId || filter.providerId === "antigravity";
2347
+ const antigravityAccounts = (config.antigravityAccounts ?? []).filter(
2348
+ (account) => !filter.accountId || account.id === filter.accountId
2349
+ );
2350
+ if (wantsAntigravity) await this.antigravityCollector.collectMany(antigravityAccounts);
2023
2351
  const known = /* @__PURE__ */ new Set();
2024
2352
  if (wantsClaude) for (const account of claudeAccounts) known.add(`claude\0${account.id}`);
2025
2353
  if (wantsCodex) for (const account of codexAccounts) known.add(`codex\0${account.id}`);
@@ -2028,6 +2356,7 @@ var AccountAllowanceService = class {
2028
2356
  if (wantsGrok) for (const account of grokAccounts) known.add(`grok\0${account.id}`);
2029
2357
  if (wantsCopilot) for (const account of copilotAccounts) known.add(`copilot\0${account.id}`);
2030
2358
  if (wantsGemini) for (const account of geminiAccounts) known.add(`gemini\0${account.id}`);
2359
+ if (wantsAntigravity) for (const account of antigravityAccounts) known.add(`antigravity\0${account.id}`);
2031
2360
  return this.store.list(filter).filter((snapshot) => known.has(`${snapshot.providerId}\0${snapshot.accountId}`));
2032
2361
  }
2033
2362
  knownAccounts(config) {
@@ -2038,7 +2367,8 @@ var AccountAllowanceService = class {
2038
2367
  ...(config.opencodegoAccounts ?? []).map((account) => ({ providerId: "opencodego", accountId: account.id })),
2039
2368
  ...(config.grokAccounts ?? []).map((account) => ({ providerId: "grok", accountId: account.id })),
2040
2369
  ...(config.copilotAccounts ?? []).map((account) => ({ providerId: "copilot", accountId: account.id })),
2041
- ...(config.geminiAccounts ?? []).map((account) => ({ providerId: "gemini", accountId: account.id }))
2370
+ ...(config.geminiAccounts ?? []).map((account) => ({ providerId: "gemini", accountId: account.id })),
2371
+ ...(config.antigravityAccounts ?? []).map((account) => ({ providerId: "antigravity", accountId: account.id }))
2042
2372
  ];
2043
2373
  }
2044
2374
  /** Force-refresh Claude usage for one account or every stored Claude account. */
@@ -2108,6 +2438,15 @@ var AccountAllowanceService = class {
2108
2438
  );
2109
2439
  return this.geminiCollector.collectMany(accounts, { force: true });
2110
2440
  }
2441
+ /** Force-refresh Antigravity usage (quotaSummary dual buckets) for one/all accounts. */
2442
+ async refreshAntigravity(accountId) {
2443
+ const config = await this.credentials.getFullConfig();
2444
+ this.store.pruneToKnownAccounts(this.knownAccounts(config));
2445
+ const accounts = (config.antigravityAccounts ?? []).filter(
2446
+ (account) => !accountId || account.id === accountId
2447
+ );
2448
+ return this.antigravityCollector.collectMany(accounts, { force: true });
2449
+ }
2111
2450
  /**
2112
2451
  * Keep Claude + Codex + Kimi snapshots warm for allowance-aware routing. All
2113
2452
  * collectors preserve their cache + per-account in-flight coalescing; a tick
@@ -2125,6 +2464,7 @@ var AccountAllowanceService = class {
2125
2464
  await this.grokCollector.collectMany(config.grokAccounts ?? [], { refreshAheadMs });
2126
2465
  await this.copilotCollector.collectMany(config.copilotAccounts ?? [], { refreshAheadMs });
2127
2466
  await this.geminiCollector.collectMany(config.geminiAccounts ?? [], { refreshAheadMs });
2467
+ await this.antigravityCollector.collectMany(config.antigravityAccounts ?? [], { refreshAheadMs });
2128
2468
  }
2129
2469
  /** Remove a cache row as soon as an account is deleted by the admin path. */
2130
2470
  removeAccountSnapshot(providerId, accountId) {
@@ -2219,7 +2559,7 @@ var ClaudeAllowanceRefreshScheduler = class {
2219
2559
  var import_node_crypto2 = require("crypto");
2220
2560
  var import_node_fs = require("fs");
2221
2561
  var import_node_path = require("path");
2222
- var import_AccountAllowanceStore9 = require("@omnicross/core/pipeline/AccountAllowanceStore");
2562
+ var import_AccountAllowanceStore10 = require("@omnicross/core/pipeline/AccountAllowanceStore");
2223
2563
  var ACCOUNT_ALLOWANCE_CACHE_VERSION = 1;
2224
2564
  var MAX_PERSISTED_ALLOWANCE_SNAPSHOTS = 256;
2225
2565
  var MAX_ALLOWANCE_CACHE_BYTES = 1e6;
@@ -2248,7 +2588,7 @@ var JsonAccountAllowancePersistence = class {
2248
2588
  save(snapshots) {
2249
2589
  const rows = [];
2250
2590
  for (const snapshot of snapshots) {
2251
- const normalized2 = (0, import_AccountAllowanceStore9.normalizeAccountAllowanceSnapshot)(snapshot);
2591
+ const normalized2 = (0, import_AccountAllowanceStore10.normalizeAccountAllowanceSnapshot)(snapshot);
2252
2592
  if (!normalized2) continue;
2253
2593
  rows.push(normalized2);
2254
2594
  if (rows.length >= MAX_PERSISTED_ALLOWANCE_SNAPSHOTS) break;
@@ -2531,7 +2871,7 @@ var import_outbound_api5 = require("@omnicross/core/outbound-api");
2531
2871
  var import_image_generation_types = require("@omnicross/contracts/image-generation-types");
2532
2872
  var import_AccountAllowanceScheduling2 = require("@omnicross/core/pipeline/AccountAllowanceScheduling");
2533
2873
  var import_SubscriptionAccountHealth = require("@omnicross/core/pipeline/SubscriptionAccountHealth");
2534
- var import_upstreamFetch10 = require("@omnicross/core/pipeline/upstreamFetch");
2874
+ var import_upstreamFetch12 = require("@omnicross/core/pipeline/upstreamFetch");
2535
2875
  var import_core3 = require("@omnicross/core");
2536
2876
 
2537
2877
  // src/image-generation/imagesConfigValidation.ts
@@ -3131,7 +3471,11 @@ var TOKEN_FIELDS = {
3131
3471
  claude: ["accessToken", "refreshToken"],
3132
3472
  codex: ["accessToken", "refreshToken", "idToken"],
3133
3473
  gemini: ["accessToken", "refreshToken"],
3134
- opencodego: ["apiKey"]
3474
+ opencodego: ["apiKey"],
3475
+ kimi: ["accessToken", "refreshToken"],
3476
+ grok: ["accessToken", "refreshToken"],
3477
+ copilot: ["accessToken", "refreshToken"],
3478
+ antigravity: ["accessToken", "refreshToken"]
3135
3479
  };
3136
3480
  function transformTokenBlock(block, fields, fn) {
3137
3481
  const next = { ...block };
@@ -3203,6 +3547,19 @@ function resolveAdminConfig(admin) {
3203
3547
  token: typeof admin?.token === "string" && admin.token.length > 0 ? admin.token : void 0
3204
3548
  };
3205
3549
  }
3550
+ function validateAntigravity(raw) {
3551
+ if (!raw || typeof raw !== "object" || Array.isArray(raw)) return void 0;
3552
+ const a = raw;
3553
+ if (typeof a["sandboxFailover"] !== "boolean") return void 0;
3554
+ return { sandboxFailover: a["sandboxFailover"] };
3555
+ }
3556
+ function validateOpenCodeGo(raw) {
3557
+ if (!raw || typeof raw !== "object" || Array.isArray(raw)) return void 0;
3558
+ const o = raw;
3559
+ const ua = o["userAgent"];
3560
+ if (typeof ua !== "string" || ua.trim().length === 0) return void 0;
3561
+ return { userAgent: ua.trim() };
3562
+ }
3206
3563
  function validateUsage(raw) {
3207
3564
  if (!raw || typeof raw !== "object" || Array.isArray(raw)) return void 0;
3208
3565
  const u = raw;
@@ -3496,7 +3853,9 @@ function validateConfig(raw) {
3496
3853
  const admin = validateAdmin(obj["admin"]);
3497
3854
  const logging = validateLogging(obj["logging"]);
3498
3855
  const usage = validateUsage(obj["usage"]);
3499
- return { providers, server, admin, logging };
3856
+ const antigravity = validateAntigravity(obj["antigravity"]);
3857
+ const opencodego = validateOpenCodeGo(obj["opencodego"]);
3858
+ return { providers, server, admin, logging, usage, antigravity, opencodego };
3500
3859
  }
3501
3860
  var secretBox = null;
3502
3861
  function setSecretBox(box) {
@@ -4517,11 +4876,11 @@ function preserveOutboundProxySecrets(incoming, current) {
4517
4876
  }
4518
4877
 
4519
4878
  // src/proxy/upstreamProxyResolver.ts
4520
- var import_upstreamFetch8 = require("@omnicross/core/pipeline/upstreamFetch");
4879
+ var import_upstreamFetch9 = require("@omnicross/core/pipeline/upstreamFetch");
4521
4880
  var serverProxy;
4522
4881
  function setServerProxyConfig(proxy) {
4523
4882
  serverProxy = proxy;
4524
- (0, import_upstreamFetch8.bumpUpstreamProxyGeneration)();
4883
+ (0, import_upstreamFetch9.bumpUpstreamProxyGeneration)();
4525
4884
  }
4526
4885
  function getServerProxyConfig() {
4527
4886
  return serverProxy;
@@ -4588,8 +4947,169 @@ function createUpstreamProxyResolver(src = {}) {
4588
4947
  };
4589
4948
  }
4590
4949
 
4591
- // src/admin/accountsOAuth.ts
4950
+ // src/admin/accountsAntigravityOAuth.ts
4951
+ var import_GeminiCodeAssistProjectResolver3 = require("@omnicross/core/auth/GeminiCodeAssistProjectResolver");
4592
4952
  var import_subscriptions8 = require("@omnicross/subscriptions");
4953
+ function err5(status, message) {
4954
+ return { status, body: { error: { type: "admin_api_error", message } } };
4955
+ }
4956
+ var DEFAULT_ANTIGRAVITY_OAUTH_TTL_MS = 10 * 6e4;
4957
+ function handleAntigravityOAuthStart(deps) {
4958
+ if (deps.antigravitySessions.isBusy()) {
4959
+ return err5(
4960
+ 409,
4961
+ "an antigravity sign-in is already in progress (loopback 127.0.0.1:51121 is held) \u2014 finish it in the browser or wait for it to time out"
4962
+ );
4963
+ }
4964
+ const { authUrl, state } = import_subscriptions8.antigravityOAuth.generateAuthParams();
4965
+ const { sessionId, signal } = deps.antigravitySessions.begin();
4966
+ void runAntigravityLoopback(sessionId, state, signal, deps);
4967
+ return { status: 200, body: { authUrl, sessionId } };
4968
+ }
4969
+ async function runAntigravityLoopback(sessionId, state, signal, deps) {
4970
+ const isPending = () => !signal.aborted && deps.antigravitySessions.get(sessionId)?.status === "pending";
4971
+ try {
4972
+ const code = await deps.antigravityAwaitLoopback(state, void 0, signal);
4973
+ if (!isPending()) return;
4974
+ const exchangeFetch = deps.oauthExchangeFetch("antigravity");
4975
+ const result = await import_subscriptions8.antigravityOAuth.exchangeCodeForTokens(code, exchangeFetch);
4976
+ if (!isPending()) return;
4977
+ const expiresAt = new Date(Date.now() + result.expiresIn * 1e3).toISOString();
4978
+ const email = await import_subscriptions8.antigravityOAuth.fetchUserEmail(result.accessToken, exchangeFetch);
4979
+ if (!isPending()) return;
4980
+ const projectId = await (0, import_GeminiCodeAssistProjectResolver3.getAntigravityProjectResolver)().resolveProject(result.accessToken);
4981
+ if (!isPending()) return;
4982
+ const block = {
4983
+ authMethod: "oauth",
4984
+ status: "authorized",
4985
+ accessToken: result.accessToken,
4986
+ refreshToken: result.refreshToken,
4987
+ expiresAt,
4988
+ ...email ? { email } : {},
4989
+ ...projectId ? { projectId } : {},
4990
+ lastRefreshedAt: (/* @__PURE__ */ new Date()).toISOString()
4991
+ };
4992
+ await deps.subscriptionAccountAppender.appendProviderAccount("antigravity", block);
4993
+ if (isPending()) deps.antigravitySessions.settle(sessionId, "done");
4994
+ } catch (e) {
4995
+ if (!isPending()) return;
4996
+ const reason = e instanceof Error ? e.message : "antigravity sign-in failed";
4997
+ deps.antigravitySessions.settle(sessionId, "error", reason);
4998
+ }
4999
+ }
5000
+ function handleAntigravityOAuthCancel(sessionId, deps) {
5001
+ if (!deps.antigravitySessions.cancel(sessionId)) {
5002
+ return err5(404, "unknown or expired antigravity sign-in session");
5003
+ }
5004
+ return { status: 200, body: { ok: true } };
5005
+ }
5006
+ function handleAntigravityOAuthStatus(sessionId, deps) {
5007
+ const s = deps.antigravitySessions.get(sessionId);
5008
+ if (!s) return err5(404, "unknown or expired antigravity sign-in session");
5009
+ return { status: 200, body: { state: s.status, ...s.error ? { message: s.error } : {} } };
5010
+ }
5011
+
5012
+ // src/allowance/AntigravityModelDiscovery.ts
5013
+ var import_canonical_models = require("@omnicross/contracts/canonical-models");
5014
+ var import_subscription_model_catalog = require("@omnicross/contracts/subscription-model-catalog");
5015
+ var import_GeminiCodeAssistProjectResolver4 = require("@omnicross/core/auth/GeminiCodeAssistProjectResolver");
5016
+ var import_upstreamFetch10 = require("@omnicross/core/pipeline/upstreamFetch");
5017
+ var import_antigravityIdentity2 = require("@omnicross/core/transformer/transformers/antigravityIdentity");
5018
+ function isRecord6(value) {
5019
+ return !!value && typeof value === "object" && !Array.isArray(value);
5020
+ }
5021
+ function optionalString(value) {
5022
+ return typeof value === "string" && value.length > 0 ? value : void 0;
5023
+ }
5024
+ function optionalNumber(value) {
5025
+ return typeof value === "number" && Number.isFinite(value) && value > 0 ? value : void 0;
5026
+ }
5027
+ function optionalBoolean(value) {
5028
+ return typeof value === "boolean" ? value : void 0;
5029
+ }
5030
+ function parseAntigravityAvailableModels(payload) {
5031
+ if (!isRecord6(payload)) return [];
5032
+ const models = payload["models"];
5033
+ if (!isRecord6(models)) return [];
5034
+ const out = [];
5035
+ for (const [id, raw] of Object.entries(models)) {
5036
+ if (ANTIGRAVITY_DISCOVERY_DENYLIST.has(id)) continue;
5037
+ if (!isRecord6(raw)) continue;
5038
+ if (raw["isInternal"] === true) continue;
5039
+ out.push({
5040
+ id,
5041
+ ...optionalString(raw["displayName"]) ? { displayName: optionalString(raw["displayName"]) } : {},
5042
+ ...optionalBoolean(raw["supportsImages"]) !== void 0 ? { supportsImages: optionalBoolean(raw["supportsImages"]) } : {},
5043
+ ...optionalBoolean(raw["supportsThinking"]) !== void 0 ? { supportsThinking: optionalBoolean(raw["supportsThinking"]) } : {},
5044
+ ...optionalNumber(raw["thinkingBudget"]) !== void 0 ? { thinkingBudget: optionalNumber(raw["thinkingBudget"]) } : {},
5045
+ ...optionalNumber(raw["maxTokens"]) !== void 0 ? { maxTokens: optionalNumber(raw["maxTokens"]) } : {},
5046
+ ...optionalNumber(raw["maxOutputTokens"]) !== void 0 ? { maxOutputTokens: optionalNumber(raw["maxOutputTokens"]) } : {}
5047
+ });
5048
+ }
5049
+ out.sort((a, b) => a.id.localeCompare(b.id));
5050
+ return out;
5051
+ }
5052
+ function mergeAntigravityCatalog(discovered, log = (line) => console.warn(line), staticIds = import_subscription_model_catalog.SUBSCRIPTION_MODEL_CATALOG.antigravity) {
5053
+ const entries = staticIds.map((id) => {
5054
+ const capabilities = (0, import_canonical_models.lookupCanonicalCapabilities)(id);
5055
+ return {
5056
+ id,
5057
+ origin: "static",
5058
+ displayName: id,
5059
+ ...capabilities?.vision !== void 0 ? { supportsImages: capabilities.vision } : {},
5060
+ ...capabilities?.reasoning !== void 0 ? { supportsThinking: capabilities.reasoning } : {},
5061
+ ...capabilities?.thinkingTokenLimit ? { thinkingBudget: capabilities.thinkingTokenLimit.max } : {},
5062
+ // Discovery calls the context window maxTokens, not the output ceiling.
5063
+ ...capabilities?.contextLength !== void 0 ? { maxTokens: capabilities.contextLength } : {},
5064
+ ...capabilities?.maxTokens !== void 0 ? { maxOutputTokens: capabilities.maxTokens } : {}
5065
+ };
5066
+ });
5067
+ const staticSet = new Set(staticIds);
5068
+ for (const model of discovered) {
5069
+ if (staticSet.has(model.id)) {
5070
+ log(
5071
+ `[AntigravityModelDiscovery] dynamic model '${model.id}' conflicts with the static catalog \u2014 static entry kept`
5072
+ );
5073
+ continue;
5074
+ }
5075
+ entries.push({ ...model, origin: "discovered" });
5076
+ }
5077
+ return entries;
5078
+ }
5079
+ async function fetchAntigravityAvailableModels(accessToken, fetchImpl = (url, init) => (0, import_upstreamFetch10.fetchUpstream)(url, init, { providerId: "antigravity", redactBodies: true })) {
5080
+ let response;
5081
+ try {
5082
+ response = await fetchImpl(`${import_GeminiCodeAssistProjectResolver4.ANTIGRAVITY_CODE_ASSIST_ENDPOINT}/v1internal:fetchAvailableModels`, {
5083
+ method: "POST",
5084
+ headers: {
5085
+ Authorization: `Bearer ${accessToken}`,
5086
+ Accept: "application/json",
5087
+ "Content-Type": "application/json",
5088
+ "User-Agent": (0, import_antigravityIdentity2.getAntigravityUserAgent)()
5089
+ },
5090
+ body: JSON.stringify({}),
5091
+ signal: AbortSignal.timeout(15e3)
5092
+ });
5093
+ } catch {
5094
+ return null;
5095
+ }
5096
+ if (!response.ok) return null;
5097
+ const payload = await response.json().catch(() => null);
5098
+ if (!isRecord6(payload) || !isRecord6(payload["models"])) return null;
5099
+ return parseAntigravityAvailableModels(payload);
5100
+ }
5101
+ async function handleAntigravityModelsRoute(deps) {
5102
+ const accessToken = await deps.resolveAntigravityAccessToken().catch(() => null);
5103
+ const discovered = accessToken ? await fetchAntigravityAvailableModels(accessToken, deps.fetchImpl) : null;
5104
+ const models = mergeAntigravityCatalog(discovered ?? []);
5105
+ return {
5106
+ status: 200,
5107
+ body: { models, discovered: discovered !== null }
5108
+ };
5109
+ }
5110
+
5111
+ // src/admin/accountsOAuth.ts
5112
+ var import_subscriptions9 = require("@omnicross/subscriptions");
4593
5113
 
4594
5114
  // src/admin/accountsWrite.ts
4595
5115
  var VALID_PROVIDER_IDS = [
@@ -4599,7 +5119,8 @@ var VALID_PROVIDER_IDS = [
4599
5119
  "opencodego",
4600
5120
  "kimi",
4601
5121
  "grok",
4602
- "copilot"
5122
+ "copilot",
5123
+ "antigravity"
4603
5124
  ];
4604
5125
  function asSubscriptionProviderId(id) {
4605
5126
  return VALID_PROVIDER_IDS.includes(id) ? id : null;
@@ -4781,7 +5302,7 @@ function validateCopilot(body) {
4781
5302
  ]);
4782
5303
  return out;
4783
5304
  }
4784
- function validateOpenCodeGo(body) {
5305
+ function validateOpenCodeGo2(body) {
4785
5306
  const authMethod = str(body["authMethod"]);
4786
5307
  const status = str(body["status"]);
4787
5308
  if (authMethod !== "manual") return null;
@@ -4815,7 +5336,7 @@ function validateTokenBody(providerId, body) {
4815
5336
  case "gemini":
4816
5337
  return validateGemini(body);
4817
5338
  case "opencodego":
4818
- return validateOpenCodeGo(body);
5339
+ return validateOpenCodeGo2(body);
4819
5340
  case "kimi":
4820
5341
  return validateKimi(body);
4821
5342
  case "grok":
@@ -4851,37 +5372,37 @@ async function statusEntryFor(reader, providerId) {
4851
5372
 
4852
5373
  // src/admin/accountsOAuth.ts
4853
5374
  var OAUTH_HTTP_PROVIDERS = /* @__PURE__ */ new Set(["claude", "gemini"]);
4854
- function err5(status, message) {
5375
+ function err6(status, message) {
4855
5376
  return { status, body: { error: { type: "admin_api_error", message } } };
4856
5377
  }
4857
5378
  function handleOAuthStart(providerId, deps) {
4858
5379
  if (!OAUTH_HTTP_PROVIDERS.has(providerId)) {
4859
- return err5(400, `oauth not available for provider '${providerId}'`);
5380
+ return err6(400, `oauth not available for provider '${providerId}'`);
4860
5381
  }
4861
- const flow = providerId === "claude" ? import_subscriptions8.claudeOAuth : import_subscriptions8.geminiOAuth;
5382
+ const flow = providerId === "claude" ? import_subscriptions9.claudeOAuth : import_subscriptions9.geminiOAuth;
4862
5383
  const { authUrl, codeVerifier, state } = flow.generateAuthParams();
4863
5384
  const sessionId = deps.oauthSessions.put({ providerId, codeVerifier, state });
4864
5385
  return { status: 200, body: { authUrl, sessionId } };
4865
5386
  }
4866
5387
  async function handleOAuthComplete(providerId, body, deps) {
4867
5388
  if (!OAUTH_HTTP_PROVIDERS.has(providerId)) {
4868
- return err5(400, `oauth not available for provider '${providerId}'`);
5389
+ return err6(400, `oauth not available for provider '${providerId}'`);
4869
5390
  }
4870
5391
  const sessionId = typeof body["sessionId"] === "string" ? body["sessionId"] : "";
4871
5392
  const rawCode = typeof body["code"] === "string" ? body["code"] : "";
4872
- if (!sessionId) return err5(400, "oauth complete requires { sessionId }");
4873
- if (!rawCode) return err5(400, "oauth complete requires { code }");
5393
+ if (!sessionId) return err6(400, "oauth complete requires { sessionId }");
5394
+ if (!rawCode) return err6(400, "oauth complete requires { code }");
4874
5395
  const session = deps.oauthSessions.peek(sessionId);
4875
- if (!session) return err5(410, "oauth session is unknown, expired, or already used");
5396
+ if (!session) return err6(410, "oauth session is unknown, expired, or already used");
4876
5397
  if (session.providerId !== providerId) {
4877
- return err5(400, `oauth session does not match provider '${providerId}'`);
5398
+ return err6(400, `oauth session does not match provider '${providerId}'`);
4878
5399
  }
4879
5400
  let code = rawCode.trim();
4880
5401
  if (providerId === "claude") {
4881
5402
  const [splitCode, pastedState] = code.split("#");
4882
- if (!splitCode) return err5(400, "no authorization code was provided");
5403
+ if (!splitCode) return err6(400, "no authorization code was provided");
4883
5404
  if (pastedState && pastedState !== session.state) {
4884
- return err5(400, "oauth state did not match (possible CSRF) \u2014 aborting");
5405
+ return err6(400, "oauth state did not match (possible CSRF) \u2014 aborting");
4885
5406
  }
4886
5407
  code = splitCode;
4887
5408
  }
@@ -4891,7 +5412,7 @@ async function handleOAuthComplete(providerId, body, deps) {
4891
5412
  block = providerId === "claude" ? await exchangeClaude(code, session.codeVerifier, session.state, exchangeFetch) : await exchangeGemini(code, session.codeVerifier, exchangeFetch);
4892
5413
  } catch (exchangeError) {
4893
5414
  const reason = exchangeError instanceof Error ? exchangeError.message : "token exchange failed";
4894
- return err5(502, `oauth token exchange failed for '${providerId}': ${reason}`);
5415
+ return err6(502, `oauth token exchange failed for '${providerId}': ${reason}`);
4895
5416
  }
4896
5417
  deps.oauthSessions.consume(sessionId);
4897
5418
  const label = typeof body["label"] === "string" && body["label"].trim() ? body["label"].trim() : void 0;
@@ -4900,7 +5421,7 @@ async function handleOAuthComplete(providerId, body, deps) {
4900
5421
  return { status: 200, body: status ? { account: status } : { ok: true } };
4901
5422
  }
4902
5423
  async function exchangeClaude(code, codeVerifier, state, exchangeFetch) {
4903
- const result = await import_subscriptions8.claudeOAuth.exchangeCodeForTokens(
5424
+ const result = await import_subscriptions9.claudeOAuth.exchangeCodeForTokens(
4904
5425
  { authorizationCode: code, codeVerifier, state },
4905
5426
  exchangeFetch
4906
5427
  );
@@ -4916,7 +5437,7 @@ async function exchangeClaude(code, codeVerifier, state, exchangeFetch) {
4916
5437
  };
4917
5438
  }
4918
5439
  async function exchangeGemini(code, codeVerifier, exchangeFetch) {
4919
- const result = await import_subscriptions8.geminiOAuth.exchangeCodeForTokens(code, codeVerifier, exchangeFetch);
5440
+ const result = await import_subscriptions9.geminiOAuth.exchangeCodeForTokens(code, codeVerifier, exchangeFetch);
4920
5441
  const expiresAt = new Date(Date.now() + result.expiresIn * 1e3).toISOString();
4921
5442
  return {
4922
5443
  authMethod: "oauth",
@@ -5221,8 +5742,8 @@ function errBody(message) {
5221
5742
  return { error: { type: "admin_api_error", message } };
5222
5743
  }
5223
5744
  var defaultCommandRunner = (command) => new Promise((resolve10) => {
5224
- (0, import_node_child_process.exec)(command, { timeout: 18e4 }, (err8, _stdout, stderr) => {
5225
- if (err8) resolve10({ ok: false, error: stderr.trim() || err8.message });
5745
+ (0, import_node_child_process.exec)(command, { timeout: 18e4 }, (err9, _stdout, stderr) => {
5746
+ if (err9) resolve10({ ok: false, error: stderr.trim() || err9.message });
5226
5747
  else resolve10({ ok: true });
5227
5748
  });
5228
5749
  });
@@ -5268,8 +5789,8 @@ async function handleCliLaunch(cli, body, ctx) {
5268
5789
  providerId: typeof body["providerId"] === "string" ? body["providerId"] : void 0,
5269
5790
  model: typeof body["model"] === "string" ? body["model"] : void 0
5270
5791
  });
5271
- } catch (err8) {
5272
- return { status: 400, body: errBody(err8 instanceof Error ? err8.message : "no launch target") };
5792
+ } catch (err9) {
5793
+ return { status: 400, body: errBody(err9 instanceof Error ? err9.message : "no launch target") };
5273
5794
  }
5274
5795
  const id = (0, import_node_crypto7.randomUUID)();
5275
5796
  let leaseId2;
@@ -5297,9 +5818,9 @@ async function handleCliLaunch(cli, body, ctx) {
5297
5818
  } else {
5298
5819
  launch = await buildLaunchEnv(cli, ctx.llmConfig, target);
5299
5820
  }
5300
- } catch (err8) {
5301
- const status = err8 instanceof import_provider_proxy2.RouteLeaseError ? err8.status : 400;
5302
- return { status, body: errBody(err8 instanceof Error ? err8.message : "failed to build launch env") };
5821
+ } catch (err9) {
5822
+ const status = err9 instanceof import_provider_proxy2.RouteLeaseError ? err9.status : 400;
5823
+ return { status, body: errBody(err9 instanceof Error ? err9.message : "failed to build launch env") };
5303
5824
  }
5304
5825
  const cwd = typeof body["cwd"] === "string" && body["cwd"].trim() ? body["cwd"].trim() : void 0;
5305
5826
  const opener = ctx.opener ?? defaultTerminalOpener;
@@ -5327,9 +5848,9 @@ async function handleCliLaunch(cli, body, ctx) {
5327
5848
  onFailure: onSessionEnd
5328
5849
  });
5329
5850
  if (cleanup) openerCleanup = cleanup;
5330
- } catch (err8) {
5851
+ } catch (err9) {
5331
5852
  onSessionEnd();
5332
- return { status: 500, body: errBody(err8 instanceof Error ? err8.message : "failed to open terminal") };
5853
+ return { status: 500, body: errBody(err9 instanceof Error ? err9.message : "failed to open terminal") };
5333
5854
  }
5334
5855
  if (ended) {
5335
5856
  openerCleanup?.();
@@ -5570,7 +6091,7 @@ function classifySearchFailure(stage, code) {
5570
6091
  }
5571
6092
 
5572
6093
  // src/search/SearchAssembly.ts
5573
- var import_upstreamFetch9 = require("@omnicross/core/pipeline/upstreamFetch");
6094
+ var import_upstreamFetch11 = require("@omnicross/core/pipeline/upstreamFetch");
5574
6095
  var import_search = require("@omnicross/core/search");
5575
6096
  var import_api2 = require("@omnicross/core/search/api");
5576
6097
  var import_http2 = require("@omnicross/core/search/http");
@@ -5588,7 +6109,7 @@ function searchPolicyFrom(config) {
5588
6109
  };
5589
6110
  }
5590
6111
  function resolveSearchUpstreamDispatcher(url) {
5591
- return (0, import_upstreamFetch9.resolveUpstreamDispatcher)({ url });
6112
+ return (0, import_upstreamFetch11.resolveUpstreamDispatcher)({ url });
5592
6113
  }
5593
6114
  var searchUpstreamProxyConfig = createUpstreamProxyResolver();
5594
6115
  function resolveSearchUpstreamProxyConfig(url) {
@@ -5870,7 +6391,7 @@ async function handleSearchQuery(req, res, deps) {
5870
6391
  // src/admin/searchAdminView.ts
5871
6392
  var API_KEY_PROVIDERS = /* @__PURE__ */ new Set(["tavily", "jina", "zhipu", "z.ai"]);
5872
6393
  var BASIC_AUTH_PROVIDERS = /* @__PURE__ */ new Set(["searxng"]);
5873
- function isRecord5(value) {
6394
+ function isRecord7(value) {
5874
6395
  return value !== null && typeof value === "object" && !Array.isArray(value);
5875
6396
  }
5876
6397
  function redactSearchServerConfig(search) {
@@ -5920,13 +6441,13 @@ function resolveSecretField(entry, field, stored) {
5920
6441
  else delete entry[field];
5921
6442
  }
5922
6443
  function preserveSearchSecrets(incoming, current) {
5923
- if (!isRecord5(incoming)) return incoming;
6444
+ if (!isRecord7(incoming)) return incoming;
5924
6445
  const section = { ...incoming };
5925
6446
  const providersValue = section["providers"];
5926
- if (!isRecord5(providersValue)) return section;
6447
+ if (!isRecord7(providersValue)) return section;
5927
6448
  const providers = {};
5928
6449
  for (const [id, entryValue] of Object.entries(providersValue)) {
5929
- if (!isRecord5(entryValue)) {
6450
+ if (!isRecord7(entryValue)) {
5930
6451
  providers[id] = entryValue;
5931
6452
  continue;
5932
6453
  }
@@ -6004,7 +6525,7 @@ function parseKeyPolicyBody(body) {
6004
6525
  var ENDPOINTS = /* @__PURE__ */ new Set(["chat", "responses", "messages", "gemini"]);
6005
6526
  var TARGET_KINDS = /* @__PURE__ */ new Set(["account", "account-group", "account-pool", "provider"]);
6006
6527
  var FALLBACKS = /* @__PURE__ */ new Set(["next", "fail", "global"]);
6007
- function isRecord6(value) {
6528
+ function isRecord8(value) {
6008
6529
  return !!value && typeof value === "object" && !Array.isArray(value);
6009
6530
  }
6010
6531
  function nonBlank(value) {
@@ -6024,7 +6545,7 @@ function validateGatewayBindingsSegment(patch) {
6024
6545
  const ids = /* @__PURE__ */ new Set();
6025
6546
  raw.forEach((entry, index) => {
6026
6547
  const path2 = `bindings[${index}]`;
6027
- if (!isRecord6(entry)) {
6548
+ if (!isRecord8(entry)) {
6028
6549
  errors.push(`${path2} must be an object`);
6029
6550
  return;
6030
6551
  }
@@ -6053,12 +6574,12 @@ function validateGatewayBindingsSegment(patch) {
6053
6574
  } else if (entry.modelMappings.length > 100) {
6054
6575
  errors.push(`${path2}.modelMappings cannot contain more than 100 entries`);
6055
6576
  } else if (entry.modelMappings.some(
6056
- (mapping) => !isRecord6(mapping) || !nonBlank(mapping.source) || !nonBlank(mapping.target)
6577
+ (mapping) => !isRecord8(mapping) || !nonBlank(mapping.source) || !nonBlank(mapping.target)
6057
6578
  )) {
6058
6579
  errors.push(`${path2}.modelMappings must contain non-empty source and target strings`);
6059
6580
  }
6060
6581
  }
6061
- if (!isRecord6(entry.target) || !TARGET_KINDS.has(String(entry.target.kind))) {
6582
+ if (!isRecord8(entry.target) || !TARGET_KINDS.has(String(entry.target.kind))) {
6062
6583
  errors.push(`${path2}.target is invalid`);
6063
6584
  } else {
6064
6585
  if (!nonBlank(entry.target.providerId)) errors.push(`${path2}.target.providerId is required`);
@@ -6073,7 +6594,7 @@ function validateGatewayBindingsSegment(patch) {
6073
6594
  }
6074
6595
  }
6075
6596
  if (entry.modelMap !== void 0) {
6076
- if (!isRecord6(entry.modelMap) || Object.values(entry.modelMap).some((value) => typeof value !== "string")) {
6597
+ if (!isRecord8(entry.modelMap) || Object.values(entry.modelMap).some((value) => typeof value !== "string")) {
6077
6598
  errors.push(`${path2}.modelMap must contain string values`);
6078
6599
  }
6079
6600
  }
@@ -6374,7 +6895,12 @@ var PROVIDER_KEYS = {
6374
6895
  },
6375
6896
  kimi: { block: "kimi", accounts: "kimiAccounts", active: "activeKimiAccountId" },
6376
6897
  grok: { block: "grok", accounts: "grokAccounts", active: "activeGrokAccountId" },
6377
- copilot: { block: "copilot", accounts: "copilotAccounts", active: "activeCopilotAccountId" }
6898
+ copilot: { block: "copilot", accounts: "copilotAccounts", active: "activeCopilotAccountId" },
6899
+ antigravity: {
6900
+ block: "antigravity",
6901
+ accounts: "antigravityAccounts",
6902
+ active: "activeAntigravityAccountId"
6903
+ }
6378
6904
  };
6379
6905
  function clone(value) {
6380
6906
  return JSON.parse(JSON.stringify(value));
@@ -6896,7 +7422,7 @@ async function applyImport(packString, passphrase, mode, deps, parseProviderInpu
6896
7422
  }
6897
7423
 
6898
7424
  // src/admin/adminMigration.ts
6899
- function err6(status, message) {
7425
+ function err7(status, message) {
6900
7426
  return { status, body: { error: { type: "admin_api_error", message } } };
6901
7427
  }
6902
7428
  async function handleExport(body, deps) {
@@ -6906,30 +7432,30 @@ async function handleExport(body, deps) {
6906
7432
  return { status: 200, body: { pack, version: BUNDLE_VERSION } };
6907
7433
  } catch (error) {
6908
7434
  if (error instanceof WeakPassphraseError) {
6909
- return err6(400, error.message);
7435
+ return err7(400, error.message);
6910
7436
  }
6911
- return err6(500, "failed to build the migration pack");
7437
+ return err7(500, "failed to build the migration pack");
6912
7438
  }
6913
7439
  }
6914
7440
  async function handleImport(body, deps) {
6915
7441
  const blob = typeof body["blob"] === "string" ? body["blob"] : "";
6916
7442
  const passphrase = typeof body["passphrase"] === "string" ? body["passphrase"] : "";
6917
7443
  const mode = body["mode"] === "overwrite" ? "overwrite" : "merge";
6918
- if (!blob) return err6(400, "import requires { blob }");
7444
+ if (!blob) return err7(400, "import requires { blob }");
6919
7445
  try {
6920
7446
  const counts = await applyImport(blob, passphrase, mode, deps, deps.parseProviderInput);
6921
7447
  return { status: 200, body: counts };
6922
7448
  } catch (error) {
6923
7449
  if (error instanceof WeakPassphraseError) {
6924
- return err6(400, error.message);
7450
+ return err7(400, error.message);
6925
7451
  }
6926
- return err6(400, error instanceof Error ? error.message : "import failed");
7452
+ return err7(400, error instanceof Error ? error.message : "import failed");
6927
7453
  }
6928
7454
  }
6929
7455
 
6930
7456
  // src/admin/usagePricing.ts
6931
7457
  var import_usage = require("@omnicross/core/usage");
6932
- var err7 = (status, message) => ({
7458
+ var err8 = (status, message) => ({
6933
7459
  status,
6934
7460
  body: { error: { type: "admin_api_error", message } }
6935
7461
  });
@@ -6942,7 +7468,7 @@ function parseRange(query2) {
6942
7468
  const startTs = parseFiniteInt(query2.get("startTs"));
6943
7469
  const endTs = parseFiniteInt(query2.get("endTs"));
6944
7470
  if (startTs === null || endTs === null) {
6945
- return err7(400, "startTs and endTs are required finite-integer unix-millis query params");
7471
+ return err8(400, "startTs and endTs are required finite-integer unix-millis query params");
6946
7472
  }
6947
7473
  return { startTs, endTs };
6948
7474
  }
@@ -6967,14 +7493,14 @@ async function handleUsageGet(view, query2, deps) {
6967
7493
  case "timeseries": {
6968
7494
  const bucket = query2.get("bucket");
6969
7495
  if (bucket !== "hour" && bucket !== "day" && bucket !== "month") {
6970
- return err7(400, "bucket must be one of 'hour', 'day', 'month'");
7496
+ return err8(400, "bucket must be one of 'hour', 'day', 'month'");
6971
7497
  }
6972
7498
  const now = Date.now();
6973
7499
  const clamped = { startTs: range.startTs, endTs: Math.min(range.endTs, now) };
6974
7500
  if (clamped.startTs < clamped.endTs) {
6975
7501
  const projected = Math.ceil((clamped.endTs - clamped.startTs) / BUCKET_SPAN_MS[bucket]) + 1;
6976
7502
  if (projected > MAX_TIMESERIES_BUCKETS) {
6977
- return err7(
7503
+ return err8(
6978
7504
  400,
6979
7505
  `requested range projects ~${projected} '${bucket}' buckets (max ${MAX_TIMESERIES_BUCKETS}); narrow the range or use a coarser bucket`
6980
7506
  );
@@ -6997,7 +7523,7 @@ async function handleUsageGet(view, query2, deps) {
6997
7523
  };
6998
7524
  }
6999
7525
  default:
7000
- return err7(404, `unknown usage view '${view ?? ""}'`);
7526
+ return err8(404, `unknown usage view '${view ?? ""}'`);
7001
7527
  }
7002
7528
  }
7003
7529
  function poolKeyLabels(cfg) {
@@ -7046,7 +7572,7 @@ async function handlePricingList(deps) {
7046
7572
  async function handlePricingUpsert(body, deps) {
7047
7573
  const input = parsePricingEntryInput(body);
7048
7574
  if (!input) {
7049
- return err7(400, "invalid pricing entry (providerId, modelId, finite numeric inputPricePer1m/outputPricePer1m required)");
7575
+ return err8(400, "invalid pricing entry (providerId, modelId, finite numeric inputPricePer1m/outputPricePer1m required)");
7050
7576
  }
7051
7577
  const entry = await deps.pricingEngine.upsertManual(input);
7052
7578
  return { status: 200, body: { entry } };
@@ -7055,7 +7581,7 @@ async function handlePricingDelete(query2, deps) {
7055
7581
  const providerId = query2.get("providerId")?.trim() ?? "";
7056
7582
  const modelId = query2.get("modelId")?.trim() ?? "";
7057
7583
  if (!providerId || !modelId) {
7058
- return err7(400, "delete requires providerId and modelId query params");
7584
+ return err8(400, "delete requires providerId and modelId query params");
7059
7585
  }
7060
7586
  const deleted = await deps.pricingStore.delete(providerId, modelId);
7061
7587
  if (deleted) await deps.pricingEngine.invalidateCache();
@@ -7075,13 +7601,13 @@ async function handlePricingFetchLatest(deps) {
7075
7601
  }
7076
7602
  };
7077
7603
  } catch (e) {
7078
- return err7(502, `pricing-source fetch failed: ${e instanceof Error ? e.message : String(e)}`);
7604
+ return err8(502, `pricing-source fetch failed: ${e instanceof Error ? e.message : String(e)}`);
7079
7605
  }
7080
7606
  }
7081
7607
  async function handlePricingResolveConflicts(body, deps) {
7082
7608
  const raw = body["resolutions"];
7083
7609
  if (!Array.isArray(raw)) {
7084
- return err7(400, "resolve-conflicts requires { resolutions: [...] }");
7610
+ return err8(400, "resolve-conflicts requires { resolutions: [...] }");
7085
7611
  }
7086
7612
  const currentRows = await deps.pricingStore.getAll();
7087
7613
  const userEditedKeys = new Set(
@@ -7091,21 +7617,21 @@ async function handlePricingResolveConflicts(body, deps) {
7091
7617
  const pendingIncoming = /* @__PURE__ */ new Map();
7092
7618
  let staleCount = 0;
7093
7619
  for (const item of raw) {
7094
- if (!item || typeof item !== "object") return err7(400, "invalid resolution entry");
7620
+ if (!item || typeof item !== "object") return err8(400, "invalid resolution entry");
7095
7621
  const r = item;
7096
7622
  const action = r["action"];
7097
7623
  if (action !== "overwrite" && action !== "skip") {
7098
- return err7(400, "resolution action must be 'overwrite' or 'skip'");
7624
+ return err8(400, "resolution action must be 'overwrite' or 'skip'");
7099
7625
  }
7100
7626
  const providerId = typeof r["providerId"] === "string" && r["providerId"].trim() ? r["providerId"].trim() : "";
7101
7627
  const modelId = typeof r["modelId"] === "string" && r["modelId"].trim() ? r["modelId"].trim() : "";
7102
7628
  if (!providerId || !modelId) {
7103
- return err7(400, "each resolution requires top-level providerId and modelId");
7629
+ return err8(400, "each resolution requires top-level providerId and modelId");
7104
7630
  }
7105
7631
  const incoming = parsePricingEntryInput(r["incoming"]);
7106
- if (!incoming) return err7(400, "each resolution must echo a valid incoming pricing entry");
7632
+ if (!incoming) return err8(400, "each resolution must echo a valid incoming pricing entry");
7107
7633
  if (incoming.providerId !== providerId || incoming.modelId !== modelId) {
7108
- return err7(400, "resolution providerId/modelId must match the echoed incoming entry");
7634
+ return err8(400, "resolution providerId/modelId must match the echoed incoming entry");
7109
7635
  }
7110
7636
  const key = `${providerId}::${modelId}`;
7111
7637
  if (action === "overwrite" && !userEditedKeys.has(key)) {
@@ -7150,7 +7676,7 @@ function query(req) {
7150
7676
  }
7151
7677
  function allowanceProvider(value) {
7152
7678
  if (!value) return void 0;
7153
- return value === "claude" || value === "codex" || value === "kimi" || value === "opencodego" || value === "grok" || value === "copilot" || value === "gemini" ? value : null;
7679
+ return value === "claude" || value === "codex" || value === "kimi" || value === "opencodego" || value === "grok" || value === "copilot" || value === "gemini" || value === "antigravity" ? value : null;
7154
7680
  }
7155
7681
  async function handleAccountAllowanceApi(req, res, method, rest, service) {
7156
7682
  if (!service) return writeError2(res, 501, "account allowance service is not available");
@@ -7227,6 +7753,16 @@ async function handleAccountAllowanceApi(req, res, method, rest, service) {
7227
7753
  }
7228
7754
  return writeJson3(res, 200, { allowances: allowances2 });
7229
7755
  }
7756
+ if (requestedProvider === "antigravity") {
7757
+ if (!service.refreshAntigravity) {
7758
+ return writeError2(res, 501, "antigravity allowance refresh is not available");
7759
+ }
7760
+ const allowances2 = await service.refreshAntigravity(accountId);
7761
+ if (accountId && allowances2.length === 0) {
7762
+ return writeError2(res, 404, `Antigravity account '${accountId}' not found`);
7763
+ }
7764
+ return writeJson3(res, 200, { allowances: allowances2 });
7765
+ }
7230
7766
  if (requestedProvider === "gemini") {
7231
7767
  if (!service.refreshGemini) {
7232
7768
  return writeError2(res, 501, "gemini allowance refresh is not available");
@@ -7407,8 +7943,8 @@ async function handleAdminApi(req, res, path2, deps) {
7407
7943
  default:
7408
7944
  return writeJsonError(res, 404, `unknown admin resource '${resource}'`);
7409
7945
  }
7410
- } catch (err8) {
7411
- writeJsonError(res, 500, err8 instanceof Error ? err8.message : String(err8));
7946
+ } catch (err9) {
7947
+ writeJsonError(res, 500, err9 instanceof Error ? err9.message : String(err9));
7412
7948
  }
7413
7949
  }
7414
7950
  function requestQuery(req) {
@@ -7583,7 +8119,7 @@ async function handleDiscoverModels(res, id, cfg) {
7583
8119
  const headers = { Accept: "application/json" };
7584
8120
  if (resolvedKey) headers["Authorization"] = `Bearer ${resolvedKey}`;
7585
8121
  Object.assign(headers, expandRowExtraHeaders(row));
7586
- const response = await (0, import_upstreamFetch10.fetchUpstream)(url, { method: "GET", headers }, { providerId: "byo" });
8122
+ const response = await (0, import_upstreamFetch12.fetchUpstream)(url, { method: "GET", headers }, { providerId: "byo" });
7587
8123
  if (!response.ok) {
7588
8124
  const text = await response.text().catch(() => "");
7589
8125
  let message = text.slice(0, 300);
@@ -7600,8 +8136,8 @@ async function handleDiscoverModels(res, id, cfg) {
7600
8136
  const data = await response.json();
7601
8137
  const models = Array.isArray(data?.data) ? data.data.map((m) => typeof m?.id === "string" ? m.id : "").filter((m) => m.length > 0) : [];
7602
8138
  return writeJson4(res, 200, { models });
7603
- } catch (err8) {
7604
- const message = err8 instanceof Error ? err8.message : String(err8);
8139
+ } catch (err9) {
8140
+ const message = err9 instanceof Error ? err9.message : String(err9);
7605
8141
  return writeJson4(res, 200, { models: [], error: `discovery failed: ${message}` });
7606
8142
  }
7607
8143
  }
@@ -7643,7 +8179,7 @@ async function handleTestModel(req, res, id, cfg) {
7643
8179
  Object.assign(headers, expandRowExtraHeaders(row));
7644
8180
  const startedAt = Date.now();
7645
8181
  try {
7646
- const response = await (0, import_upstreamFetch10.fetchUpstream)(
8182
+ const response = await (0, import_upstreamFetch12.fetchUpstream)(
7647
8183
  url,
7648
8184
  { method: "POST", headers, body: JSON.stringify(payload) },
7649
8185
  { providerId: "byo" }
@@ -7665,8 +8201,8 @@ async function handleTestModel(req, res, id, cfg) {
7665
8201
  latencyMs,
7666
8202
  sample: extractSampleText(text, row.apiFormat)
7667
8203
  });
7668
- } catch (err8) {
7669
- const message = err8 instanceof Error ? err8.message : String(err8);
8204
+ } catch (err9) {
8205
+ const message = err9 instanceof Error ? err9.message : String(err9);
7670
8206
  return writeJson4(res, 200, { ok: false, latencyMs: Date.now() - startedAt, message });
7671
8207
  }
7672
8208
  }
@@ -8251,8 +8787,8 @@ function imageConfigurationAuditFields(previous, next) {
8251
8787
  const after = next ?? import_outbound_api5.DEFAULT_IMAGES_SERVER_CONFIG;
8252
8788
  const fields = [];
8253
8789
  if (before.enabled !== after.enabled) fields.push("enablement");
8254
- if (before.provider !== after.provider) fields.push("provider");
8255
- if (before.defaultModel !== after.defaultModel || !sameConfigValue(before.modelAliases, after.modelAliases)) fields.push("model");
8790
+ if (!sameConfigValue(before.models, after.models)) fields.push("provider");
8791
+ if (before.defaultModel !== after.defaultModel || !sameConfigValue(before.aliases, after.aliases) || !sameConfigValue(before.codex, after.codex)) fields.push("model");
8256
8792
  if (!sameConfigValue(before.account, after.account)) fields.push("account");
8257
8793
  if (!sameConfigValue(before.queue, after.queue)) fields.push("queue");
8258
8794
  if (!sameConfigValue(before.temporary, after.temporary)) fields.push("temporary");
@@ -8456,6 +8992,12 @@ async function handleAccounts(req, res, method, rest, deps) {
8456
8992
  deps.accountAllowanceService
8457
8993
  );
8458
8994
  }
8995
+ if (method === "GET" && rest[0] === "antigravity" && rest[1] === "models") {
8996
+ const result = await handleAntigravityModelsRoute({
8997
+ resolveAntigravityAccessToken: deps.resolveAntigravityAccessToken ?? (async () => null)
8998
+ });
8999
+ return writeJson4(res, result.status, result.body);
9000
+ }
8459
9001
  if (method === "GET" && rest.length === 0) {
8460
9002
  const accounts = await deps.subscriptionAccounts.listAll();
8461
9003
  const providerAccounts = await deps.subscriptionTokenWriter.listSanitizedAccounts();
@@ -8481,12 +9023,12 @@ async function handleAccounts(req, res, method, rest, deps) {
8481
9023
  }
8482
9024
  return writeJson4(res, 200, { ok: true, affected: result.affected });
8483
9025
  }
8484
- if (method === "GET" && (rest[0] === "codex" || rest[0] === "kimi" || rest[0] === "grok" || rest[0] === "copilot") && rest[1] === "oauth" && rest[3] === "status") {
8485
- const result = rest[0] === "codex" ? handleCodexOAuthStatus(rest[2], deps) : rest[0] === "kimi" ? handleKimiOAuthStatus(rest[2], deps) : rest[0] === "grok" ? handleGrokOAuthStatus(rest[2], deps) : handleCopilotOAuthStatus(rest[2], deps);
9026
+ if (method === "GET" && (rest[0] === "codex" || rest[0] === "kimi" || rest[0] === "grok" || rest[0] === "copilot" || rest[0] === "antigravity") && rest[1] === "oauth" && rest[3] === "status") {
9027
+ const result = rest[0] === "codex" ? handleCodexOAuthStatus(rest[2], deps) : rest[0] === "kimi" ? handleKimiOAuthStatus(rest[2], deps) : rest[0] === "grok" ? handleGrokOAuthStatus(rest[2], deps) : rest[0] === "copilot" ? handleCopilotOAuthStatus(rest[2], deps) : handleAntigravityOAuthStatus(rest[2], deps);
8486
9028
  return writeJson4(res, result.status, result.body);
8487
9029
  }
8488
- if (method === "DELETE" && (rest[0] === "codex" || rest[0] === "kimi" || rest[0] === "grok" || rest[0] === "copilot") && rest[1] === "oauth" && rest[2]) {
8489
- const result = rest[0] === "codex" ? handleCodexOAuthCancel(rest[2], deps) : rest[0] === "kimi" ? handleKimiOAuthCancel(rest[2], deps) : rest[0] === "grok" ? handleGrokOAuthCancel(rest[2], deps) : handleCopilotOAuthCancel(rest[2], deps);
9030
+ if (method === "DELETE" && (rest[0] === "codex" || rest[0] === "kimi" || rest[0] === "grok" || rest[0] === "copilot" || rest[0] === "antigravity") && rest[1] === "oauth" && rest[2]) {
9031
+ const result = rest[0] === "codex" ? handleCodexOAuthCancel(rest[2], deps) : rest[0] === "kimi" ? handleKimiOAuthCancel(rest[2], deps) : rest[0] === "grok" ? handleGrokOAuthCancel(rest[2], deps) : rest[0] === "copilot" ? handleCopilotOAuthCancel(rest[2], deps) : handleAntigravityOAuthCancel(rest[2], deps);
8490
9032
  return writeJson4(res, result.status, result.body);
8491
9033
  }
8492
9034
  if (method === "GET" && rest.length === 3 && rest[2] === "diagnostics") {
@@ -8556,6 +9098,10 @@ async function handleAccounts(req, res, method, rest, deps) {
8556
9098
  const result2 = await handleCopilotOAuthStart(deps, body2["enterpriseUrl"]);
8557
9099
  return writeJson4(res, result2.status, result2.body);
8558
9100
  }
9101
+ if (providerId === "antigravity") {
9102
+ const result2 = handleAntigravityOAuthStart(deps);
9103
+ return writeJson4(res, result2.status, result2.body);
9104
+ }
8559
9105
  const result = handleOAuthStart(providerId, deps);
8560
9106
  return writeJson4(res, result.status, result.body);
8561
9107
  }
@@ -8950,7 +9496,7 @@ async function handleImages(res, method, rest, deps) {
8950
9496
  return writeJson4(res, 200, {
8951
9497
  configured: {
8952
9498
  enabled: images.enabled,
8953
- provider: images.provider,
9499
+ provider: images.models[images.defaultModel] ?? "codex-subscription",
8954
9500
  model: images.defaultModel,
8955
9501
  remoteUrlsEnabled: images.remote.enabled,
8956
9502
  referenceTtlMs: images.references.ttlMs
@@ -9050,12 +9596,12 @@ async function handlePlayground(req, res, method, deps) {
9050
9596
  const payload = body["body"];
9051
9597
  const status = deps.outboundApiServer.getStatus();
9052
9598
  if (!status.running || !status.port) return writeJsonError(res, 503, "outbound server not running");
9053
- const path2 = resolvePlaygroundPath(endpoint, isRecord7(payload) ? payload : {});
9599
+ const path2 = resolvePlaygroundPath(endpoint, isRecord9(payload) ? payload : {});
9054
9600
  if (!path2) return writeJsonError(res, 400, `unknown endpoint '${endpoint}'`);
9055
9601
  const upstreamBody = typeof payload === "string" ? payload : JSON.stringify(payload ?? {});
9056
9602
  await proxyToOutbound(res, status.port, path2, key, upstreamBody);
9057
9603
  }
9058
- function isRecord7(v) {
9604
+ function isRecord9(v) {
9059
9605
  return !!v && typeof v === "object" && !Array.isArray(v);
9060
9606
  }
9061
9607
  function proxyToOutbound(res, outboundPort, path2, key, body) {
@@ -9084,8 +9630,8 @@ function proxyToOutbound(res, outboundPort, path2, key, body) {
9084
9630
  });
9085
9631
  }
9086
9632
  );
9087
- upstream.on("error", (err8) => {
9088
- if (!res.headersSent) writeJsonError(res, 502, `playground proxy failed: ${err8.message}`);
9633
+ upstream.on("error", (err9) => {
9634
+ if (!res.headersSent) writeJsonError(res, 502, `playground proxy failed: ${err9.message}`);
9089
9635
  else res.end();
9090
9636
  resolve10();
9091
9637
  });
@@ -9191,7 +9737,7 @@ async function handleUiStatic(req, res, urlPath, uiDist) {
9191
9737
  }
9192
9738
 
9193
9739
  // src/admin/version.ts
9194
- var DAEMON_VERSION = true ? "0.4.2" : "0.0.0-dev";
9740
+ var DAEMON_VERSION = true ? "0.4.3" : "0.0.0-dev";
9195
9741
 
9196
9742
  // src/admin/AdminServer.ts
9197
9743
  var LOOPBACK_ADDR = "127.0.0.1";
@@ -9234,13 +9780,13 @@ var AdminServer = class {
9234
9780
  const server = import_node_http2.default.createServer((req, res) => {
9235
9781
  this.onRequest(req, res);
9236
9782
  });
9237
- const onError = (err8) => {
9238
- if (err8.code === "EADDRINUSE" && port !== 0) {
9783
+ const onError = (err9) => {
9784
+ if (err9.code === "EADDRINUSE" && port !== 0) {
9239
9785
  server.removeListener("error", onError);
9240
9786
  this.listen(bindAddr, 0).then(resolve10, reject);
9241
9787
  return;
9242
9788
  }
9243
- reject(err8);
9789
+ reject(err9);
9244
9790
  };
9245
9791
  server.on("error", onError);
9246
9792
  server.listen(port, bindAddr, () => {
@@ -9258,8 +9804,8 @@ var AdminServer = class {
9258
9804
  }
9259
9805
  /** Per-request handler: auth gate (when a token is set) → routing. */
9260
9806
  onRequest(req, res) {
9261
- void this.dispatch(req, res).catch((err8) => {
9262
- const message = err8 instanceof Error ? err8.message : String(err8);
9807
+ void this.dispatch(req, res).catch((err9) => {
9808
+ const message = err9 instanceof Error ? err9.message : String(err9);
9263
9809
  this.deps.logger.error("[AdminServer] unhandled error:", message);
9264
9810
  if (!res.headersSent) {
9265
9811
  res.writeHead(500, { "Content-Type": "application/json" });
@@ -9482,7 +10028,10 @@ var HTML_HEADERS = {
9482
10028
  function pageHtml(message) {
9483
10029
  return `<!doctype html><meta charset="utf-8"><title>omnicross login</title><body style="font-family:sans-serif;padding:2rem"><h2>${message}</h2><p>You can close this window and return to the terminal.</p></body>`;
9484
10030
  }
9485
- function awaitLoopbackCode(expectedState, timeoutMs = DEFAULT_TIMEOUT_MS, signal) {
10031
+ function awaitLoopbackCode(expectedState, timeoutMs = DEFAULT_TIMEOUT_MS, signal, binding = {}) {
10032
+ const port = binding.port ?? LOOPBACK_PORT;
10033
+ const callbackPath = binding.path ?? CALLBACK_PATH;
10034
+ const label = binding.label ?? "codex";
9486
10035
  return new Promise((resolve10, reject) => {
9487
10036
  let settled = false;
9488
10037
  const finish = (server2, fn) => {
@@ -9493,8 +10042,8 @@ function awaitLoopbackCode(expectedState, timeoutMs = DEFAULT_TIMEOUT_MS, signal
9493
10042
  server2.close();
9494
10043
  };
9495
10044
  const server = (0, import_node_http3.createServer)((req, res) => {
9496
- const url = new URL(req.url ?? "", `http://${LOOPBACK_HOST}:${LOOPBACK_PORT}`);
9497
- if (url.pathname !== CALLBACK_PATH) {
10045
+ const url = new URL(req.url ?? "", `http://${LOOPBACK_HOST}:${port}`);
10046
+ if (url.pathname !== callbackPath) {
9498
10047
  res.writeHead(404, HTML_HEADERS);
9499
10048
  res.end(pageHtml("Not found"));
9500
10049
  return;
@@ -9523,25 +10072,25 @@ function awaitLoopbackCode(expectedState, timeoutMs = DEFAULT_TIMEOUT_MS, signal
9523
10072
  return;
9524
10073
  }
9525
10074
  signal?.addEventListener("abort", abort, { once: true });
9526
- server.on("error", (err8) => {
10075
+ server.on("error", (err9) => {
9527
10076
  if (settled) return;
9528
10077
  settled = true;
9529
10078
  clearTimeout(timer);
9530
- if (err8.code === "EADDRINUSE") {
10079
+ if (err9.code === "EADDRINUSE") {
9531
10080
  reject(
9532
10081
  new Error(
9533
- `login: cannot bind ${LOOPBACK_HOST}:${LOOPBACK_PORT} (address in use) \u2014 another codex login or process is holding the port`
10082
+ `login: cannot bind ${LOOPBACK_HOST}:${port} (address in use) \u2014 another ${label} login or process is holding the port`
9534
10083
  )
9535
10084
  );
9536
10085
  } else {
9537
- reject(err8);
10086
+ reject(err9);
9538
10087
  }
9539
10088
  });
9540
10089
  const timer = setTimeout(() => {
9541
10090
  finish(server, () => reject(new Error(`login: timed out after ${Math.round(timeoutMs / 1e3)}s waiting for the callback`)));
9542
10091
  }, timeoutMs);
9543
10092
  if (typeof timer.unref === "function") timer.unref();
9544
- server.listen(LOOPBACK_PORT, LOOPBACK_HOST);
10093
+ server.listen(port, LOOPBACK_HOST);
9545
10094
  });
9546
10095
  }
9547
10096
 
@@ -9611,7 +10160,7 @@ function createPoolKeysLoader(getProviderRow, autoDisabled) {
9611
10160
 
9612
10161
  // src/allowance/ProviderKeyQuotaService.ts
9613
10162
  var import_core4 = require("@omnicross/core");
9614
- var import_upstreamFetch11 = require("@omnicross/core/pipeline/upstreamFetch");
10163
+ var import_upstreamFetch13 = require("@omnicross/core/pipeline/upstreamFetch");
9615
10164
 
9616
10165
  // src/allowance/ProviderKeyQuota.ts
9617
10166
  var MINUTE_MS3 = 6e4;
@@ -9640,11 +10189,11 @@ function isoInstant3(value) {
9640
10189
  }
9641
10190
  return void 0;
9642
10191
  }
9643
- function secondsUntil8(instant, now) {
10192
+ function secondsUntil9(instant, now) {
9644
10193
  if (!instant) return void 0;
9645
10194
  return Math.max(0, Math.floor((Date.parse(instant) - now) / 1e3));
9646
10195
  }
9647
- function isRecord8(value) {
10196
+ function isRecord10(value) {
9648
10197
  return !!value && typeof value === "object" && !Array.isArray(value);
9649
10198
  }
9650
10199
  function detectProviderKeyQuotaAdapter(baseUrl) {
@@ -9711,17 +10260,17 @@ function zaiWindowIdLabel(durationMs) {
9711
10260
  return { id: "quota", label: "Quota" };
9712
10261
  }
9713
10262
  function parseZaiQuotaPayload(payload, now) {
9714
- if (!isRecord8(payload)) return null;
9715
- const data = isRecord8(payload["data"]) ? payload["data"] : payload;
10263
+ if (!isRecord10(payload)) return null;
10264
+ const data = isRecord10(payload["data"]) ? payload["data"] : payload;
9716
10265
  if (payload["success"] === false) return null;
9717
10266
  const limits = Array.isArray(data["limits"]) ? data["limits"] : [];
9718
10267
  const byWindow = /* @__PURE__ */ new Map();
9719
10268
  for (const raw of limits) {
9720
- if (!isRecord8(raw)) continue;
10269
+ if (!isRecord10(raw)) continue;
9721
10270
  const item = raw;
9722
10271
  if (item.type === void 0) continue;
9723
10272
  const details = raw["usageDetails"];
9724
- if (Array.isArray(details) && details.some((d) => isRecord8(d) && d["modelCode"] === "zread")) {
10273
+ if (Array.isArray(details) && details.some((d) => isRecord10(d) && d["modelCode"] === "zread")) {
9725
10274
  continue;
9726
10275
  }
9727
10276
  const durationMs = zaiWindowDurationMs(item);
@@ -9740,7 +10289,7 @@ function parseZaiQuotaPayload(payload, now) {
9740
10289
  usedPercent,
9741
10290
  ...durationMs !== void 0 ? { windowMinutes: Math.round(durationMs / MINUTE_MS3) } : {},
9742
10291
  ...resetsAt !== void 0 ? { resetsAt } : {},
9743
- remainingSeconds: secondsUntil8(resetsAt, now),
10292
+ remainingSeconds: secondsUntil9(resetsAt, now),
9744
10293
  state: "fresh"
9745
10294
  };
9746
10295
  const existing = byWindow.get(id);
@@ -9754,7 +10303,7 @@ function parseZaiQuotaPayload(payload, now) {
9754
10303
  var MINIMAX_STATUS_EXHAUSTED = 2;
9755
10304
  var MINIMAX_SHARED_BUCKET = "general";
9756
10305
  function parseMiniMaxBucket(value) {
9757
- if (!isRecord8(value)) return null;
10306
+ if (!isRecord10(value)) return null;
9758
10307
  const modelName = typeof value["model_name"] === "string" ? value["model_name"].trim() : "";
9759
10308
  if (!modelName) return null;
9760
10309
  const instant = (v) => {
@@ -9781,14 +10330,14 @@ function minimaxWindow(id, label, windowMinutes, resetsAtMs, remainingPercent, s
9781
10330
  usedPercent,
9782
10331
  ...windowMinutes !== void 0 ? { windowMinutes } : {},
9783
10332
  ...resetsAt !== void 0 ? { resetsAt } : {},
9784
- remainingSeconds: secondsUntil8(resetsAt, now),
10333
+ remainingSeconds: secondsUntil9(resetsAt, now),
9785
10334
  state: usedPercent !== null ? "fresh" : "unavailable"
9786
10335
  };
9787
10336
  }
9788
10337
  function parseMiniMaxTokenPlanPayload(payload, now) {
9789
- if (!isRecord8(payload)) return null;
10338
+ if (!isRecord10(payload)) return null;
9790
10339
  const baseResp = payload["base_resp"];
9791
- if (!isRecord8(baseResp) || baseResp["status_code"] !== 0) return null;
10340
+ if (!isRecord10(baseResp) || baseResp["status_code"] !== 0) return null;
9792
10341
  const buckets = Array.isArray(payload["model_remains"]) ? payload["model_remains"] : [];
9793
10342
  let general = null;
9794
10343
  for (const raw of buckets) {
@@ -9821,11 +10370,11 @@ function parseMiniMaxTokenPlanPayload(payload, now) {
9821
10370
  ];
9822
10371
  }
9823
10372
  function parseUmansUsagePayload(payload, now) {
9824
- if (!isRecord8(payload)) return null;
9825
- const limits = isRecord8(payload["limits"]) ? payload["limits"] : void 0;
9826
- const requests = limits && isRecord8(limits["requests"]) ? limits["requests"] : void 0;
9827
- const usage = isRecord8(payload["usage"]) ? payload["usage"] : void 0;
9828
- const window = isRecord8(payload["window"]) ? payload["window"] : void 0;
10373
+ if (!isRecord10(payload)) return null;
10374
+ const limits = isRecord10(payload["limits"]) ? payload["limits"] : void 0;
10375
+ const requests = limits && isRecord10(limits["requests"]) ? limits["requests"] : void 0;
10376
+ const usage = isRecord10(payload["usage"]) ? payload["usage"] : void 0;
10377
+ const window = isRecord10(payload["window"]) ? payload["window"] : void 0;
9829
10378
  const hardCap = finiteNumber5(requests?.["hard_cap"]);
9830
10379
  const softLimit = finiteNumber5(requests?.["limit"]);
9831
10380
  const requestsInWindow = finiteNumber5(usage?.["requests_in_window"]);
@@ -9846,15 +10395,15 @@ function parseUmansUsagePayload(payload, now) {
9846
10395
  usedPercent,
9847
10396
  windowMinutes: 5 * 60,
9848
10397
  ...resetsAt !== void 0 ? { resetsAt } : {},
9849
- remainingSeconds: secondsUntil8(resetsAt, now),
10398
+ remainingSeconds: secondsUntil9(resetsAt, now),
9850
10399
  state: "fresh"
9851
10400
  }
9852
10401
  ];
9853
10402
  }
9854
10403
  function parseSyntheticQuotasPayload(payload, now) {
9855
- if (!isRecord8(payload)) return null;
9856
- const fiveHour = isRecord8(payload["rollingFiveHourLimit"]) ? payload["rollingFiveHourLimit"] : void 0;
9857
- const weekly = isRecord8(payload["weeklyTokenLimit"]) ? payload["weeklyTokenLimit"] : void 0;
10404
+ if (!isRecord10(payload)) return null;
10405
+ const fiveHour = isRecord10(payload["rollingFiveHourLimit"]) ? payload["rollingFiveHourLimit"] : void 0;
10406
+ const weekly = isRecord10(payload["weeklyTokenLimit"]) ? payload["weeklyTokenLimit"] : void 0;
9858
10407
  const windows = [];
9859
10408
  if (fiveHour) {
9860
10409
  const max = finiteNumber5(fiveHour["max"]);
@@ -9868,7 +10417,7 @@ function parseSyntheticQuotasPayload(payload, now) {
9868
10417
  usedPercent,
9869
10418
  windowMinutes: 5 * 60,
9870
10419
  ...resetsAt !== void 0 ? { resetsAt } : {},
9871
- remainingSeconds: secondsUntil8(resetsAt, now),
10420
+ remainingSeconds: secondsUntil9(resetsAt, now),
9872
10421
  state: usedPercent !== null || resetsAt ? "fresh" : "unavailable"
9873
10422
  });
9874
10423
  }
@@ -9883,7 +10432,7 @@ function parseSyntheticQuotasPayload(payload, now) {
9883
10432
  usedPercent,
9884
10433
  windowMinutes: 7 * 24 * 60,
9885
10434
  ...resetsAt !== void 0 ? { resetsAt } : {},
9886
- remainingSeconds: secondsUntil8(resetsAt, now),
10435
+ remainingSeconds: secondsUntil9(resetsAt, now),
9887
10436
  state: usedPercent !== null || resetsAt ? "fresh" : "unavailable"
9888
10437
  });
9889
10438
  }
@@ -9895,12 +10444,12 @@ var CLINE_WINDOW_CONFIG = {
9895
10444
  monthly: { id: "thirty-day", label: "30 days", minutes: 30 * 24 * 60 }
9896
10445
  };
9897
10446
  function parseClinePassUsageLimitsPayload(payload, now) {
9898
- if (!isRecord8(payload)) return null;
9899
- const data = isRecord8(payload["data"]) ? payload["data"] : payload;
10447
+ if (!isRecord10(payload)) return null;
10448
+ const data = isRecord10(payload["data"]) ? payload["data"] : payload;
9900
10449
  const limits = Array.isArray(data["limits"]) ? data["limits"] : [];
9901
10450
  const windows = [];
9902
10451
  for (const raw of limits) {
9903
- if (!isRecord8(raw)) continue;
10452
+ if (!isRecord10(raw)) continue;
9904
10453
  const config = CLINE_WINDOW_CONFIG[typeof raw["type"] === "string" ? raw["type"] : ""];
9905
10454
  if (!config) continue;
9906
10455
  const usedPercent = finitePercent4(raw["percentUsed"]);
@@ -9913,7 +10462,7 @@ function parseClinePassUsageLimitsPayload(payload, now) {
9913
10462
  usedPercent,
9914
10463
  windowMinutes: config.minutes,
9915
10464
  ...resetsAt !== void 0 ? { resetsAt } : {},
9916
- remainingSeconds: secondsUntil8(resetsAt, now),
10465
+ remainingSeconds: secondsUntil9(resetsAt, now),
9917
10466
  state: "fresh"
9918
10467
  });
9919
10468
  }
@@ -9952,7 +10501,7 @@ function rowKeyEntries(row) {
9952
10501
  return [];
9953
10502
  }
9954
10503
  var ProviderKeyQuotaService = class {
9955
- constructor(box, fetchImpl = (url, init) => (0, import_upstreamFetch11.fetchUpstream)(url, init, { redactBodies: true }), now = Date.now) {
10504
+ constructor(box, fetchImpl = (url, init) => (0, import_upstreamFetch13.fetchUpstream)(url, init, { redactBodies: true }), now = Date.now) {
9956
10505
  this.box = box;
9957
10506
  this.fetchImpl = fetchImpl;
9958
10507
  this.now = now;
@@ -10088,7 +10637,7 @@ function defaultBillingDir(configPath) {
10088
10637
  // src/image-generation/ImageDoctorService.ts
10089
10638
  var import_image_generation = require("@omnicross/core/image-generation");
10090
10639
  var import_outbound_api7 = require("@omnicross/core/outbound-api");
10091
- var import_subscriptions9 = require("@omnicross/subscriptions");
10640
+ var import_subscriptions10 = require("@omnicross/subscriptions");
10092
10641
 
10093
10642
  // src/image-generation/FileCodexImageCapabilityEvidenceSource.ts
10094
10643
  var import_node_crypto13 = require("crypto");
@@ -10526,16 +11075,16 @@ function createImageDoctorService(options) {
10526
11075
  paths,
10527
11076
  ttlMs: config.evidenceTtlMs
10528
11077
  }));
10529
- const createLiveVerifier = options.createLiveVerifier ?? ((strategy, config) => (0, import_subscriptions9.createCodexImageLiveVerifier)({
11078
+ const createLiveVerifier = options.createLiveVerifier ?? ((strategy, config) => (0, import_subscriptions10.createCodexImageLiveVerifier)({
10530
11079
  authStrategy: strategy,
10531
11080
  generationTimeoutMs: config.queue.generationTimeoutMs
10532
11081
  }));
10533
- const readAccount = async () => {
10534
- const codex = (await options.subscriptionAccounts.listAll()).find((entry) => entry.providerId === "codex");
11082
+ const readAccount = async (providerId) => {
11083
+ const entry = (await options.subscriptionAccounts.listAll()).find((candidate) => candidate.providerId === providerId);
10535
11084
  return Object.freeze({
10536
- present: codex !== void 0,
10537
- usable: codex?.credentialStatus.ok === true,
10538
- reason: codex === void 0 ? "missing" : codex.credentialStatus.ok ? "ready" : "unavailable"
11085
+ present: entry !== void 0,
11086
+ usable: entry?.credentialStatus.ok === true,
11087
+ reason: entry === void 0 ? "missing" : entry.credentialStatus.ok ? "ready" : "unavailable"
10539
11088
  });
10540
11089
  };
10541
11090
  const activePaths = () => options.storageCatalog.active().resolver;
@@ -10573,6 +11122,7 @@ function createImageDoctorService(options) {
10573
11122
  } catch {
10574
11123
  storesValid = false;
10575
11124
  }
11125
+ const antigravityAccount = await readAccount("antigravity");
10576
11126
  const rows = await options.keyDb.outboundApiKeysList();
10577
11127
  let legacyRows = 0;
10578
11128
  let invalidRows = 0;
@@ -10589,7 +11139,7 @@ function createImageDoctorService(options) {
10589
11139
  invalidRows += 1;
10590
11140
  }
10591
11141
  }
10592
- const account = await readAccount();
11142
+ const account = await readAccount("codex");
10593
11143
  let evidence;
10594
11144
  let evidenceStore;
10595
11145
  try {
@@ -10603,10 +11153,11 @@ function createImageDoctorService(options) {
10603
11153
  return Object.freeze({
10604
11154
  config: Object.freeze({
10605
11155
  enabled: config.enabled,
10606
- provider: config.provider,
11156
+ provider: config.models[config.defaultModel] ?? "codex-subscription",
10607
11157
  model: config.defaultModel,
10608
11158
  valid: configErrors.length === 0,
10609
- errorCount: configErrors.length
11159
+ errorCount: configErrors.length,
11160
+ routedProviders: Object.freeze([...new Set(Object.values(config.models))])
10610
11161
  }),
10611
11162
  roots: Object.freeze({
10612
11163
  valid: verifiedAreas === ROOT_AREAS.length,
@@ -10631,12 +11182,13 @@ function createImageDoctorService(options) {
10631
11182
  imagesAuthorizedRows
10632
11183
  }),
10633
11184
  account,
11185
+ antigravityAccount,
10634
11186
  evidence: Object.freeze(evidence)
10635
11187
  });
10636
11188
  },
10637
11189
  verifyLive: async (config, signal) => {
10638
11190
  if (!config.enabled) return Object.freeze({ ok: false, code: "images_disabled" });
10639
- const account = await readAccount();
11191
+ const account = await readAccount("codex");
10640
11192
  if (!account.usable) {
10641
11193
  return Object.freeze({ ok: false, code: "codex_account_unavailable" });
10642
11194
  }
@@ -10888,7 +11440,7 @@ var ImageCleanupService = class {
10888
11440
  var import_node_crypto16 = require("crypto");
10889
11441
  var import_image_generation5 = require("@omnicross/core/image-generation");
10890
11442
  var import_outbound_api8 = require("@omnicross/core/outbound-api");
10891
- var import_subscriptions10 = require("@omnicross/subscriptions");
11443
+ var import_subscriptions11 = require("@omnicross/subscriptions");
10892
11444
 
10893
11445
  // src/image-generation/ImageApiRuntimeResolver.ts
10894
11446
  var import_node_crypto14 = require("crypto");
@@ -10916,10 +11468,11 @@ function createTrustedImageApiRuntimeResolver(options) {
10916
11468
  throw new TypeError("enabled image remote loading requires a proven resolver");
10917
11469
  }
10918
11470
  const hmacKey = Buffer.from(options.hmacKey);
10919
- const modelAliases = new Map(Object.entries(options.config.modelAliases));
11471
+ const modelAliases = new Map(Object.entries(options.config.aliases));
11472
+ const modelRoutes = new Map(Object.entries(options.config.models));
10920
11473
  const limits = Object.freeze({ ...options.config.limits });
10921
- const providerId = options.config.provider;
10922
11474
  const defaultModel = options.config.defaultModel;
11475
+ const providerId = modelRoutes.get(defaultModel) ?? "codex-subscription";
10923
11476
  const referenceStore = options.referenceStore;
10924
11477
  const retention = Object.freeze({
10925
11478
  enabled: true,
@@ -10940,6 +11493,7 @@ function createTrustedImageApiRuntimeResolver(options) {
10940
11493
  providerId,
10941
11494
  defaultModel,
10942
11495
  modelAliases,
11496
+ modelRoutes,
10943
11497
  limits,
10944
11498
  ...preferredAccountId ? { preferredAccountId } : {},
10945
11499
  ...preferredAccountGroup ? { preferredAccountGroup } : {},
@@ -11341,7 +11895,9 @@ var GENERATION_ID = /^[A-Za-z0-9][A-Za-z0-9_.:-]{0,127}$/u;
11341
11895
  function snapshotConfig(config) {
11342
11896
  return {
11343
11897
  ...config,
11344
- modelAliases: { ...config.modelAliases },
11898
+ models: { ...config.models },
11899
+ aliases: { ...config.aliases },
11900
+ codex: { ...config.codex },
11345
11901
  account: { ...config.account },
11346
11902
  queue: { ...config.queue },
11347
11903
  temporary: { ...config.temporary },
@@ -11375,10 +11931,15 @@ function createImageRuntimeGeneration(options) {
11375
11931
  }
11376
11932
  });
11377
11933
  }
11378
- const authStrategy = options.subscriptionAccounts.getStrategy("codex");
11379
- if (!authStrategy || authStrategy.providerId !== "codex") {
11934
+ const routedProviders = [...new Set(Object.values(config.models))];
11935
+ const codexStrategy = routedProviders.includes("codex-subscription") ? options.subscriptionAccounts.getStrategy("codex") : void 0;
11936
+ if (routedProviders.includes("codex-subscription") && (!codexStrategy || codexStrategy.providerId !== "codex")) {
11380
11937
  throw new TypeError("enabled image runtime requires the Codex subscription strategy");
11381
11938
  }
11939
+ const antigravityStrategy = routedProviders.includes("antigravity-subscription") ? options.subscriptionAccounts.getStrategy("antigravity") : void 0;
11940
+ if (routedProviders.includes("antigravity-subscription") && (!antigravityStrategy || antigravityStrategy.providerId !== "antigravity")) {
11941
+ throw new TypeError("enabled image runtime requires the Antigravity subscription strategy");
11942
+ }
11382
11943
  const privateHmacKey = options.privateHmacKey ? Buffer.from(options.privateHmacKey) : loadOrCreateImageTenantHmacSalt(options.storage.paths, import_node_crypto16.randomBytes);
11383
11944
  if (privateHmacKey.byteLength !== 32) {
11384
11945
  privateHmacKey.fill(0);
@@ -11413,23 +11974,32 @@ function createImageRuntimeGeneration(options) {
11413
11974
  if (options.testOnlySyntheticVerifiedProvider && options.testOnlySyntheticVerifiedProvider.label !== "synthetic-verified-image-provider-test-only") {
11414
11975
  throw new TypeError("synthetic verified image provider test seam label is invalid");
11415
11976
  }
11416
- const provider = options.testOnlySyntheticVerifiedProvider ? options.testOnlySyntheticVerifiedProvider.createProvider({
11977
+ const providers = options.testOnlySyntheticVerifiedProvider ? [options.testOnlySyntheticVerifiedProvider.createProvider({
11417
11978
  generationId: options.generationId,
11418
11979
  scheduler,
11419
11980
  now: options.now ?? Date.now,
11420
11981
  referenceStore: options.storage.referenceStore,
11421
11982
  stateStore: options.storage.stateStore
11422
- }) : (0, import_subscriptions10.createCodexSubscriptionImageProvider)({
11423
- authStrategy,
11983
+ })] : routedProviders.map((providerId) => providerId === "codex-subscription" ? (0, import_subscriptions11.createCodexSubscriptionImageProvider)({
11984
+ authStrategy: codexStrategy,
11424
11985
  evidenceSource: generationEvidenceSource,
11425
11986
  executionScheduler: scheduler,
11426
11987
  generationTimeoutMs: config.queue.generationTimeoutMs,
11988
+ now: options.now,
11989
+ wire: {
11990
+ imageModel: config.codex.imageModel,
11991
+ carrierModel: config.codex.carrierModel
11992
+ }
11993
+ }) : (0, import_subscriptions11.createAntigravitySubscriptionImageProvider)({
11994
+ authStrategy: antigravityStrategy,
11995
+ executionScheduler: scheduler,
11996
+ generationTimeoutMs: config.queue.generationTimeoutMs,
11427
11997
  now: options.now
11428
- });
11429
- if (provider.id !== config.provider) {
11998
+ }));
11999
+ if (providers.length === 1 && providers[0].id !== "codex-subscription") {
11430
12000
  throw new TypeError("synthetic verified image provider id must match configured provider");
11431
12001
  }
11432
- const providerRegistry = new import_image_generation5.ImageProviderRegistry([provider]);
12002
+ const providerRegistry = new import_image_generation5.ImageProviderRegistry(providers);
11433
12003
  const orchestrator = new import_image_generation5.ImageOrchestrator({
11434
12004
  registry: providerRegistry,
11435
12005
  referenceStore: options.storage.referenceStore,
@@ -11451,35 +12021,53 @@ function createImageRuntimeGeneration(options) {
11451
12021
  ...options.createCallId ? { createCallId: options.createCallId } : {},
11452
12022
  ...options.now ? { now: options.now } : {}
11453
12023
  });
12024
+ const defaultProviderId = config.models[config.defaultModel] ?? "codex-subscription";
12025
+ const inspectOneProvider = async (providerId, apiKeyId) => {
12026
+ const capabilities = await orchestrator.getCapabilities(providerId, {
12027
+ requestId: `${options.generationId}:capability-inspection`,
12028
+ tenantId: apiKeyId,
12029
+ signal: new AbortController().signal,
12030
+ sessionKey: `outbound:images:${apiKeyId}`,
12031
+ ...config.account.id ? { preferredAccountId: config.account.id } : {},
12032
+ ...config.account.group ? { preferredAccountGroup: config.account.group } : {},
12033
+ boundAccountFallbackPolicy: config.account.fallback
12034
+ });
12035
+ return capabilities;
12036
+ };
11454
12037
  const inspectCapability = async (apiKeyId) => {
11455
- try {
11456
- const capabilities = await orchestrator.getCapabilities(config.provider, {
11457
- requestId: `${options.generationId}:capability-inspection`,
11458
- tenantId: apiKeyId,
11459
- signal: new AbortController().signal,
11460
- sessionKey: `outbound:images:${apiKeyId}`,
11461
- ...config.account.id ? { preferredAccountId: config.account.id } : {},
11462
- ...config.account.group ? { preferredAccountGroup: config.account.group } : {},
11463
- boundAccountFallbackPolicy: config.account.fallback
11464
- });
11465
- const available = capabilities.available === true && capabilities.generate === true && capabilities.models.includes(config.defaultModel);
11466
- return Object.freeze({
11467
- enabled: true,
11468
- available,
11469
- providerId: config.provider,
11470
- model: config.defaultModel,
11471
- ...!available ? { reason: capabilities.reason ?? "runtime_unavailable" } : {},
11472
- capabilities
11473
- });
11474
- } catch (error) {
12038
+ const providerCapabilities = /* @__PURE__ */ new Map();
12039
+ let defaultProviderError;
12040
+ for (const providerId of [...new Set(Object.values(config.models))]) {
12041
+ try {
12042
+ providerCapabilities.set(providerId, await inspectOneProvider(providerId, apiKeyId));
12043
+ } catch (error) {
12044
+ if (providerId === defaultProviderId) defaultProviderError = error;
12045
+ }
12046
+ }
12047
+ const routedModels = Object.freeze(
12048
+ [...providerCapabilities.entries()].flatMap(([providerId, capabilities2]) => capabilities2.available === true && capabilities2.generate === true ? Object.entries(config.models).filter(([model, modelProvider]) => modelProvider === providerId && capabilities2.models.includes(model)).map(([model]) => model) : [])
12049
+ );
12050
+ const capabilities = providerCapabilities.get(defaultProviderId);
12051
+ if (!capabilities) {
11475
12052
  return Object.freeze({
11476
12053
  enabled: true,
11477
12054
  available: false,
11478
- providerId: config.provider,
12055
+ providerId: defaultProviderId,
11479
12056
  model: config.defaultModel,
11480
- reason: error instanceof import_image_generation5.ImageGenerationError && (error.code === "upstream_auth_required" || error.code === "invalid_api_key") ? "account_unverified" : "runtime_unavailable"
12057
+ routedModels,
12058
+ reason: defaultProviderError instanceof import_image_generation5.ImageGenerationError && (defaultProviderError.code === "upstream_auth_required" || defaultProviderError.code === "invalid_api_key") ? "account_unverified" : "runtime_unavailable"
11481
12059
  });
11482
12060
  }
12061
+ const available = capabilities.available === true && capabilities.generate === true && capabilities.models.includes(config.defaultModel);
12062
+ return Object.freeze({
12063
+ enabled: true,
12064
+ available,
12065
+ providerId: defaultProviderId,
12066
+ model: config.defaultModel,
12067
+ routedModels,
12068
+ ...!available ? { reason: capabilities.reason ?? "runtime_unavailable" } : {},
12069
+ capabilities
12070
+ });
11483
12071
  };
11484
12072
  const resolverToDispose = runtimeResolver;
11485
12073
  const schedulerToDispose = scheduler;
@@ -11517,7 +12105,7 @@ function createImageRuntimeGeneration(options) {
11517
12105
  imageApi,
11518
12106
  hosted,
11519
12107
  hostedRuntime: Object.freeze({
11520
- providerId: config.provider,
12108
+ providerId: defaultProviderId,
11521
12109
  imageModel: config.defaultModel,
11522
12110
  referenceTtlMs: config.references.ttlMs,
11523
12111
  maxOutputBytes: config.limits.maxOutputBytes,
@@ -14460,6 +15048,9 @@ var ImageRuntimeManager = class {
14460
15048
  }
14461
15049
  async listAvailableModels(apiKeyId) {
14462
15050
  const inspection = await this.inspectCapability(apiKeyId);
15051
+ if (inspection.routedModels !== void 0) {
15052
+ return Object.freeze([...inspection.routedModels]);
15053
+ }
14463
15054
  return inspection.available && inspection.model === "gpt-image-2" ? Object.freeze([inspection.model]) : Object.freeze([]);
14464
15055
  }
14465
15056
  resourceStatus() {
@@ -16647,11 +17238,12 @@ var JsonVoucherDb = class {
16647
17238
  // src/ports/JsonSubscriptionCredentialStore.ts
16648
17239
  var import_node_fs24 = require("fs");
16649
17240
  var import_node_path24 = require("path");
17241
+ var import_GeminiCodeAssistProjectResolver5 = require("@omnicross/core/auth/GeminiCodeAssistProjectResolver");
16650
17242
  var import_SubscriptionAccountHealth2 = require("@omnicross/core/pipeline/SubscriptionAccountHealth");
16651
17243
  var import_AccountAllowanceScheduling3 = require("@omnicross/core/pipeline/AccountAllowanceScheduling");
16652
- var import_upstreamFetch12 = require("@omnicross/core/pipeline/upstreamFetch");
17244
+ var import_upstreamFetch14 = require("@omnicross/core/pipeline/upstreamFetch");
16653
17245
  var import_SubscriptionIdentityStore2 = require("@omnicross/core/provider-proxy/identity/SubscriptionIdentityStore");
16654
- var import_subscriptions11 = require("@omnicross/subscriptions");
17246
+ var import_subscriptions12 = require("@omnicross/subscriptions");
16655
17247
 
16656
17248
  // src/ports/account-sync.ts
16657
17249
  function viewOf(tokens) {
@@ -16799,7 +17391,7 @@ var JsonSubscriptionCredentialStore = class {
16799
17391
  * a plaintext token pair into `upstream-trace.jsonl`.
16800
17392
  */
16801
17393
  buildRefreshFetch(providerId, accountId) {
16802
- return this.fetchImpl ?? ((url, init) => (0, import_upstreamFetch12.fetchUpstream)(url, init, { providerId, accountId, redactBodies: true }));
17394
+ return this.fetchImpl ?? ((url, init) => (0, import_upstreamFetch14.fetchUpstream)(url, init, { providerId, accountId, redactBodies: true }));
16803
17395
  }
16804
17396
  /**
16805
17397
  * In-flight refresh coalescing. OAuth refresh tokens are
@@ -16840,7 +17432,7 @@ var JsonSubscriptionCredentialStore = class {
16840
17432
  * other hot reads. Never returns token material.
16841
17433
  */
16842
17434
  getAccountProxy(providerId, accountId) {
16843
- if (providerId !== "claude" && providerId !== "codex" && providerId !== "gemini" && providerId !== "opencodego" && providerId !== "kimi" && providerId !== "grok" && providerId !== "copilot") {
17435
+ if (providerId !== "claude" && providerId !== "codex" && providerId !== "gemini" && providerId !== "opencodego" && providerId !== "kimi" && providerId !== "grok" && providerId !== "copilot" && providerId !== "antigravity") {
16844
17436
  return void 0;
16845
17437
  }
16846
17438
  return getAccountProxy(this.readConfig(), providerId, accountId);
@@ -16859,7 +17451,7 @@ var JsonSubscriptionCredentialStore = class {
16859
17451
  const fingerprintOn = identityStore.isEnabled();
16860
17452
  const now = Date.now();
16861
17453
  const out = {};
16862
- for (const provider of ["claude", "codex", "gemini", "opencodego", "kimi", "grok", "copilot"]) {
17454
+ for (const provider of ["claude", "codex", "gemini", "opencodego", "kimi", "grok", "copilot", "antigravity"]) {
16863
17455
  const sanitized = sanitizeAccounts(config, provider);
16864
17456
  if (sanitized.length === 0) continue;
16865
17457
  for (const account of sanitized) {
@@ -16925,7 +17517,7 @@ var JsonSubscriptionCredentialStore = class {
16925
17517
  this.materializeMigration(config);
16926
17518
  const refreshFetch = this.buildRefreshFetch("claude", capturedId);
16927
17519
  try {
16928
- const result = await import_subscriptions11.claudeOAuth.refreshAccessToken(claude.refreshToken, refreshFetch);
17520
+ const result = await import_subscriptions12.claudeOAuth.refreshAccessToken(claude.refreshToken, refreshFetch);
16929
17521
  const expiresAt = new Date(Date.now() + result.expiresIn * 1e3).toISOString();
16930
17522
  const next = {
16931
17523
  ...claude,
@@ -16960,7 +17552,7 @@ var JsonSubscriptionCredentialStore = class {
16960
17552
  this.materializeMigration(config);
16961
17553
  const refreshFetch = this.buildRefreshFetch("codex", capturedId);
16962
17554
  try {
16963
- const result = await import_subscriptions11.codexOAuth.refreshAccessToken(codex.refreshToken, refreshFetch);
17555
+ const result = await import_subscriptions12.codexOAuth.refreshAccessToken(codex.refreshToken, refreshFetch);
16964
17556
  const expiresAt = new Date(Date.now() + result.expiresIn * 1e3).toISOString();
16965
17557
  const next = {
16966
17558
  ...codex,
@@ -16998,7 +17590,7 @@ var JsonSubscriptionCredentialStore = class {
16998
17590
  this.materializeMigration(config);
16999
17591
  const refreshFetch = this.buildRefreshFetch("gemini", capturedId);
17000
17592
  try {
17001
- const result = await import_subscriptions11.geminiOAuth.refreshAccessToken(gemini.refreshToken, refreshFetch);
17593
+ const result = await import_subscriptions12.geminiOAuth.refreshAccessToken(gemini.refreshToken, refreshFetch);
17002
17594
  const expiresAt = new Date(Date.now() + result.expiresIn * 1e3).toISOString();
17003
17595
  const next = {
17004
17596
  ...gemini,
@@ -17034,10 +17626,10 @@ var JsonSubscriptionCredentialStore = class {
17034
17626
  this.materializeMigration(config);
17035
17627
  const refreshFetch = this.buildRefreshFetch("kimi", capturedId);
17036
17628
  try {
17037
- const result = await import_subscriptions11.kimiOAuth.refreshAccessToken(
17629
+ const result = await import_subscriptions12.kimiOAuth.refreshAccessToken(
17038
17630
  kimi.refreshToken,
17039
17631
  refreshFetch,
17040
- import_subscriptions11.kimiOAuth.kimiFingerprintHeaders(kimi.deviceId)
17632
+ import_subscriptions12.kimiOAuth.kimiFingerprintHeaders(kimi.deviceId)
17041
17633
  );
17042
17634
  const expiresAt = new Date(Date.now() + result.expiresIn * 1e3).toISOString();
17043
17635
  const next = {
@@ -17074,8 +17666,8 @@ var JsonSubscriptionCredentialStore = class {
17074
17666
  this.materializeMigration(config);
17075
17667
  const refreshFetch = this.buildRefreshFetch("grok", capturedId);
17076
17668
  try {
17077
- const tokenEndpoint = await import_subscriptions11.grokOAuth.resolveGrokTokenEndpoint(refreshFetch);
17078
- const result = await import_subscriptions11.grokOAuth.refreshGrokAccessToken(grok.refreshToken, tokenEndpoint, refreshFetch);
17669
+ const tokenEndpoint = await import_subscriptions12.grokOAuth.resolveGrokTokenEndpoint(refreshFetch);
17670
+ const result = await import_subscriptions12.grokOAuth.refreshGrokAccessToken(grok.refreshToken, tokenEndpoint, refreshFetch);
17079
17671
  const expiresAt = new Date(Date.now() + result.expiresIn * 1e3).toISOString();
17080
17672
  const next = {
17081
17673
  ...grok,
@@ -17118,6 +17710,76 @@ var JsonSubscriptionCredentialStore = class {
17118
17710
  return false;
17119
17711
  });
17120
17712
  }
17713
+ /**
17714
+ * Refresh the Antigravity (Google) OAuth access token. Like gemini, the
17715
+ * Google token endpoint does NOT return a refresh_token on refresh, so this
17716
+ * writes ONLY access+expiresAt (+status/lastRefreshedAt) and DELIBERATELY
17717
+ * preserves the stored `refreshToken` — plus the account's `projectId`
17718
+ * (a handshake product; the post-refresh re-validation is the refresh
17719
+ * scheduler's hook, not this write) and `email`. HONEST `false` when no
17720
+ * refresh_token.
17721
+ */
17722
+ async refreshAntigravityToken() {
17723
+ return this.coalesce("antigravity:active", async () => {
17724
+ const config = this.readConfig();
17725
+ const active = getActiveAccount(config, "antigravity");
17726
+ const antigravity = active?.tokens;
17727
+ if (!active || !antigravity?.refreshToken) return false;
17728
+ const capturedId = active.id;
17729
+ this.materializeMigration(config);
17730
+ const refreshFetch = this.buildRefreshFetch("antigravity", capturedId);
17731
+ try {
17732
+ const result = await import_subscriptions12.antigravityOAuth.refreshAccessToken(antigravity.refreshToken, refreshFetch);
17733
+ const expiresAt = new Date(Date.now() + result.expiresIn * 1e3).toISOString();
17734
+ const next = {
17735
+ ...antigravity,
17736
+ // KEEP the existing refreshToken/projectId/email.
17737
+ accessToken: result.accessToken,
17738
+ expiresAt,
17739
+ status: "authorized",
17740
+ lastRefreshedAt: (/* @__PURE__ */ new Date()).toISOString(),
17741
+ errorMessage: void 0
17742
+ };
17743
+ this.writeBackById("antigravity", capturedId, next);
17744
+ await this.revalidateAntigravityProject(capturedId);
17745
+ return true;
17746
+ } catch (error) {
17747
+ this.markExpiredById("antigravity", capturedId, antigravity, error);
17748
+ return false;
17749
+ }
17750
+ });
17751
+ }
17752
+ /**
17753
+ * Post-refresh project re-validation hook (antigravity design D8): after a
17754
+ * successful antigravity token refresh, re-run the Code Assist project
17755
+ * handshake and write the (possibly rotated) `projectId` back to the account.
17756
+ * A handshake FAILURE keeps the stored projectId untouched (logged) so the
17757
+ * account keeps serving with the last-known-good project until a later
17758
+ * refresh succeeds. Returns whether the handshake produced a project.
17759
+ */
17760
+ async revalidateAntigravityProject(accountId) {
17761
+ const before = getAccountById(this.readConfig(), "antigravity", accountId);
17762
+ const accessToken = before?.tokens?.accessToken;
17763
+ if (!accessToken) return false;
17764
+ try {
17765
+ const projectId = await (0, import_GeminiCodeAssistProjectResolver5.getAntigravityProjectResolver)().resolveProject(accessToken);
17766
+ if (projectId !== void 0) {
17767
+ const config = this.readConfig();
17768
+ const account = getAccountById(config, "antigravity", accountId);
17769
+ const tokens = account?.tokens;
17770
+ if (account && tokens?.accessToken === accessToken && tokens.projectId !== projectId) {
17771
+ this.writeBackById("antigravity", accountId, { ...tokens, projectId });
17772
+ }
17773
+ return true;
17774
+ }
17775
+ return false;
17776
+ } catch (error) {
17777
+ console.warn(
17778
+ `[JsonSubscriptionCredentialStore] antigravity project re-validation failed for account ${accountId}: ` + (error instanceof Error ? error.message : String(error))
17779
+ );
17780
+ return false;
17781
+ }
17782
+ }
17121
17783
  /**
17122
17784
  * Refresh a SPECIFIC managed account by id (background scheduler sweep and
17123
17785
  * account-pool resolution). It uses only that account's stored refresh
@@ -17146,6 +17808,7 @@ var JsonSubscriptionCredentialStore = class {
17146
17808
  };
17147
17809
  if (refreshed.idToken) next.idToken = refreshed.idToken;
17148
17810
  this.writeBackById(provider, id, next);
17811
+ if (provider === "antigravity") await this.revalidateAntigravityProject(id);
17149
17812
  return true;
17150
17813
  } catch (error) {
17151
17814
  this.markExpiredById(provider, id, captured, error);
@@ -17170,7 +17833,7 @@ var JsonSubscriptionCredentialStore = class {
17170
17833
  }
17171
17834
  const oauth = account.tokens;
17172
17835
  if (!oauth.accessToken) return null;
17173
- if (providerId === "codex" || providerId === "gemini" || providerId === "kimi" || providerId === "grok" || providerId === "copilot") {
17836
+ if (providerId === "codex" || providerId === "gemini" || providerId === "kimi" || providerId === "grok" || providerId === "copilot" || providerId === "antigravity") {
17174
17837
  const expiresAtMs = oauth.expiresAt ? Date.parse(oauth.expiresAt) : 0;
17175
17838
  const expiringSoon = expiresAtMs > 0 && Date.now() >= expiresAtMs - ACCOUNT_REFRESH_LEAD_MS;
17176
17839
  if (expiringSoon && oauth.refreshToken) {
@@ -17263,10 +17926,10 @@ var JsonSubscriptionCredentialStore = class {
17263
17926
  if (provider === "kimi") {
17264
17927
  const account = accountId ? getAccountById(this.readConfig(), "kimi", accountId) : void 0;
17265
17928
  const deviceId = account?.tokens?.deviceId;
17266
- const r2 = await import_subscriptions11.kimiOAuth.refreshAccessToken(
17929
+ const r2 = await import_subscriptions12.kimiOAuth.refreshAccessToken(
17267
17930
  refreshToken,
17268
17931
  refreshFetch,
17269
- import_subscriptions11.kimiOAuth.kimiFingerprintHeaders(deviceId)
17932
+ import_subscriptions12.kimiOAuth.kimiFingerprintHeaders(deviceId)
17270
17933
  );
17271
17934
  return {
17272
17935
  accessToken: r2.accessToken,
@@ -17275,8 +17938,8 @@ var JsonSubscriptionCredentialStore = class {
17275
17938
  };
17276
17939
  }
17277
17940
  if (provider === "grok") {
17278
- const tokenEndpoint = await import_subscriptions11.grokOAuth.resolveGrokTokenEndpoint(refreshFetch);
17279
- const r2 = await import_subscriptions11.grokOAuth.refreshGrokAccessToken(refreshToken, tokenEndpoint, refreshFetch);
17941
+ const tokenEndpoint = await import_subscriptions12.grokOAuth.resolveGrokTokenEndpoint(refreshFetch);
17942
+ const r2 = await import_subscriptions12.grokOAuth.refreshGrokAccessToken(refreshToken, tokenEndpoint, refreshFetch);
17280
17943
  return {
17281
17944
  accessToken: r2.accessToken,
17282
17945
  refreshToken: r2.refreshToken,
@@ -17286,7 +17949,14 @@ var JsonSubscriptionCredentialStore = class {
17286
17949
  if (provider === "copilot") {
17287
17950
  throw new Error("GitHub Copilot tokens cannot be refreshed \u2014 re-authenticate the account");
17288
17951
  }
17289
- const flow = provider === "claude" ? import_subscriptions11.claudeOAuth : provider === "codex" ? import_subscriptions11.codexOAuth : import_subscriptions11.geminiOAuth;
17952
+ if (provider === "antigravity") {
17953
+ const r2 = await import_subscriptions12.antigravityOAuth.refreshAccessToken(refreshToken, refreshFetch);
17954
+ return {
17955
+ accessToken: r2.accessToken,
17956
+ expiresAt: new Date(Date.now() + r2.expiresIn * 1e3).toISOString()
17957
+ };
17958
+ }
17959
+ const flow = provider === "claude" ? import_subscriptions12.claudeOAuth : provider === "codex" ? import_subscriptions12.codexOAuth : import_subscriptions12.geminiOAuth;
17290
17960
  const r = await flow.refreshAccessToken(refreshToken, refreshFetch);
17291
17961
  return {
17292
17962
  accessToken: r.accessToken,
@@ -17529,7 +18199,7 @@ var JsonSubscriptionCredentialStore = class {
17529
18199
  };
17530
18200
 
17531
18201
  // src/AccountHealthProbeScheduler.ts
17532
- var import_upstreamFetch13 = require("@omnicross/core/pipeline/upstreamFetch");
18202
+ var import_upstreamFetch15 = require("@omnicross/core/pipeline/upstreamFetch");
17533
18203
 
17534
18204
  // src/probe/CodexGenerationProbe.ts
17535
18205
  var import_codexCliHeaders = require("@omnicross/core/provider-proxy/identity/codexCliHeaders");
@@ -17681,7 +18351,11 @@ var PROVIDER_PROBE_PLANS = {
17681
18351
  // The Copilot quota endpoint (copilot_internal/user) is a verified FREE
17682
18352
  // authed GET but lives on api.github.com with its own auth dialect and a
17683
18353
  // monthly-only window — the allowance collector owns the health surface.
17684
- copilot: { kind: "local" }
18354
+ copilot: { kind: "local" },
18355
+ // Antigravity's quota endpoints are POST RPCs on daily-cloudcode-pa (not a
18356
+ // cheap GET) and need the antigravity/hub UA — the allowance collector owns
18357
+ // the health surface; the probe stays local.
18358
+ antigravity: { kind: "local" }
17685
18359
  };
17686
18360
  function probePlanFor(providerId) {
17687
18361
  return PROVIDER_PROBE_PLANS[providerId] ?? { kind: "local" };
@@ -17703,7 +18377,7 @@ var AccountHealthProbeScheduler = class {
17703
18377
  this.logger = logger;
17704
18378
  this.config = config;
17705
18379
  this.now = opts.now ?? Date.now;
17706
- this.fetchImpl = opts.fetchImpl ?? import_upstreamFetch13.fetchUpstream;
18380
+ this.fetchImpl = opts.fetchImpl ?? import_upstreamFetch15.fetchUpstream;
17707
18381
  this.sleep = opts.sleep ?? ((ms) => new Promise((r) => setTimeout(r, ms)));
17708
18382
  this.planFor = opts.planFor ?? probePlanFor;
17709
18383
  }
@@ -19401,7 +20075,7 @@ var AuditWriter = class {
19401
20075
  var import_node_fs33 = require("fs");
19402
20076
  var import_node_crypto24 = require("crypto");
19403
20077
  var import_node_path33 = require("path");
19404
- var import_upstreamFetch14 = require("@omnicross/core/pipeline/upstreamFetch");
20078
+ var import_upstreamFetch16 = require("@omnicross/core/pipeline/upstreamFetch");
19405
20079
 
19406
20080
  // src/billing/billingFiles.ts
19407
20081
  var BILLING_FILE_RE = /^billing-(\d{4})-(\d{2})-(\d{2})\.jsonl$/;
@@ -19424,7 +20098,7 @@ var BillingPublisher = class {
19424
20098
  constructor(billingDir, logger, opts = {}) {
19425
20099
  this.billingDir = billingDir;
19426
20100
  this.logger = logger;
19427
- this.fetchImpl = opts.fetchImpl ?? ((url, init) => (0, import_upstreamFetch14.fetchUpstream)(url, init));
20101
+ this.fetchImpl = opts.fetchImpl ?? ((url, init) => (0, import_upstreamFetch16.fetchUpstream)(url, init));
19428
20102
  this.defer = opts.defer ?? ((fn) => setTimeout(fn, 0));
19429
20103
  this.timeoutMs = opts.timeoutMs ?? BILLING_POST_TIMEOUT_MS;
19430
20104
  this.now = opts.now ?? Date.now;
@@ -19674,7 +20348,7 @@ var BillingRetrySweeper = class {
19674
20348
  // src/TokenRefreshScheduler.ts
19675
20349
  var REFRESH_LEAD_MS2 = 5 * 6e4;
19676
20350
  var SWEEP_INTERVAL_MS5 = 6e4;
19677
- var OAUTH_PROVIDERS2 = ["claude", "codex", "gemini", "kimi", "grok", "copilot"];
20351
+ var OAUTH_PROVIDERS2 = ["claude", "codex", "gemini", "kimi", "grok", "copilot", "antigravity"];
19678
20352
  var TokenRefreshScheduler = class {
19679
20353
  constructor(store, logger, intervalMs = SWEEP_INTERVAL_MS5, leadMs = REFRESH_LEAD_MS2) {
19680
20354
  this.store = store;
@@ -19765,6 +20439,8 @@ var TokenRefreshScheduler = class {
19765
20439
  // never reaches this — the branch exists for union totality.
19766
20440
  case "copilot":
19767
20441
  return this.store.refreshCopilotToken();
20442
+ case "antigravity":
20443
+ return this.store.refreshAntigravityToken();
19768
20444
  }
19769
20445
  }
19770
20446
  };
@@ -19841,7 +20517,7 @@ function createRouteLeaseSubscriptionPreflight(credentials) {
19841
20517
 
19842
20518
  // src/webhook/WebhookDispatcher.ts
19843
20519
  var import_node_crypto25 = require("crypto");
19844
- var import_upstreamFetch15 = require("@omnicross/core/pipeline/upstreamFetch");
20520
+ var import_upstreamFetch17 = require("@omnicross/core/pipeline/upstreamFetch");
19845
20521
  var WEBHOOK_MAX_ATTEMPTS = 3;
19846
20522
  var WEBHOOK_QUEUE_MAX = 1e3;
19847
20523
  var WEBHOOK_SEND_TIMEOUT_MS = 1e4;
@@ -19861,7 +20537,7 @@ var WebhookDispatcher = class {
19861
20537
  sleep;
19862
20538
  now;
19863
20539
  constructor(opts = {}) {
19864
- this.fetchImpl = opts.fetchImpl ?? ((url, init) => (0, import_upstreamFetch15.fetchUpstream)(url, init));
20540
+ this.fetchImpl = opts.fetchImpl ?? ((url, init) => (0, import_upstreamFetch17.fetchUpstream)(url, init));
19865
20541
  this.logger = opts.logger;
19866
20542
  this.maxAttempts = opts.maxAttempts ?? WEBHOOK_MAX_ATTEMPTS;
19867
20543
  this.queueMax = opts.queueMax ?? WEBHOOK_QUEUE_MAX;
@@ -19947,8 +20623,8 @@ var WebhookDispatcher = class {
19947
20623
  signal: AbortSignal.timeout(this.timeoutMs)
19948
20624
  });
19949
20625
  return res.ok ? { ok: true, status: res.status } : { ok: false, status: res.status };
19950
- } catch (err8) {
19951
- return { ok: false, error: err8 instanceof Error ? err8.message : String(err8) };
20626
+ } catch (err9) {
20627
+ return { ok: false, error: err9 instanceof Error ? err9.message : String(err9) };
19952
20628
  }
19953
20629
  }
19954
20630
  /**
@@ -20090,12 +20766,12 @@ function buildDaemon(config, paths) {
20090
20766
  setSecretBox(secretBox3);
20091
20767
  setSecretBox2(secretBox3);
20092
20768
  const decryptedConfig = decryptConfigSecrets(config, secretBox3);
20093
- const accountAllowanceStore = new import_AccountAllowanceStore10.AccountAllowanceStore(
20769
+ const accountAllowanceStore = new import_AccountAllowanceStore11.AccountAllowanceStore(
20094
20770
  Date.now,
20095
20771
  void 0,
20096
20772
  new JsonAccountAllowancePersistence(defaultAccountAllowancePath(paths.configPath))
20097
20773
  );
20098
- (0, import_AccountAllowanceStore10.setSharedAccountAllowanceStore)(accountAllowanceStore);
20774
+ (0, import_AccountAllowanceStore11.setSharedAccountAllowanceStore)(accountAllowanceStore);
20099
20775
  (0, import_AccountAllowanceScheduling5.getSharedAccountAllowanceScheduling)().configure(
20100
20776
  (0, import_outbound_api10.normalizeServerConfig)(decryptedConfig.server).allowanceScheduling
20101
20777
  );
@@ -20120,20 +20796,22 @@ function buildDaemon(config, paths) {
20120
20796
  claudeAllowanceRefreshScheduler.configure(
20121
20797
  (0, import_outbound_api10.normalizeServerConfig)(decryptedConfig.server).allowanceScheduling
20122
20798
  );
20123
- const subscriptionAccounts = new import_subscriptions12.SubscriptionAccountService(credentialStore);
20124
- (0, import_subscriptions12.setSubscriptionAccountService)(subscriptionAccounts);
20125
- const subscriptionRegistry = new import_subscriptions12.SubscriptionProviderRegistry(
20799
+ const subscriptionAccounts = new import_subscriptions13.SubscriptionAccountService(credentialStore);
20800
+ (0, import_subscriptions13.setSubscriptionAccountService)(subscriptionAccounts);
20801
+ const subscriptionRegistry = new import_subscriptions13.SubscriptionProviderRegistry(
20126
20802
  subscriptionAccounts,
20127
20803
  credentialStore
20128
20804
  );
20129
- (0, import_subscriptions12.setSubscriptionProviderRegistry)(subscriptionRegistry);
20805
+ (0, import_subscriptions13.setSubscriptionProviderRegistry)(subscriptionRegistry);
20130
20806
  setServerProxyConfig(decryptedConfig.server?.proxy);
20131
- (0, import_upstreamFetch16.setUpstreamProxyResolver)(
20807
+ (0, import_upstreamFetch18.setUpstreamProxyResolver)(
20132
20808
  createUpstreamProxyResolver({
20133
20809
  getAccountProxy: (providerId, accountId) => credentialStore.getAccountProxy(providerId, accountId)
20134
20810
  })
20135
20811
  );
20136
- (0, import_gemini_code_assist_resolver.setGeminiCodeAssistResolver)((0, import_GeminiCodeAssistProjectResolver2.getGeminiCodeAssistProjectResolver)());
20812
+ (0, import_gemini_code_assist_resolver.setGeminiCodeAssistResolver)((0, import_GeminiCodeAssistProjectResolver6.getGeminiCodeAssistProjectResolver)());
20813
+ (0, import_antigravityFailover.setAntigravitySandboxFailover)(decryptedConfig.antigravity?.sandboxFailover === true);
20814
+ (0, import_openCodeGoHeaders2.setOpenCodeGoUserAgent)(decryptedConfig.opencodego?.userAgent ?? null);
20137
20815
  const autoDisableStore = new AutoDisableStore();
20138
20816
  const providerKeyQuotaService = new ProviderKeyQuotaService(secretBox3);
20139
20817
  const apiKeyPool = new import_ApiKeyPoolService.ApiKeyPoolService(
@@ -20152,7 +20830,7 @@ function buildDaemon(config, paths) {
20152
20830
  const pricingEngine = new import_usage2.PricingEngine(pricingStore, logger, {
20153
20831
  // Catalog egress follows the same global/env proxy policy as every other
20154
20832
  // daemon upstream call; no provider/account override applies here.
20155
- fetchImpl: ((input, init) => (0, import_upstreamFetch16.fetchUpstream)(String(input), init ?? {}))
20833
+ fetchImpl: ((input, init) => (0, import_upstreamFetch18.fetchUpstream)(String(input), init ?? {}))
20156
20834
  });
20157
20835
  const pricingRefreshScheduler = new PricingRefreshScheduler(
20158
20836
  pricingEngine,
@@ -20437,7 +21115,7 @@ function buildDaemon(config, paths) {
20437
21115
  // — `server.proxy.byProvider[...]` was silently skipped — and the call was
20438
21116
  // excluded from the upstream trace, so a failing login left no evidence.
20439
21117
  // `redactBodies` keeps the code/verifier + minted token out of that trace.
20440
- oauthExchangeFetch: paths.oauthExchangeFetch ? () => paths.oauthExchangeFetch : (providerId) => (url, init) => (0, import_upstreamFetch16.fetchUpstream)(url, init, { providerId, redactBodies: true }),
21118
+ oauthExchangeFetch: paths.oauthExchangeFetch ? () => paths.oauthExchangeFetch : (providerId) => (url, init) => (0, import_upstreamFetch18.fetchUpstream)(url, init, { providerId, redactBodies: true }),
20441
21119
  subscriptionAccountAppender: credentialStore,
20442
21120
  // Codex interactive OAuth (app-parity-2 child 5) — the async loopback flow store
20443
21121
  // + the one-shot 127.0.0.1:1455 listener. Token captured + persisted daemon-side;
@@ -20452,6 +21130,21 @@ function buildDaemon(config, paths) {
20452
21130
  // Grok interactive OAuth — the same async DEVICE-CODE shape as kimi.
20453
21131
  grokSessions: new CodexOAuthSessionStore(),
20454
21132
  copilotSessions: new CodexOAuthSessionStore(),
21133
+ // Antigravity interactive OAuth — the async LOOPBACK flow store + the
21134
+ // one-shot 127.0.0.1:51121 listener (same shape as codex; test seam below).
21135
+ antigravitySessions: new CodexOAuthSessionStore(),
21136
+ antigravityAwaitLoopback: paths.antigravityAwaitLoopback ?? ((state, timeoutMs, signal) => awaitLoopbackCode(state, timeoutMs, signal, {
21137
+ port: 51121,
21138
+ path: "/oauth-callback",
21139
+ label: "antigravity"
21140
+ })),
21141
+ // The dynamic model-catalog probe's token source (the ACTIVE antigravity
21142
+ // account; refreshed by the by-id near-expiry seam inside the lookup).
21143
+ resolveAntigravityAccessToken: async () => {
21144
+ const config2 = await credentialStore.getFullConfig();
21145
+ const activeId = config2.activeAntigravityAccountId ?? config2.antigravityAccounts?.[0]?.id;
21146
+ return activeId ? credentialStore.getAccessTokenForAccount("antigravity", activeId) : null;
21147
+ },
20455
21148
  // Migration pack (app-parity child 6, design D2/D3) — the concrete credential
20456
21149
  // store provides BOTH the full DECRYPTED read (`getFullConfig`, export) and
20457
21150
  // the multi-account append (`appendProviderAccount`, import re-encrypts at-
@@ -20510,7 +21203,7 @@ function buildDaemon(config, paths) {
20510
21203
  });
20511
21204
  const webhookDispatcher = new WebhookDispatcher({
20512
21205
  logger,
20513
- fetchImpl: (url, init) => (0, import_upstreamFetch16.fetchUpstream)(url, init)
21206
+ fetchImpl: (url, init) => (0, import_upstreamFetch18.fetchUpstream)(url, init)
20514
21207
  });
20515
21208
  setWebhookRuntime(webhookDispatcher, (0, import_SubscriptionAccountHealth4.getSharedAccountHealth)());
20516
21209
  const auditWriter = new AuditWriter(auditDir, logger);
@@ -20590,9 +21283,9 @@ function resetDaemonSingletonsForTests() {
20590
21283
  (0, import_provider_proxy4.__resetProviderProxyForTests)();
20591
21284
  (0, import_outbound_api10.__resetOutboundApiServerForTests)();
20592
21285
  (0, import_subscriptionRegistryPort.setSubscriptionRegistryForOutbound)(null);
20593
- (0, import_subscriptions12.setSubscriptionProviderRegistry)(null);
20594
- (0, import_subscriptions12.setSubscriptionAccountService)(null);
20595
- (0, import_upstreamFetch16.setUpstreamProxyResolver)(null);
21286
+ (0, import_subscriptions13.setSubscriptionProviderRegistry)(null);
21287
+ (0, import_subscriptions13.setSubscriptionAccountService)(null);
21288
+ (0, import_upstreamFetch18.setUpstreamProxyResolver)(null);
20596
21289
  setServerProxyConfig(void 0);
20597
21290
  (0, import_gemini_code_assist_resolver.setGeminiCodeAssistResolver)(null);
20598
21291
  setSecretBox(null);
@@ -20601,7 +21294,7 @@ function resetDaemonSingletonsForTests() {
20601
21294
  resetAuditRuntimeForTests();
20602
21295
  resetBillingRuntimeForTests();
20603
21296
  (0, import_SubscriptionIdentityStore3.__resetSharedIdentityStoreForTests)();
20604
- (0, import_AccountAllowanceStore10.__resetSharedAccountAllowanceStoreForTests)();
21297
+ (0, import_AccountAllowanceStore11.__resetSharedAccountAllowanceStoreForTests)();
20605
21298
  (0, import_AccountAllowanceScheduling5.__resetSharedAccountAllowanceSchedulingForTests)();
20606
21299
  (0, import_usage2.__resetSharedUsageThroughputTrackerForTests)();
20607
21300
  }