@omnicross/daemon 0.4.2 → 0.4.4

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.js CHANGED
@@ -18,16 +18,18 @@ import { setSubscriptionRegistryForOutbound } from "@omnicross/core/outbound-api
18
18
  import { getSharedAccountHealth as getSharedAccountHealth4 } from "@omnicross/core/pipeline/SubscriptionAccountHealth";
19
19
  import {
20
20
  __resetSharedAccountAllowanceStoreForTests,
21
- AccountAllowanceStore as AccountAllowanceStore9,
21
+ AccountAllowanceStore as AccountAllowanceStore10,
22
22
  setSharedAccountAllowanceStore
23
23
  } from "@omnicross/core/pipeline/AccountAllowanceStore";
24
24
  import {
25
25
  __resetSharedAccountAllowanceSchedulingForTests,
26
26
  getSharedAccountAllowanceScheduling as getSharedAccountAllowanceScheduling5
27
27
  } from "@omnicross/core/pipeline/AccountAllowanceScheduling";
28
- import { fetchUpstream as fetchUpstream14, setUpstreamProxyResolver } from "@omnicross/core/pipeline/upstreamFetch";
28
+ import { fetchUpstream as fetchUpstream16, setUpstreamProxyResolver } from "@omnicross/core/pipeline/upstreamFetch";
29
29
  import { __resetSharedIdentityStoreForTests } from "@omnicross/core/provider-proxy/identity/SubscriptionIdentityStore";
30
30
  import { setGeminiCodeAssistResolver } from "@omnicross/core/ports/gemini-code-assist-resolver";
31
+ import { setAntigravitySandboxFailover } from "@omnicross/core/transformer/transformers/antigravityFailover";
32
+ import { setOpenCodeGoUserAgent } from "@omnicross/core/provider-proxy/identity/openCodeGoHeaders";
31
33
  import {
32
34
  __resetProviderProxyForTests,
33
35
  createNativeResponsesHostedImageIngress,
@@ -411,7 +413,7 @@ function handleCopilotOAuthStatus(sessionId, deps) {
411
413
 
412
414
  // src/allowance/AccountAllowanceService.ts
413
415
  import {
414
- getSharedAccountAllowanceStore as getSharedAccountAllowanceStore8
416
+ getSharedAccountAllowanceStore as getSharedAccountAllowanceStore9
415
417
  } from "@omnicross/core/pipeline/AccountAllowanceStore";
416
418
  import {
417
419
  getSharedAccountAllowanceScheduling
@@ -1801,11 +1803,328 @@ var GeminiAllowanceCollector = class {
1801
1803
  }
1802
1804
  };
1803
1805
 
1804
- // src/allowance/OpenCodeGoAllowanceCollector.ts
1806
+ // src/allowance/AntigravityAllowanceCollector.ts
1807
+ import { ANTIGRAVITY_CODE_ASSIST_ENDPOINT } from "@omnicross/core/auth/GeminiCodeAssistProjectResolver";
1808
+ import {
1809
+ ANTIGRAVITY_COUNTER_TO_MODEL_FAMILY,
1810
+ antigravityCounterFamiliesForBucketId
1811
+ } from "@omnicross/core/pipeline/antigravityQuotaFamily";
1805
1812
  import {
1806
1813
  getSharedAccountAllowanceStore as getSharedAccountAllowanceStore7
1807
1814
  } from "@omnicross/core/pipeline/AccountAllowanceStore";
1808
1815
  import { fetchUpstream as fetchUpstream7 } from "@omnicross/core/pipeline/upstreamFetch";
1816
+ import { getAntigravityUserAgent } from "@omnicross/core/transformer/transformers/antigravityIdentity";
1817
+ var ANTIGRAVITY_ALLOWANCE_CACHE_MS = 5 * 6e4;
1818
+ var RETRIEVE_USER_QUOTA_SUMMARY_PATH = "/v1internal:retrieveUserQuotaSummary";
1819
+ var FETCH_AVAILABLE_MODELS_PATH = "/v1internal:fetchAvailableModels";
1820
+ var ANTIGRAVITY_DISCOVERY_DENYLIST = /* @__PURE__ */ new Set([
1821
+ "chat_20706",
1822
+ "chat_23310",
1823
+ "gemini-2.5-pro"
1824
+ ]);
1825
+ function isRecord5(value) {
1826
+ return !!value && typeof value === "object" && !Array.isArray(value);
1827
+ }
1828
+ function secondsUntil7(instant, now) {
1829
+ if (!instant) return void 0;
1830
+ return Math.max(0, Math.floor((Date.parse(instant) - now) / 1e3));
1831
+ }
1832
+ var WINDOW_LABELS = {
1833
+ "five-hour": "5 Hour",
1834
+ weekly: "Weekly",
1835
+ daily: "Daily"
1836
+ };
1837
+ function classifyWindowId(...sources) {
1838
+ for (const source of sources) {
1839
+ if (!source) continue;
1840
+ const text = source.toLowerCase();
1841
+ if (text.includes("week") || text.includes("7d") || /7[\s_-]*day/.test(text)) return "weekly";
1842
+ if (text.includes("5h") || text.includes("five hour") || /5[\s_-]*hour/.test(text)) return "five-hour";
1843
+ if (text.includes("day") || text.includes("daily") || text.includes("24h")) return "daily";
1844
+ }
1845
+ return void 0;
1846
+ }
1847
+ function inferWindowFromReset(resetsAt, now) {
1848
+ if (resetsAt !== void 0 && Date.parse(resetsAt) - now > 24 * 60 * 60 * 1e3) return "weekly";
1849
+ return "daily";
1850
+ }
1851
+ function clampFraction(value) {
1852
+ if (value === void 0 || !Number.isFinite(value)) return void 0;
1853
+ return Math.min(1, Math.max(0, value));
1854
+ }
1855
+ function usedPercentFromFraction(fraction) {
1856
+ const clamped = clampFraction(fraction);
1857
+ if (clamped === void 0) return null;
1858
+ return Math.round((1 - clamped) * 1e3) / 10;
1859
+ }
1860
+ function toResetsAt(resetTime) {
1861
+ if (!resetTime || !Number.isFinite(Date.parse(resetTime))) return void 0;
1862
+ return new Date(Date.parse(resetTime)).toISOString();
1863
+ }
1864
+ function parseAntigravityQuotaSummary(payload, now) {
1865
+ if (!isRecord5(payload)) return null;
1866
+ const groups = Array.isArray(payload["groups"]) ? payload["groups"] : [];
1867
+ const topBuckets = Array.isArray(payload["buckets"]) ? payload["buckets"] : [];
1868
+ const hasGrouped = groups.some((group) => Array.isArray(group.buckets) && group.buckets.length > 0);
1869
+ if (!hasGrouped && topBuckets.length === 0) return null;
1870
+ const windows = /* @__PURE__ */ new Map();
1871
+ const addBucket = (bucket, groupName) => {
1872
+ const families = antigravityCounterFamiliesForBucketId(bucket.bucketId, groupName);
1873
+ if (families.length === 0) return;
1874
+ const resetsAt = toResetsAt(bucket.resetTime);
1875
+ const windowId = classifyWindowId(bucket.window, bucket.displayName, bucket.bucketId) ?? (resetsAt !== void 0 ? inferWindowFromReset(resetsAt, now) : void 0);
1876
+ if (windowId === void 0) return;
1877
+ const usedPercent = usedPercentFromFraction(bucket.remainingFraction) ?? (bucket.disabled === true || bucket.resetTime ? bucket.disabled === true ? 100 : null : null);
1878
+ for (const family of families) {
1879
+ const id = `antigravity:${family}:${windowId}`;
1880
+ const candidate = {
1881
+ id,
1882
+ label: `${WINDOW_LABELS[windowId]} (${family})`,
1883
+ scope: "model-family",
1884
+ // The window carries the MODEL family (gemini/claude/gpt-oss) — the
1885
+ // scheduling gate compares it against the requested model's family.
1886
+ modelFamily: ANTIGRAVITY_COUNTER_TO_MODEL_FAMILY[family],
1887
+ usedPercent,
1888
+ ...resetsAt !== void 0 ? { resetsAt } : {},
1889
+ remainingSeconds: secondsUntil7(resetsAt, now),
1890
+ state: "fresh",
1891
+ ...bucket.disabled === true ? { disabled: true } : {}
1892
+ };
1893
+ const existing = windows.get(id);
1894
+ if (!existing || candidate.disabled === true || existing.disabled !== true && (candidate.usedPercent ?? -1) > (existing.usedPercent ?? -1)) {
1895
+ windows.set(id, candidate);
1896
+ }
1897
+ }
1898
+ };
1899
+ if (hasGrouped) {
1900
+ for (const group of groups) {
1901
+ for (const bucket of group.buckets ?? []) addBucket(bucket, group.displayName);
1902
+ }
1903
+ } else {
1904
+ for (const bucket of topBuckets) addBucket(bucket);
1905
+ }
1906
+ const result = [...windows.values()];
1907
+ return result.length > 0 ? result : null;
1908
+ }
1909
+ function legacyQuotaInfos(model) {
1910
+ const out = [];
1911
+ const source = {
1912
+ ...model.apiProvider ? { apiProvider: model.apiProvider } : {},
1913
+ ...model.modelProvider ? { modelProvider: model.modelProvider } : {}
1914
+ };
1915
+ const add = (value, windowDefault) => {
1916
+ if (!value) return;
1917
+ const list = Array.isArray(value) ? value : [value];
1918
+ for (const info of list) {
1919
+ out.push({ ...source, ...windowDefault ? { windowId: windowDefault } : {}, ...info });
1920
+ }
1921
+ };
1922
+ add(model.quotaInfo);
1923
+ add(model.quotaInfos);
1924
+ add(model.dailyQuotaInfo, "daily");
1925
+ add(model.dailyQuotaInfos, "daily");
1926
+ add(model.weeklyQuotaInfo, "weekly");
1927
+ add(model.weeklyQuotaInfos, "weekly");
1928
+ return out;
1929
+ }
1930
+ function legacyCounterFamily(info) {
1931
+ switch (info.modelProvider ?? info.apiProvider) {
1932
+ case "MODEL_PROVIDER_ANTHROPIC":
1933
+ case "API_PROVIDER_ANTHROPIC_VERTEX":
1934
+ return "anthropic";
1935
+ case "MODEL_PROVIDER_GOOGLE":
1936
+ case "API_PROVIDER_GOOGLE_GEMINI":
1937
+ return "google";
1938
+ case "MODEL_PROVIDER_OPENAI":
1939
+ case "API_PROVIDER_OPENAI_VERTEX":
1940
+ return "openai";
1941
+ default:
1942
+ return void 0;
1943
+ }
1944
+ }
1945
+ function parseAntigravityLegacyQuota(payload, now) {
1946
+ if (!isRecord5(payload)) return null;
1947
+ const models = payload["models"];
1948
+ if (!isRecord5(models)) return null;
1949
+ const windows = /* @__PURE__ */ new Map();
1950
+ for (const info of Object.values(models).flatMap(legacyQuotaInfos)) {
1951
+ const family = legacyCounterFamily(info);
1952
+ if (!family) continue;
1953
+ const resetsAt = toResetsAt(info.resetTime);
1954
+ const windowId = classifyWindowId(info.windowId, info.windowLabel) ?? (resetsAt !== void 0 ? inferWindowFromReset(resetsAt, now) : void 0);
1955
+ if (windowId === void 0) continue;
1956
+ const id = `antigravity:${family}:${windowId}`;
1957
+ const candidate = {
1958
+ id,
1959
+ label: `${WINDOW_LABELS[windowId]} (${family})`,
1960
+ scope: "model-family",
1961
+ modelFamily: ANTIGRAVITY_COUNTER_TO_MODEL_FAMILY[family],
1962
+ usedPercent: usedPercentFromFraction(info.remainingFraction),
1963
+ ...resetsAt !== void 0 ? { resetsAt } : {},
1964
+ remainingSeconds: secondsUntil7(resetsAt, now),
1965
+ state: "fresh"
1966
+ };
1967
+ const existing = windows.get(id);
1968
+ if (!existing || (candidate.usedPercent ?? -1) > (existing.usedPercent ?? -1)) {
1969
+ windows.set(id, candidate);
1970
+ }
1971
+ }
1972
+ const result = [...windows.values()];
1973
+ return result.length > 0 ? result : null;
1974
+ }
1975
+ var AntigravityAllowanceCollector = class {
1976
+ constructor(credentials, store = getSharedAccountAllowanceStore7(), fetchImpl = (url, init, accountId) => fetchUpstream7(url, init, { providerId: "antigravity", accountId, redactBodies: true }), now = Date.now) {
1977
+ this.credentials = credentials;
1978
+ this.store = store;
1979
+ this.fetchImpl = fetchImpl;
1980
+ this.now = now;
1981
+ }
1982
+ credentials;
1983
+ store;
1984
+ fetchImpl;
1985
+ now;
1986
+ inFlight = /* @__PURE__ */ new Map();
1987
+ async collectMany(accounts, options = {}) {
1988
+ const settled = await Promise.allSettled(
1989
+ accounts.map((account) => this.collect(account, options))
1990
+ );
1991
+ return settled.flatMap((result) => result.status === "fulfilled" ? [result.value] : []);
1992
+ }
1993
+ collect(account, options = {}) {
1994
+ const now = this.now();
1995
+ if (account.tokens.authMethod !== "oauth") {
1996
+ const existing = this.store.get("antigravity", account.id, now);
1997
+ if (existing?.windows.every((window) => window.state === "unsupported")) {
1998
+ return Promise.resolve(existing);
1999
+ }
2000
+ const snapshot = this.unsupportedSnapshot(account.id, now);
2001
+ this.store.set(snapshot);
2002
+ return Promise.resolve(snapshot);
2003
+ }
2004
+ const cached = this.store.get("antigravity", account.id, now);
2005
+ if (!options.force && cached && this.isCacheValid(cached, now, options.refreshAheadMs)) {
2006
+ return Promise.resolve(cached);
2007
+ }
2008
+ const running = this.inFlight.get(account.id);
2009
+ if (running) return running;
2010
+ const promise = this.fetchAccount(account.id).catch(() => this.failureSnapshot(account.id, "antigravity_usage_request_failed", this.now())).finally(() => this.inFlight.delete(account.id));
2011
+ this.inFlight.set(account.id, promise);
2012
+ return promise;
2013
+ }
2014
+ isCacheValid(snapshot, now, refreshAheadMs) {
2015
+ if (snapshot.windows.every((window) => window.state === "unsupported")) return true;
2016
+ const expiresAt = snapshot.expiresAt ? Date.parse(snapshot.expiresAt) : 0;
2017
+ const ahead = typeof refreshAheadMs === "number" && Number.isFinite(refreshAheadMs) ? Math.max(0, refreshAheadMs) : 0;
2018
+ return Number.isFinite(expiresAt) && expiresAt > now + ahead;
2019
+ }
2020
+ async fetchAccount(accountId) {
2021
+ let accessToken = await this.credentials.getAccessTokenForAccount("antigravity", accountId);
2022
+ if (!accessToken) return this.failureSnapshot(accountId, "antigravity_usage_token_unavailable", this.now());
2023
+ let response = await this.request(accountId, accessToken, RETRIEVE_USER_QUOTA_SUMMARY_PATH, {
2024
+ project: void 0
2025
+ });
2026
+ if (response.status === 401 || response.status === 403) {
2027
+ const refreshed = await this.credentials.refreshAccountToken("antigravity", accountId);
2028
+ if (!refreshed) return this.failureSnapshot(accountId, "antigravity_usage_unauthorized", this.now());
2029
+ accessToken = await this.credentials.getAccessTokenForAccount("antigravity", accountId);
2030
+ if (!accessToken) return this.failureSnapshot(accountId, "antigravity_usage_token_unavailable", this.now());
2031
+ response = await this.request(accountId, accessToken, RETRIEVE_USER_QUOTA_SUMMARY_PATH, {
2032
+ project: void 0
2033
+ });
2034
+ if (response.status === 401 || response.status === 403) {
2035
+ return this.failureSnapshot(accountId, "antigravity_usage_unauthorized", this.now());
2036
+ }
2037
+ }
2038
+ if (response.ok) {
2039
+ const payload = await response.json().catch(() => null);
2040
+ const windows = parseAntigravityQuotaSummary(payload, this.now());
2041
+ if (windows) {
2042
+ const snapshot2 = this.snapshot(accountId, windows);
2043
+ this.store.set(snapshot2);
2044
+ return snapshot2;
2045
+ }
2046
+ }
2047
+ const legacy = await this.request(accountId, accessToken, FETCH_AVAILABLE_MODELS_PATH, {});
2048
+ if (!legacy.ok) {
2049
+ return this.failureSnapshot(accountId, "antigravity_usage_http_error", this.now());
2050
+ }
2051
+ const legacyPayload = await legacy.json().catch(() => null);
2052
+ const legacyWindows = parseAntigravityLegacyQuota(legacyPayload, this.now());
2053
+ if (!legacyWindows) {
2054
+ return this.failureSnapshot(accountId, "antigravity_usage_invalid_response", this.now());
2055
+ }
2056
+ const snapshot = this.snapshot(accountId, legacyWindows);
2057
+ this.store.set(snapshot);
2058
+ return snapshot;
2059
+ }
2060
+ /** One upstream round-trip with the antigravity/hub masquerade UA. */
2061
+ request(accountId, accessToken, path2, body) {
2062
+ return this.fetchImpl(`${ANTIGRAVITY_CODE_ASSIST_ENDPOINT}${path2}`, {
2063
+ method: "POST",
2064
+ headers: {
2065
+ Authorization: `Bearer ${accessToken}`,
2066
+ Accept: "application/json",
2067
+ "Content-Type": "application/json",
2068
+ "User-Agent": getAntigravityUserAgent()
2069
+ },
2070
+ body: JSON.stringify(body),
2071
+ signal: AbortSignal.timeout(15e3)
2072
+ }, accountId);
2073
+ }
2074
+ snapshot(accountId, windows, now = this.now()) {
2075
+ return {
2076
+ providerId: "antigravity",
2077
+ accountId,
2078
+ source: "oauth-usage-api",
2079
+ observedAt: new Date(now).toISOString(),
2080
+ expiresAt: new Date(now + ANTIGRAVITY_ALLOWANCE_CACHE_MS).toISOString(),
2081
+ windows
2082
+ };
2083
+ }
2084
+ failureSnapshot(accountId, code, now) {
2085
+ const existing = this.store.get("antigravity", accountId, now);
2086
+ const snapshot = existing ? {
2087
+ ...existing,
2088
+ expiresAt: new Date(now + ANTIGRAVITY_ALLOWANCE_CACHE_MS).toISOString(),
2089
+ windows: existing.windows.map((window) => ({
2090
+ ...window,
2091
+ state: window.state === "unsupported" ? "unsupported" : window.usedPercent !== null || window.resetsAt || window.disabled ? "stale" : "unavailable"
2092
+ })),
2093
+ lastErrorCode: code
2094
+ } : {
2095
+ providerId: "antigravity",
2096
+ accountId,
2097
+ source: "oauth-usage-api",
2098
+ observedAt: new Date(now).toISOString(),
2099
+ expiresAt: new Date(now + ANTIGRAVITY_ALLOWANCE_CACHE_MS).toISOString(),
2100
+ windows: [
2101
+ { id: "antigravity-quota", label: "Antigravity quota", scope: "all", usedPercent: null, state: "unavailable" }
2102
+ ],
2103
+ lastErrorCode: code
2104
+ };
2105
+ this.store.set(snapshot);
2106
+ return snapshot;
2107
+ }
2108
+ unsupportedSnapshot(accountId, now) {
2109
+ return {
2110
+ providerId: "antigravity",
2111
+ accountId,
2112
+ source: "oauth-usage-api",
2113
+ observedAt: new Date(now).toISOString(),
2114
+ windows: [
2115
+ { id: "antigravity-quota", label: "Antigravity quota", scope: "all", usedPercent: null, state: "unsupported" }
2116
+ ],
2117
+ lastErrorCode: "antigravity_usage_unsupported_auth"
2118
+ };
2119
+ }
2120
+ };
2121
+
2122
+ // src/allowance/OpenCodeGoAllowanceCollector.ts
2123
+ import {
2124
+ getSharedAccountAllowanceStore as getSharedAccountAllowanceStore8
2125
+ } from "@omnicross/core/pipeline/AccountAllowanceStore";
2126
+ import { fetchUpstream as fetchUpstream8 } from "@omnicross/core/pipeline/upstreamFetch";
2127
+ import { getOpenCodeGoUserAgent } from "@omnicross/core/provider-proxy/identity/openCodeGoHeaders";
1809
2128
  import { normalizeOpenCodeGoBaseUrl } from "@omnicross/subscriptions";
1810
2129
  var OPENCODEGO_ALLOWANCE_CACHE_MS = 5 * 6e4;
1811
2130
  var OPENCODEGO_DEFAULT_GO_BASE = "https://opencode.ai/zen/go";
@@ -1819,7 +2138,7 @@ function isoInstant2(value) {
1819
2138
  const time = Date.parse(value);
1820
2139
  return Number.isFinite(time) ? new Date(time).toISOString() : void 0;
1821
2140
  }
1822
- function secondsUntil7(instant, now) {
2141
+ function secondsUntil8(instant, now) {
1823
2142
  if (!instant) return void 0;
1824
2143
  return Math.max(0, Math.floor((Date.parse(instant) - now) / 1e3));
1825
2144
  }
@@ -1834,12 +2153,12 @@ function windowFromPayload3(id, label, minutes, payload, now) {
1834
2153
  usedPercent,
1835
2154
  windowMinutes: minutes,
1836
2155
  ...resetsAt !== void 0 ? { resetsAt } : {},
1837
- remainingSeconds: secondsUntil7(resetsAt, now),
2156
+ remainingSeconds: secondsUntil8(resetsAt, now),
1838
2157
  state: usedPercent !== null || resetsAt ? "fresh" : "unavailable"
1839
2158
  };
1840
2159
  }
1841
2160
  var OpenCodeGoAllowanceCollector = class {
1842
- constructor(credentials, store = getSharedAccountAllowanceStore7(), fetchImpl = (url, init, accountId) => fetchUpstream7(url, init, { providerId: "opencodego", accountId, redactBodies: true }), now = Date.now) {
2161
+ constructor(credentials, store = getSharedAccountAllowanceStore8(), fetchImpl = (url, init, accountId) => fetchUpstream8(url, init, { providerId: "opencodego", accountId, redactBodies: true }), now = Date.now) {
1843
2162
  this.credentials = credentials;
1844
2163
  this.store = store;
1845
2164
  this.fetchImpl = fetchImpl;
@@ -1872,7 +2191,14 @@ var OpenCodeGoAllowanceCollector = class {
1872
2191
  const base = account.tokens.baseUrl ? normalizeOpenCodeGoBaseUrl(account.tokens.baseUrl) : OPENCODEGO_DEFAULT_GO_BASE;
1873
2192
  const response = await this.fetchImpl(`${base}/v1/usage`, {
1874
2193
  method: "GET",
1875
- headers: { Authorization: `Bearer ${apiKey}`, Accept: "application/json" },
2194
+ // opencodego-egress-identity: the background poll identifies itself with
2195
+ // the same configured/default UA the relay carries (no session header —
2196
+ // a poll has no conversation).
2197
+ headers: {
2198
+ Authorization: `Bearer ${apiKey}`,
2199
+ Accept: "application/json",
2200
+ "User-Agent": getOpenCodeGoUserAgent()
2201
+ },
1876
2202
  signal: AbortSignal.timeout(15e3)
1877
2203
  }, account.id);
1878
2204
  if (response.status === 401 || response.status === 403) {
@@ -1944,7 +2270,7 @@ function codexUnavailable(accountId, now) {
1944
2270
  };
1945
2271
  }
1946
2272
  var AccountAllowanceService = class {
1947
- constructor(credentials, store = getSharedAccountAllowanceStore8(), collector, codexCollector, kimiCollector, opencodegoCollector, grokCollector, copilotCollector, geminiCollector, now = Date.now) {
2273
+ constructor(credentials, store = getSharedAccountAllowanceStore9(), collector, codexCollector, kimiCollector, opencodegoCollector, grokCollector, copilotCollector, geminiCollector, antigravityCollector, now = Date.now) {
1948
2274
  this.credentials = credentials;
1949
2275
  this.store = store;
1950
2276
  this.now = now;
@@ -1955,6 +2281,7 @@ var AccountAllowanceService = class {
1955
2281
  this.grokCollector = grokCollector ?? new GrokAllowanceCollector(credentials, store);
1956
2282
  this.copilotCollector = copilotCollector ?? new CopilotAllowanceCollector(credentials, store);
1957
2283
  this.geminiCollector = geminiCollector ?? new GeminiAllowanceCollector(credentials, store);
2284
+ this.antigravityCollector = antigravityCollector ?? new AntigravityAllowanceCollector(credentials, store);
1958
2285
  }
1959
2286
  credentials;
1960
2287
  store;
@@ -1966,6 +2293,7 @@ var AccountAllowanceService = class {
1966
2293
  copilotCollector;
1967
2294
  opencodegoCollector;
1968
2295
  geminiCollector;
2296
+ antigravityCollector;
1969
2297
  /**
1970
2298
  * Read all/filtered snapshots. Claude's and Codex's five-minute caches are
1971
2299
  * refreshed lazily on read (Codex polls `/backend-api/wham/usage`; the
@@ -2014,6 +2342,11 @@ var AccountAllowanceService = class {
2014
2342
  (account) => !filter.accountId || account.id === filter.accountId
2015
2343
  );
2016
2344
  if (wantsGemini) await this.geminiCollector.collectMany(geminiAccounts);
2345
+ const wantsAntigravity = !filter.providerId || filter.providerId === "antigravity";
2346
+ const antigravityAccounts = (config.antigravityAccounts ?? []).filter(
2347
+ (account) => !filter.accountId || account.id === filter.accountId
2348
+ );
2349
+ if (wantsAntigravity) await this.antigravityCollector.collectMany(antigravityAccounts);
2017
2350
  const known = /* @__PURE__ */ new Set();
2018
2351
  if (wantsClaude) for (const account of claudeAccounts) known.add(`claude\0${account.id}`);
2019
2352
  if (wantsCodex) for (const account of codexAccounts) known.add(`codex\0${account.id}`);
@@ -2022,6 +2355,7 @@ var AccountAllowanceService = class {
2022
2355
  if (wantsGrok) for (const account of grokAccounts) known.add(`grok\0${account.id}`);
2023
2356
  if (wantsCopilot) for (const account of copilotAccounts) known.add(`copilot\0${account.id}`);
2024
2357
  if (wantsGemini) for (const account of geminiAccounts) known.add(`gemini\0${account.id}`);
2358
+ if (wantsAntigravity) for (const account of antigravityAccounts) known.add(`antigravity\0${account.id}`);
2025
2359
  return this.store.list(filter).filter((snapshot) => known.has(`${snapshot.providerId}\0${snapshot.accountId}`));
2026
2360
  }
2027
2361
  knownAccounts(config) {
@@ -2032,7 +2366,8 @@ var AccountAllowanceService = class {
2032
2366
  ...(config.opencodegoAccounts ?? []).map((account) => ({ providerId: "opencodego", accountId: account.id })),
2033
2367
  ...(config.grokAccounts ?? []).map((account) => ({ providerId: "grok", accountId: account.id })),
2034
2368
  ...(config.copilotAccounts ?? []).map((account) => ({ providerId: "copilot", accountId: account.id })),
2035
- ...(config.geminiAccounts ?? []).map((account) => ({ providerId: "gemini", accountId: account.id }))
2369
+ ...(config.geminiAccounts ?? []).map((account) => ({ providerId: "gemini", accountId: account.id })),
2370
+ ...(config.antigravityAccounts ?? []).map((account) => ({ providerId: "antigravity", accountId: account.id }))
2036
2371
  ];
2037
2372
  }
2038
2373
  /** Force-refresh Claude usage for one account or every stored Claude account. */
@@ -2102,6 +2437,15 @@ var AccountAllowanceService = class {
2102
2437
  );
2103
2438
  return this.geminiCollector.collectMany(accounts, { force: true });
2104
2439
  }
2440
+ /** Force-refresh Antigravity usage (quotaSummary dual buckets) for one/all accounts. */
2441
+ async refreshAntigravity(accountId) {
2442
+ const config = await this.credentials.getFullConfig();
2443
+ this.store.pruneToKnownAccounts(this.knownAccounts(config));
2444
+ const accounts = (config.antigravityAccounts ?? []).filter(
2445
+ (account) => !accountId || account.id === accountId
2446
+ );
2447
+ return this.antigravityCollector.collectMany(accounts, { force: true });
2448
+ }
2105
2449
  /**
2106
2450
  * Keep Claude + Codex + Kimi snapshots warm for allowance-aware routing. All
2107
2451
  * collectors preserve their cache + per-account in-flight coalescing; a tick
@@ -2119,6 +2463,7 @@ var AccountAllowanceService = class {
2119
2463
  await this.grokCollector.collectMany(config.grokAccounts ?? [], { refreshAheadMs });
2120
2464
  await this.copilotCollector.collectMany(config.copilotAccounts ?? [], { refreshAheadMs });
2121
2465
  await this.geminiCollector.collectMany(config.geminiAccounts ?? [], { refreshAheadMs });
2466
+ await this.antigravityCollector.collectMany(config.antigravityAccounts ?? [], { refreshAheadMs });
2122
2467
  }
2123
2468
  /** Remove a cache row as soon as an account is deleted by the admin path. */
2124
2469
  removeAccountSnapshot(providerId, accountId) {
@@ -2555,7 +2900,7 @@ import {
2555
2900
  } from "@omnicross/contracts/image-generation-types";
2556
2901
  import { getSharedAccountAllowanceScheduling as getSharedAccountAllowanceScheduling2 } from "@omnicross/core/pipeline/AccountAllowanceScheduling";
2557
2902
  import { getSharedAccountHealth } from "@omnicross/core/pipeline/SubscriptionAccountHealth";
2558
- import { fetchUpstream as fetchUpstream8 } from "@omnicross/core/pipeline/upstreamFetch";
2903
+ import { fetchUpstream as fetchUpstream10 } from "@omnicross/core/pipeline/upstreamFetch";
2559
2904
  import { mergeExtraHeaders } from "@omnicross/core";
2560
2905
 
2561
2906
  // src/image-generation/imagesConfigValidation.ts
@@ -3172,7 +3517,11 @@ var TOKEN_FIELDS = {
3172
3517
  claude: ["accessToken", "refreshToken"],
3173
3518
  codex: ["accessToken", "refreshToken", "idToken"],
3174
3519
  gemini: ["accessToken", "refreshToken"],
3175
- opencodego: ["apiKey"]
3520
+ opencodego: ["apiKey"],
3521
+ kimi: ["accessToken", "refreshToken"],
3522
+ grok: ["accessToken", "refreshToken"],
3523
+ copilot: ["accessToken", "refreshToken"],
3524
+ antigravity: ["accessToken", "refreshToken"]
3176
3525
  };
3177
3526
  function transformTokenBlock(block, fields, fn) {
3178
3527
  const next = { ...block };
@@ -3244,6 +3593,19 @@ function resolveAdminConfig(admin) {
3244
3593
  token: typeof admin?.token === "string" && admin.token.length > 0 ? admin.token : void 0
3245
3594
  };
3246
3595
  }
3596
+ function validateAntigravity(raw) {
3597
+ if (!raw || typeof raw !== "object" || Array.isArray(raw)) return void 0;
3598
+ const a = raw;
3599
+ if (typeof a["sandboxFailover"] !== "boolean") return void 0;
3600
+ return { sandboxFailover: a["sandboxFailover"] };
3601
+ }
3602
+ function validateOpenCodeGo(raw) {
3603
+ if (!raw || typeof raw !== "object" || Array.isArray(raw)) return void 0;
3604
+ const o = raw;
3605
+ const ua = o["userAgent"];
3606
+ if (typeof ua !== "string" || ua.trim().length === 0) return void 0;
3607
+ return { userAgent: ua.trim() };
3608
+ }
3247
3609
  function validateUsage(raw) {
3248
3610
  if (!raw || typeof raw !== "object" || Array.isArray(raw)) return void 0;
3249
3611
  const u = raw;
@@ -3537,7 +3899,9 @@ function validateConfig(raw) {
3537
3899
  const admin = validateAdmin(obj["admin"]);
3538
3900
  const logging = validateLogging(obj["logging"]);
3539
3901
  const usage = validateUsage(obj["usage"]);
3540
- return { providers, server, admin, logging };
3902
+ const antigravity = validateAntigravity(obj["antigravity"]);
3903
+ const opencodego = validateOpenCodeGo(obj["opencodego"]);
3904
+ return { providers, server, admin, logging, usage, antigravity, opencodego };
3541
3905
  }
3542
3906
  var secretBox = null;
3543
3907
  function setSecretBox(box) {
@@ -4642,6 +5006,167 @@ function createUpstreamProxyResolver(src = {}) {
4642
5006
  };
4643
5007
  }
4644
5008
 
5009
+ // src/admin/accountsAntigravityOAuth.ts
5010
+ import { getAntigravityProjectResolver } from "@omnicross/core/auth/GeminiCodeAssistProjectResolver";
5011
+ import { antigravityOAuth } from "@omnicross/subscriptions";
5012
+ function err5(status, message) {
5013
+ return { status, body: { error: { type: "admin_api_error", message } } };
5014
+ }
5015
+ var DEFAULT_ANTIGRAVITY_OAUTH_TTL_MS = 10 * 6e4;
5016
+ function handleAntigravityOAuthStart(deps) {
5017
+ if (deps.antigravitySessions.isBusy()) {
5018
+ return err5(
5019
+ 409,
5020
+ "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"
5021
+ );
5022
+ }
5023
+ const { authUrl, state } = antigravityOAuth.generateAuthParams();
5024
+ const { sessionId, signal } = deps.antigravitySessions.begin();
5025
+ void runAntigravityLoopback(sessionId, state, signal, deps);
5026
+ return { status: 200, body: { authUrl, sessionId } };
5027
+ }
5028
+ async function runAntigravityLoopback(sessionId, state, signal, deps) {
5029
+ const isPending = () => !signal.aborted && deps.antigravitySessions.get(sessionId)?.status === "pending";
5030
+ try {
5031
+ const code = await deps.antigravityAwaitLoopback(state, void 0, signal);
5032
+ if (!isPending()) return;
5033
+ const exchangeFetch = deps.oauthExchangeFetch("antigravity");
5034
+ const result = await antigravityOAuth.exchangeCodeForTokens(code, exchangeFetch);
5035
+ if (!isPending()) return;
5036
+ const expiresAt = new Date(Date.now() + result.expiresIn * 1e3).toISOString();
5037
+ const email = await antigravityOAuth.fetchUserEmail(result.accessToken, exchangeFetch);
5038
+ if (!isPending()) return;
5039
+ const projectId = await getAntigravityProjectResolver().resolveProject(result.accessToken);
5040
+ if (!isPending()) return;
5041
+ const block = {
5042
+ authMethod: "oauth",
5043
+ status: "authorized",
5044
+ accessToken: result.accessToken,
5045
+ refreshToken: result.refreshToken,
5046
+ expiresAt,
5047
+ ...email ? { email } : {},
5048
+ ...projectId ? { projectId } : {},
5049
+ lastRefreshedAt: (/* @__PURE__ */ new Date()).toISOString()
5050
+ };
5051
+ await deps.subscriptionAccountAppender.appendProviderAccount("antigravity", block);
5052
+ if (isPending()) deps.antigravitySessions.settle(sessionId, "done");
5053
+ } catch (e) {
5054
+ if (!isPending()) return;
5055
+ const reason = e instanceof Error ? e.message : "antigravity sign-in failed";
5056
+ deps.antigravitySessions.settle(sessionId, "error", reason);
5057
+ }
5058
+ }
5059
+ function handleAntigravityOAuthCancel(sessionId, deps) {
5060
+ if (!deps.antigravitySessions.cancel(sessionId)) {
5061
+ return err5(404, "unknown or expired antigravity sign-in session");
5062
+ }
5063
+ return { status: 200, body: { ok: true } };
5064
+ }
5065
+ function handleAntigravityOAuthStatus(sessionId, deps) {
5066
+ const s = deps.antigravitySessions.get(sessionId);
5067
+ if (!s) return err5(404, "unknown or expired antigravity sign-in session");
5068
+ return { status: 200, body: { state: s.status, ...s.error ? { message: s.error } : {} } };
5069
+ }
5070
+
5071
+ // src/allowance/AntigravityModelDiscovery.ts
5072
+ import { lookupCanonicalCapabilities } from "@omnicross/contracts/canonical-models";
5073
+ import { SUBSCRIPTION_MODEL_CATALOG } from "@omnicross/contracts/subscription-model-catalog";
5074
+ import { ANTIGRAVITY_CODE_ASSIST_ENDPOINT as ANTIGRAVITY_CODE_ASSIST_ENDPOINT2 } from "@omnicross/core/auth/GeminiCodeAssistProjectResolver";
5075
+ import { fetchUpstream as fetchUpstream9 } from "@omnicross/core/pipeline/upstreamFetch";
5076
+ import { getAntigravityUserAgent as getAntigravityUserAgent2 } from "@omnicross/core/transformer/transformers/antigravityIdentity";
5077
+ function isRecord6(value) {
5078
+ return !!value && typeof value === "object" && !Array.isArray(value);
5079
+ }
5080
+ function optionalString(value) {
5081
+ return typeof value === "string" && value.length > 0 ? value : void 0;
5082
+ }
5083
+ function optionalNumber(value) {
5084
+ return typeof value === "number" && Number.isFinite(value) && value > 0 ? value : void 0;
5085
+ }
5086
+ function optionalBoolean(value) {
5087
+ return typeof value === "boolean" ? value : void 0;
5088
+ }
5089
+ function parseAntigravityAvailableModels(payload) {
5090
+ if (!isRecord6(payload)) return [];
5091
+ const models = payload["models"];
5092
+ if (!isRecord6(models)) return [];
5093
+ const out = [];
5094
+ for (const [id, raw] of Object.entries(models)) {
5095
+ if (ANTIGRAVITY_DISCOVERY_DENYLIST.has(id)) continue;
5096
+ if (!isRecord6(raw)) continue;
5097
+ if (raw["isInternal"] === true) continue;
5098
+ out.push({
5099
+ id,
5100
+ ...optionalString(raw["displayName"]) ? { displayName: optionalString(raw["displayName"]) } : {},
5101
+ ...optionalBoolean(raw["supportsImages"]) !== void 0 ? { supportsImages: optionalBoolean(raw["supportsImages"]) } : {},
5102
+ ...optionalBoolean(raw["supportsThinking"]) !== void 0 ? { supportsThinking: optionalBoolean(raw["supportsThinking"]) } : {},
5103
+ ...optionalNumber(raw["thinkingBudget"]) !== void 0 ? { thinkingBudget: optionalNumber(raw["thinkingBudget"]) } : {},
5104
+ ...optionalNumber(raw["maxTokens"]) !== void 0 ? { maxTokens: optionalNumber(raw["maxTokens"]) } : {},
5105
+ ...optionalNumber(raw["maxOutputTokens"]) !== void 0 ? { maxOutputTokens: optionalNumber(raw["maxOutputTokens"]) } : {}
5106
+ });
5107
+ }
5108
+ out.sort((a, b) => a.id.localeCompare(b.id));
5109
+ return out;
5110
+ }
5111
+ function mergeAntigravityCatalog(discovered, log = (line) => console.warn(line), staticIds = SUBSCRIPTION_MODEL_CATALOG.antigravity) {
5112
+ const entries = staticIds.map((id) => {
5113
+ const capabilities = lookupCanonicalCapabilities(id);
5114
+ return {
5115
+ id,
5116
+ origin: "static",
5117
+ displayName: id,
5118
+ ...capabilities?.vision !== void 0 ? { supportsImages: capabilities.vision } : {},
5119
+ ...capabilities?.reasoning !== void 0 ? { supportsThinking: capabilities.reasoning } : {},
5120
+ ...capabilities?.thinkingTokenLimit ? { thinkingBudget: capabilities.thinkingTokenLimit.max } : {},
5121
+ // Discovery calls the context window maxTokens, not the output ceiling.
5122
+ ...capabilities?.contextLength !== void 0 ? { maxTokens: capabilities.contextLength } : {},
5123
+ ...capabilities?.maxTokens !== void 0 ? { maxOutputTokens: capabilities.maxTokens } : {}
5124
+ };
5125
+ });
5126
+ const staticSet = new Set(staticIds);
5127
+ for (const model of discovered) {
5128
+ if (staticSet.has(model.id)) {
5129
+ log(
5130
+ `[AntigravityModelDiscovery] dynamic model '${model.id}' conflicts with the static catalog \u2014 static entry kept`
5131
+ );
5132
+ continue;
5133
+ }
5134
+ entries.push({ ...model, origin: "discovered" });
5135
+ }
5136
+ return entries;
5137
+ }
5138
+ async function fetchAntigravityAvailableModels(accessToken, fetchImpl = (url, init) => fetchUpstream9(url, init, { providerId: "antigravity", redactBodies: true })) {
5139
+ let response;
5140
+ try {
5141
+ response = await fetchImpl(`${ANTIGRAVITY_CODE_ASSIST_ENDPOINT2}/v1internal:fetchAvailableModels`, {
5142
+ method: "POST",
5143
+ headers: {
5144
+ Authorization: `Bearer ${accessToken}`,
5145
+ Accept: "application/json",
5146
+ "Content-Type": "application/json",
5147
+ "User-Agent": getAntigravityUserAgent2()
5148
+ },
5149
+ body: JSON.stringify({}),
5150
+ signal: AbortSignal.timeout(15e3)
5151
+ });
5152
+ } catch {
5153
+ return null;
5154
+ }
5155
+ if (!response.ok) return null;
5156
+ const payload = await response.json().catch(() => null);
5157
+ if (!isRecord6(payload) || !isRecord6(payload["models"])) return null;
5158
+ return parseAntigravityAvailableModels(payload);
5159
+ }
5160
+ async function handleAntigravityModelsRoute(deps) {
5161
+ const accessToken = await deps.resolveAntigravityAccessToken().catch(() => null);
5162
+ const discovered = accessToken ? await fetchAntigravityAvailableModels(accessToken, deps.fetchImpl) : null;
5163
+ const models = mergeAntigravityCatalog(discovered ?? []);
5164
+ return {
5165
+ status: 200,
5166
+ body: { models, discovered: discovered !== null }
5167
+ };
5168
+ }
5169
+
4645
5170
  // src/admin/accountsOAuth.ts
4646
5171
  import { claudeOAuth, geminiOAuth } from "@omnicross/subscriptions";
4647
5172
 
@@ -4653,7 +5178,8 @@ var VALID_PROVIDER_IDS = [
4653
5178
  "opencodego",
4654
5179
  "kimi",
4655
5180
  "grok",
4656
- "copilot"
5181
+ "copilot",
5182
+ "antigravity"
4657
5183
  ];
4658
5184
  function asSubscriptionProviderId(id) {
4659
5185
  return VALID_PROVIDER_IDS.includes(id) ? id : null;
@@ -4835,7 +5361,7 @@ function validateCopilot(body) {
4835
5361
  ]);
4836
5362
  return out;
4837
5363
  }
4838
- function validateOpenCodeGo(body) {
5364
+ function validateOpenCodeGo2(body) {
4839
5365
  const authMethod = str(body["authMethod"]);
4840
5366
  const status = str(body["status"]);
4841
5367
  if (authMethod !== "manual") return null;
@@ -4869,7 +5395,7 @@ function validateTokenBody(providerId, body) {
4869
5395
  case "gemini":
4870
5396
  return validateGemini(body);
4871
5397
  case "opencodego":
4872
- return validateOpenCodeGo(body);
5398
+ return validateOpenCodeGo2(body);
4873
5399
  case "kimi":
4874
5400
  return validateKimi(body);
4875
5401
  case "grok":
@@ -4905,12 +5431,12 @@ async function statusEntryFor(reader, providerId) {
4905
5431
 
4906
5432
  // src/admin/accountsOAuth.ts
4907
5433
  var OAUTH_HTTP_PROVIDERS = /* @__PURE__ */ new Set(["claude", "gemini"]);
4908
- function err5(status, message) {
5434
+ function err6(status, message) {
4909
5435
  return { status, body: { error: { type: "admin_api_error", message } } };
4910
5436
  }
4911
5437
  function handleOAuthStart(providerId, deps) {
4912
5438
  if (!OAUTH_HTTP_PROVIDERS.has(providerId)) {
4913
- return err5(400, `oauth not available for provider '${providerId}'`);
5439
+ return err6(400, `oauth not available for provider '${providerId}'`);
4914
5440
  }
4915
5441
  const flow = providerId === "claude" ? claudeOAuth : geminiOAuth;
4916
5442
  const { authUrl, codeVerifier, state } = flow.generateAuthParams();
@@ -4919,23 +5445,23 @@ function handleOAuthStart(providerId, deps) {
4919
5445
  }
4920
5446
  async function handleOAuthComplete(providerId, body, deps) {
4921
5447
  if (!OAUTH_HTTP_PROVIDERS.has(providerId)) {
4922
- return err5(400, `oauth not available for provider '${providerId}'`);
5448
+ return err6(400, `oauth not available for provider '${providerId}'`);
4923
5449
  }
4924
5450
  const sessionId = typeof body["sessionId"] === "string" ? body["sessionId"] : "";
4925
5451
  const rawCode = typeof body["code"] === "string" ? body["code"] : "";
4926
- if (!sessionId) return err5(400, "oauth complete requires { sessionId }");
4927
- if (!rawCode) return err5(400, "oauth complete requires { code }");
5452
+ if (!sessionId) return err6(400, "oauth complete requires { sessionId }");
5453
+ if (!rawCode) return err6(400, "oauth complete requires { code }");
4928
5454
  const session = deps.oauthSessions.peek(sessionId);
4929
- if (!session) return err5(410, "oauth session is unknown, expired, or already used");
5455
+ if (!session) return err6(410, "oauth session is unknown, expired, or already used");
4930
5456
  if (session.providerId !== providerId) {
4931
- return err5(400, `oauth session does not match provider '${providerId}'`);
5457
+ return err6(400, `oauth session does not match provider '${providerId}'`);
4932
5458
  }
4933
5459
  let code = rawCode.trim();
4934
5460
  if (providerId === "claude") {
4935
5461
  const [splitCode, pastedState] = code.split("#");
4936
- if (!splitCode) return err5(400, "no authorization code was provided");
5462
+ if (!splitCode) return err6(400, "no authorization code was provided");
4937
5463
  if (pastedState && pastedState !== session.state) {
4938
- return err5(400, "oauth state did not match (possible CSRF) \u2014 aborting");
5464
+ return err6(400, "oauth state did not match (possible CSRF) \u2014 aborting");
4939
5465
  }
4940
5466
  code = splitCode;
4941
5467
  }
@@ -4945,7 +5471,7 @@ async function handleOAuthComplete(providerId, body, deps) {
4945
5471
  block = providerId === "claude" ? await exchangeClaude(code, session.codeVerifier, session.state, exchangeFetch) : await exchangeGemini(code, session.codeVerifier, exchangeFetch);
4946
5472
  } catch (exchangeError) {
4947
5473
  const reason = exchangeError instanceof Error ? exchangeError.message : "token exchange failed";
4948
- return err5(502, `oauth token exchange failed for '${providerId}': ${reason}`);
5474
+ return err6(502, `oauth token exchange failed for '${providerId}': ${reason}`);
4949
5475
  }
4950
5476
  deps.oauthSessions.consume(sessionId);
4951
5477
  const label = typeof body["label"] === "string" && body["label"].trim() ? body["label"].trim() : void 0;
@@ -5283,8 +5809,8 @@ function errBody(message) {
5283
5809
  return { error: { type: "admin_api_error", message } };
5284
5810
  }
5285
5811
  var defaultCommandRunner = (command) => new Promise((resolve10) => {
5286
- exec(command, { timeout: 18e4 }, (err8, _stdout, stderr) => {
5287
- if (err8) resolve10({ ok: false, error: stderr.trim() || err8.message });
5812
+ exec(command, { timeout: 18e4 }, (err9, _stdout, stderr) => {
5813
+ if (err9) resolve10({ ok: false, error: stderr.trim() || err9.message });
5288
5814
  else resolve10({ ok: true });
5289
5815
  });
5290
5816
  });
@@ -5330,8 +5856,8 @@ async function handleCliLaunch(cli, body, ctx) {
5330
5856
  providerId: typeof body["providerId"] === "string" ? body["providerId"] : void 0,
5331
5857
  model: typeof body["model"] === "string" ? body["model"] : void 0
5332
5858
  });
5333
- } catch (err8) {
5334
- return { status: 400, body: errBody(err8 instanceof Error ? err8.message : "no launch target") };
5859
+ } catch (err9) {
5860
+ return { status: 400, body: errBody(err9 instanceof Error ? err9.message : "no launch target") };
5335
5861
  }
5336
5862
  const id = randomUUID2();
5337
5863
  let leaseId2;
@@ -5359,9 +5885,9 @@ async function handleCliLaunch(cli, body, ctx) {
5359
5885
  } else {
5360
5886
  launch = await buildLaunchEnv(cli, ctx.llmConfig, target);
5361
5887
  }
5362
- } catch (err8) {
5363
- const status = err8 instanceof RouteLeaseError2 ? err8.status : 400;
5364
- return { status, body: errBody(err8 instanceof Error ? err8.message : "failed to build launch env") };
5888
+ } catch (err9) {
5889
+ const status = err9 instanceof RouteLeaseError2 ? err9.status : 400;
5890
+ return { status, body: errBody(err9 instanceof Error ? err9.message : "failed to build launch env") };
5365
5891
  }
5366
5892
  const cwd = typeof body["cwd"] === "string" && body["cwd"].trim() ? body["cwd"].trim() : void 0;
5367
5893
  const opener = ctx.opener ?? defaultTerminalOpener;
@@ -5389,9 +5915,9 @@ async function handleCliLaunch(cli, body, ctx) {
5389
5915
  onFailure: onSessionEnd
5390
5916
  });
5391
5917
  if (cleanup) openerCleanup = cleanup;
5392
- } catch (err8) {
5918
+ } catch (err9) {
5393
5919
  onSessionEnd();
5394
- return { status: 500, body: errBody(err8 instanceof Error ? err8.message : "failed to open terminal") };
5920
+ return { status: 500, body: errBody(err9 instanceof Error ? err9.message : "failed to open terminal") };
5395
5921
  }
5396
5922
  if (ended) {
5397
5923
  openerCleanup?.();
@@ -5940,7 +6466,7 @@ async function handleSearchQuery(req, res, deps) {
5940
6466
  // src/admin/searchAdminView.ts
5941
6467
  var API_KEY_PROVIDERS = /* @__PURE__ */ new Set(["tavily", "jina", "zhipu", "z.ai"]);
5942
6468
  var BASIC_AUTH_PROVIDERS = /* @__PURE__ */ new Set(["searxng"]);
5943
- function isRecord5(value) {
6469
+ function isRecord7(value) {
5944
6470
  return value !== null && typeof value === "object" && !Array.isArray(value);
5945
6471
  }
5946
6472
  function redactSearchServerConfig(search) {
@@ -5990,13 +6516,13 @@ function resolveSecretField(entry, field, stored) {
5990
6516
  else delete entry[field];
5991
6517
  }
5992
6518
  function preserveSearchSecrets(incoming, current) {
5993
- if (!isRecord5(incoming)) return incoming;
6519
+ if (!isRecord7(incoming)) return incoming;
5994
6520
  const section = { ...incoming };
5995
6521
  const providersValue = section["providers"];
5996
- if (!isRecord5(providersValue)) return section;
6522
+ if (!isRecord7(providersValue)) return section;
5997
6523
  const providers = {};
5998
6524
  for (const [id, entryValue] of Object.entries(providersValue)) {
5999
- if (!isRecord5(entryValue)) {
6525
+ if (!isRecord7(entryValue)) {
6000
6526
  providers[id] = entryValue;
6001
6527
  continue;
6002
6528
  }
@@ -6074,7 +6600,7 @@ function parseKeyPolicyBody(body) {
6074
6600
  var ENDPOINTS = /* @__PURE__ */ new Set(["chat", "responses", "messages", "gemini"]);
6075
6601
  var TARGET_KINDS = /* @__PURE__ */ new Set(["account", "account-group", "account-pool", "provider"]);
6076
6602
  var FALLBACKS = /* @__PURE__ */ new Set(["next", "fail", "global"]);
6077
- function isRecord6(value) {
6603
+ function isRecord8(value) {
6078
6604
  return !!value && typeof value === "object" && !Array.isArray(value);
6079
6605
  }
6080
6606
  function nonBlank(value) {
@@ -6094,7 +6620,7 @@ function validateGatewayBindingsSegment(patch) {
6094
6620
  const ids = /* @__PURE__ */ new Set();
6095
6621
  raw.forEach((entry, index) => {
6096
6622
  const path2 = `bindings[${index}]`;
6097
- if (!isRecord6(entry)) {
6623
+ if (!isRecord8(entry)) {
6098
6624
  errors.push(`${path2} must be an object`);
6099
6625
  return;
6100
6626
  }
@@ -6123,12 +6649,12 @@ function validateGatewayBindingsSegment(patch) {
6123
6649
  } else if (entry.modelMappings.length > 100) {
6124
6650
  errors.push(`${path2}.modelMappings cannot contain more than 100 entries`);
6125
6651
  } else if (entry.modelMappings.some(
6126
- (mapping) => !isRecord6(mapping) || !nonBlank(mapping.source) || !nonBlank(mapping.target)
6652
+ (mapping) => !isRecord8(mapping) || !nonBlank(mapping.source) || !nonBlank(mapping.target)
6127
6653
  )) {
6128
6654
  errors.push(`${path2}.modelMappings must contain non-empty source and target strings`);
6129
6655
  }
6130
6656
  }
6131
- if (!isRecord6(entry.target) || !TARGET_KINDS.has(String(entry.target.kind))) {
6657
+ if (!isRecord8(entry.target) || !TARGET_KINDS.has(String(entry.target.kind))) {
6132
6658
  errors.push(`${path2}.target is invalid`);
6133
6659
  } else {
6134
6660
  if (!nonBlank(entry.target.providerId)) errors.push(`${path2}.target.providerId is required`);
@@ -6143,7 +6669,7 @@ function validateGatewayBindingsSegment(patch) {
6143
6669
  }
6144
6670
  }
6145
6671
  if (entry.modelMap !== void 0) {
6146
- if (!isRecord6(entry.modelMap) || Object.values(entry.modelMap).some((value) => typeof value !== "string")) {
6672
+ if (!isRecord8(entry.modelMap) || Object.values(entry.modelMap).some((value) => typeof value !== "string")) {
6147
6673
  errors.push(`${path2}.modelMap must contain string values`);
6148
6674
  }
6149
6675
  }
@@ -6456,7 +6982,12 @@ var PROVIDER_KEYS = {
6456
6982
  },
6457
6983
  kimi: { block: "kimi", accounts: "kimiAccounts", active: "activeKimiAccountId" },
6458
6984
  grok: { block: "grok", accounts: "grokAccounts", active: "activeGrokAccountId" },
6459
- copilot: { block: "copilot", accounts: "copilotAccounts", active: "activeCopilotAccountId" }
6985
+ copilot: { block: "copilot", accounts: "copilotAccounts", active: "activeCopilotAccountId" },
6986
+ antigravity: {
6987
+ block: "antigravity",
6988
+ accounts: "antigravityAccounts",
6989
+ active: "activeAntigravityAccountId"
6990
+ }
6460
6991
  };
6461
6992
  function clone(value) {
6462
6993
  return JSON.parse(JSON.stringify(value));
@@ -6978,7 +7509,7 @@ async function applyImport(packString, passphrase, mode, deps, parseProviderInpu
6978
7509
  }
6979
7510
 
6980
7511
  // src/admin/adminMigration.ts
6981
- function err6(status, message) {
7512
+ function err7(status, message) {
6982
7513
  return { status, body: { error: { type: "admin_api_error", message } } };
6983
7514
  }
6984
7515
  async function handleExport(body, deps) {
@@ -6988,30 +7519,30 @@ async function handleExport(body, deps) {
6988
7519
  return { status: 200, body: { pack, version: BUNDLE_VERSION } };
6989
7520
  } catch (error) {
6990
7521
  if (error instanceof WeakPassphraseError) {
6991
- return err6(400, error.message);
7522
+ return err7(400, error.message);
6992
7523
  }
6993
- return err6(500, "failed to build the migration pack");
7524
+ return err7(500, "failed to build the migration pack");
6994
7525
  }
6995
7526
  }
6996
7527
  async function handleImport(body, deps) {
6997
7528
  const blob = typeof body["blob"] === "string" ? body["blob"] : "";
6998
7529
  const passphrase = typeof body["passphrase"] === "string" ? body["passphrase"] : "";
6999
7530
  const mode = body["mode"] === "overwrite" ? "overwrite" : "merge";
7000
- if (!blob) return err6(400, "import requires { blob }");
7531
+ if (!blob) return err7(400, "import requires { blob }");
7001
7532
  try {
7002
7533
  const counts = await applyImport(blob, passphrase, mode, deps, deps.parseProviderInput);
7003
7534
  return { status: 200, body: counts };
7004
7535
  } catch (error) {
7005
7536
  if (error instanceof WeakPassphraseError) {
7006
- return err6(400, error.message);
7537
+ return err7(400, error.message);
7007
7538
  }
7008
- return err6(400, error instanceof Error ? error.message : "import failed");
7539
+ return err7(400, error instanceof Error ? error.message : "import failed");
7009
7540
  }
7010
7541
  }
7011
7542
 
7012
7543
  // src/admin/usagePricing.ts
7013
7544
  import { getSharedUsageThroughputTracker } from "@omnicross/core/usage";
7014
- var err7 = (status, message) => ({
7545
+ var err8 = (status, message) => ({
7015
7546
  status,
7016
7547
  body: { error: { type: "admin_api_error", message } }
7017
7548
  });
@@ -7024,7 +7555,7 @@ function parseRange(query2) {
7024
7555
  const startTs = parseFiniteInt(query2.get("startTs"));
7025
7556
  const endTs = parseFiniteInt(query2.get("endTs"));
7026
7557
  if (startTs === null || endTs === null) {
7027
- return err7(400, "startTs and endTs are required finite-integer unix-millis query params");
7558
+ return err8(400, "startTs and endTs are required finite-integer unix-millis query params");
7028
7559
  }
7029
7560
  return { startTs, endTs };
7030
7561
  }
@@ -7049,14 +7580,14 @@ async function handleUsageGet(view, query2, deps) {
7049
7580
  case "timeseries": {
7050
7581
  const bucket = query2.get("bucket");
7051
7582
  if (bucket !== "hour" && bucket !== "day" && bucket !== "month") {
7052
- return err7(400, "bucket must be one of 'hour', 'day', 'month'");
7583
+ return err8(400, "bucket must be one of 'hour', 'day', 'month'");
7053
7584
  }
7054
7585
  const now = Date.now();
7055
7586
  const clamped = { startTs: range.startTs, endTs: Math.min(range.endTs, now) };
7056
7587
  if (clamped.startTs < clamped.endTs) {
7057
7588
  const projected = Math.ceil((clamped.endTs - clamped.startTs) / BUCKET_SPAN_MS[bucket]) + 1;
7058
7589
  if (projected > MAX_TIMESERIES_BUCKETS) {
7059
- return err7(
7590
+ return err8(
7060
7591
  400,
7061
7592
  `requested range projects ~${projected} '${bucket}' buckets (max ${MAX_TIMESERIES_BUCKETS}); narrow the range or use a coarser bucket`
7062
7593
  );
@@ -7079,7 +7610,7 @@ async function handleUsageGet(view, query2, deps) {
7079
7610
  };
7080
7611
  }
7081
7612
  default:
7082
- return err7(404, `unknown usage view '${view ?? ""}'`);
7613
+ return err8(404, `unknown usage view '${view ?? ""}'`);
7083
7614
  }
7084
7615
  }
7085
7616
  function poolKeyLabels(cfg) {
@@ -7128,7 +7659,7 @@ async function handlePricingList(deps) {
7128
7659
  async function handlePricingUpsert(body, deps) {
7129
7660
  const input = parsePricingEntryInput(body);
7130
7661
  if (!input) {
7131
- return err7(400, "invalid pricing entry (providerId, modelId, finite numeric inputPricePer1m/outputPricePer1m required)");
7662
+ return err8(400, "invalid pricing entry (providerId, modelId, finite numeric inputPricePer1m/outputPricePer1m required)");
7132
7663
  }
7133
7664
  const entry = await deps.pricingEngine.upsertManual(input);
7134
7665
  return { status: 200, body: { entry } };
@@ -7137,7 +7668,7 @@ async function handlePricingDelete(query2, deps) {
7137
7668
  const providerId = query2.get("providerId")?.trim() ?? "";
7138
7669
  const modelId = query2.get("modelId")?.trim() ?? "";
7139
7670
  if (!providerId || !modelId) {
7140
- return err7(400, "delete requires providerId and modelId query params");
7671
+ return err8(400, "delete requires providerId and modelId query params");
7141
7672
  }
7142
7673
  const deleted = await deps.pricingStore.delete(providerId, modelId);
7143
7674
  if (deleted) await deps.pricingEngine.invalidateCache();
@@ -7157,13 +7688,13 @@ async function handlePricingFetchLatest(deps) {
7157
7688
  }
7158
7689
  };
7159
7690
  } catch (e) {
7160
- return err7(502, `pricing-source fetch failed: ${e instanceof Error ? e.message : String(e)}`);
7691
+ return err8(502, `pricing-source fetch failed: ${e instanceof Error ? e.message : String(e)}`);
7161
7692
  }
7162
7693
  }
7163
7694
  async function handlePricingResolveConflicts(body, deps) {
7164
7695
  const raw = body["resolutions"];
7165
7696
  if (!Array.isArray(raw)) {
7166
- return err7(400, "resolve-conflicts requires { resolutions: [...] }");
7697
+ return err8(400, "resolve-conflicts requires { resolutions: [...] }");
7167
7698
  }
7168
7699
  const currentRows = await deps.pricingStore.getAll();
7169
7700
  const userEditedKeys = new Set(
@@ -7173,21 +7704,21 @@ async function handlePricingResolveConflicts(body, deps) {
7173
7704
  const pendingIncoming = /* @__PURE__ */ new Map();
7174
7705
  let staleCount = 0;
7175
7706
  for (const item of raw) {
7176
- if (!item || typeof item !== "object") return err7(400, "invalid resolution entry");
7707
+ if (!item || typeof item !== "object") return err8(400, "invalid resolution entry");
7177
7708
  const r = item;
7178
7709
  const action = r["action"];
7179
7710
  if (action !== "overwrite" && action !== "skip") {
7180
- return err7(400, "resolution action must be 'overwrite' or 'skip'");
7711
+ return err8(400, "resolution action must be 'overwrite' or 'skip'");
7181
7712
  }
7182
7713
  const providerId = typeof r["providerId"] === "string" && r["providerId"].trim() ? r["providerId"].trim() : "";
7183
7714
  const modelId = typeof r["modelId"] === "string" && r["modelId"].trim() ? r["modelId"].trim() : "";
7184
7715
  if (!providerId || !modelId) {
7185
- return err7(400, "each resolution requires top-level providerId and modelId");
7716
+ return err8(400, "each resolution requires top-level providerId and modelId");
7186
7717
  }
7187
7718
  const incoming = parsePricingEntryInput(r["incoming"]);
7188
- if (!incoming) return err7(400, "each resolution must echo a valid incoming pricing entry");
7719
+ if (!incoming) return err8(400, "each resolution must echo a valid incoming pricing entry");
7189
7720
  if (incoming.providerId !== providerId || incoming.modelId !== modelId) {
7190
- return err7(400, "resolution providerId/modelId must match the echoed incoming entry");
7721
+ return err8(400, "resolution providerId/modelId must match the echoed incoming entry");
7191
7722
  }
7192
7723
  const key = `${providerId}::${modelId}`;
7193
7724
  if (action === "overwrite" && !userEditedKeys.has(key)) {
@@ -7232,7 +7763,7 @@ function query(req) {
7232
7763
  }
7233
7764
  function allowanceProvider(value) {
7234
7765
  if (!value) return void 0;
7235
- return value === "claude" || value === "codex" || value === "kimi" || value === "opencodego" || value === "grok" || value === "copilot" || value === "gemini" ? value : null;
7766
+ return value === "claude" || value === "codex" || value === "kimi" || value === "opencodego" || value === "grok" || value === "copilot" || value === "gemini" || value === "antigravity" ? value : null;
7236
7767
  }
7237
7768
  async function handleAccountAllowanceApi(req, res, method, rest, service) {
7238
7769
  if (!service) return writeError2(res, 501, "account allowance service is not available");
@@ -7309,6 +7840,16 @@ async function handleAccountAllowanceApi(req, res, method, rest, service) {
7309
7840
  }
7310
7841
  return writeJson3(res, 200, { allowances: allowances2 });
7311
7842
  }
7843
+ if (requestedProvider === "antigravity") {
7844
+ if (!service.refreshAntigravity) {
7845
+ return writeError2(res, 501, "antigravity allowance refresh is not available");
7846
+ }
7847
+ const allowances2 = await service.refreshAntigravity(accountId);
7848
+ if (accountId && allowances2.length === 0) {
7849
+ return writeError2(res, 404, `Antigravity account '${accountId}' not found`);
7850
+ }
7851
+ return writeJson3(res, 200, { allowances: allowances2 });
7852
+ }
7312
7853
  if (requestedProvider === "gemini") {
7313
7854
  if (!service.refreshGemini) {
7314
7855
  return writeError2(res, 501, "gemini allowance refresh is not available");
@@ -7466,7 +8007,7 @@ async function handleAdminApi(req, res, path2, deps) {
7466
8007
  case "server":
7467
8008
  return await handleServer(req, res, method, deps);
7468
8009
  case "images":
7469
- return await handleImages(res, method, rest, deps);
8010
+ return await handleImages(req, res, method, rest, deps);
7470
8011
  case "search":
7471
8012
  return await handleSearchAdmin(req, res, method, rest, deps);
7472
8013
  case "accounts":
@@ -7492,8 +8033,8 @@ async function handleAdminApi(req, res, path2, deps) {
7492
8033
  default:
7493
8034
  return writeJsonError(res, 404, `unknown admin resource '${resource}'`);
7494
8035
  }
7495
- } catch (err8) {
7496
- writeJsonError(res, 500, err8 instanceof Error ? err8.message : String(err8));
8036
+ } catch (err9) {
8037
+ writeJsonError(res, 500, err9 instanceof Error ? err9.message : String(err9));
7497
8038
  }
7498
8039
  }
7499
8040
  function requestQuery(req) {
@@ -7668,7 +8209,7 @@ async function handleDiscoverModels(res, id, cfg) {
7668
8209
  const headers = { Accept: "application/json" };
7669
8210
  if (resolvedKey) headers["Authorization"] = `Bearer ${resolvedKey}`;
7670
8211
  Object.assign(headers, expandRowExtraHeaders(row));
7671
- const response = await fetchUpstream8(url, { method: "GET", headers }, { providerId: "byo" });
8212
+ const response = await fetchUpstream10(url, { method: "GET", headers }, { providerId: "byo" });
7672
8213
  if (!response.ok) {
7673
8214
  const text = await response.text().catch(() => "");
7674
8215
  let message = text.slice(0, 300);
@@ -7685,8 +8226,8 @@ async function handleDiscoverModels(res, id, cfg) {
7685
8226
  const data = await response.json();
7686
8227
  const models = Array.isArray(data?.data) ? data.data.map((m) => typeof m?.id === "string" ? m.id : "").filter((m) => m.length > 0) : [];
7687
8228
  return writeJson4(res, 200, { models });
7688
- } catch (err8) {
7689
- const message = err8 instanceof Error ? err8.message : String(err8);
8229
+ } catch (err9) {
8230
+ const message = err9 instanceof Error ? err9.message : String(err9);
7690
8231
  return writeJson4(res, 200, { models: [], error: `discovery failed: ${message}` });
7691
8232
  }
7692
8233
  }
@@ -7728,7 +8269,7 @@ async function handleTestModel(req, res, id, cfg) {
7728
8269
  Object.assign(headers, expandRowExtraHeaders(row));
7729
8270
  const startedAt = Date.now();
7730
8271
  try {
7731
- const response = await fetchUpstream8(
8272
+ const response = await fetchUpstream10(
7732
8273
  url,
7733
8274
  { method: "POST", headers, body: JSON.stringify(payload) },
7734
8275
  { providerId: "byo" }
@@ -7750,8 +8291,8 @@ async function handleTestModel(req, res, id, cfg) {
7750
8291
  latencyMs,
7751
8292
  sample: extractSampleText(text, row.apiFormat)
7752
8293
  });
7753
- } catch (err8) {
7754
- const message = err8 instanceof Error ? err8.message : String(err8);
8294
+ } catch (err9) {
8295
+ const message = err9 instanceof Error ? err9.message : String(err9);
7755
8296
  return writeJson4(res, 200, { ok: false, latencyMs: Date.now() - startedAt, message });
7756
8297
  }
7757
8298
  }
@@ -8336,8 +8877,8 @@ function imageConfigurationAuditFields(previous, next) {
8336
8877
  const after = next ?? DEFAULT_IMAGES_SERVER_CONFIG;
8337
8878
  const fields = [];
8338
8879
  if (before.enabled !== after.enabled) fields.push("enablement");
8339
- if (before.provider !== after.provider) fields.push("provider");
8340
- if (before.defaultModel !== after.defaultModel || !sameConfigValue(before.modelAliases, after.modelAliases)) fields.push("model");
8880
+ if (!sameConfigValue(before.models, after.models)) fields.push("provider");
8881
+ if (before.defaultModel !== after.defaultModel || !sameConfigValue(before.aliases, after.aliases) || !sameConfigValue(before.codex, after.codex)) fields.push("model");
8341
8882
  if (!sameConfigValue(before.account, after.account)) fields.push("account");
8342
8883
  if (!sameConfigValue(before.queue, after.queue)) fields.push("queue");
8343
8884
  if (!sameConfigValue(before.temporary, after.temporary)) fields.push("temporary");
@@ -8541,6 +9082,12 @@ async function handleAccounts(req, res, method, rest, deps) {
8541
9082
  deps.accountAllowanceService
8542
9083
  );
8543
9084
  }
9085
+ if (method === "GET" && rest[0] === "antigravity" && rest[1] === "models") {
9086
+ const result = await handleAntigravityModelsRoute({
9087
+ resolveAntigravityAccessToken: deps.resolveAntigravityAccessToken ?? (async () => null)
9088
+ });
9089
+ return writeJson4(res, result.status, result.body);
9090
+ }
8544
9091
  if (method === "GET" && rest.length === 0) {
8545
9092
  const accounts = await deps.subscriptionAccounts.listAll();
8546
9093
  const providerAccounts = await deps.subscriptionTokenWriter.listSanitizedAccounts();
@@ -8566,12 +9113,12 @@ async function handleAccounts(req, res, method, rest, deps) {
8566
9113
  }
8567
9114
  return writeJson4(res, 200, { ok: true, affected: result.affected });
8568
9115
  }
8569
- if (method === "GET" && (rest[0] === "codex" || rest[0] === "kimi" || rest[0] === "grok" || rest[0] === "copilot") && rest[1] === "oauth" && rest[3] === "status") {
8570
- 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);
9116
+ if (method === "GET" && (rest[0] === "codex" || rest[0] === "kimi" || rest[0] === "grok" || rest[0] === "copilot" || rest[0] === "antigravity") && rest[1] === "oauth" && rest[3] === "status") {
9117
+ 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);
8571
9118
  return writeJson4(res, result.status, result.body);
8572
9119
  }
8573
- if (method === "DELETE" && (rest[0] === "codex" || rest[0] === "kimi" || rest[0] === "grok" || rest[0] === "copilot") && rest[1] === "oauth" && rest[2]) {
8574
- 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);
9120
+ if (method === "DELETE" && (rest[0] === "codex" || rest[0] === "kimi" || rest[0] === "grok" || rest[0] === "copilot" || rest[0] === "antigravity") && rest[1] === "oauth" && rest[2]) {
9121
+ 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);
8575
9122
  return writeJson4(res, result.status, result.body);
8576
9123
  }
8577
9124
  if (method === "GET" && rest.length === 3 && rest[2] === "diagnostics") {
@@ -8641,6 +9188,10 @@ async function handleAccounts(req, res, method, rest, deps) {
8641
9188
  const result2 = await handleCopilotOAuthStart(deps, body2["enterpriseUrl"]);
8642
9189
  return writeJson4(res, result2.status, result2.body);
8643
9190
  }
9191
+ if (providerId === "antigravity") {
9192
+ const result2 = handleAntigravityOAuthStart(deps);
9193
+ return writeJson4(res, result2.status, result2.body);
9194
+ }
8644
9195
  const result = handleOAuthStart(providerId, deps);
8645
9196
  return writeJson4(res, result.status, result.body);
8646
9197
  }
@@ -9003,7 +9554,41 @@ function imageEndpointUrls(base) {
9003
9554
  edits: `${base}/v1/images/edits`
9004
9555
  }) : null;
9005
9556
  }
9006
- async function handleImages(res, method, rest, deps) {
9557
+ function imageProviderEvidence(images, capabilities) {
9558
+ const evidenceAt = safeStatusTimestamp(capabilities?.oldestEvidenceAt);
9559
+ const resolvedAt = safeStatusTimestamp(capabilities?.resolvedAt);
9560
+ if (evidenceAt === void 0 || resolvedAt === void 0) return null;
9561
+ const expiresAt = evidenceAt <= Number.MAX_SAFE_INTEGER - images.evidenceTtlMs ? evidenceAt + images.evidenceTtlMs : void 0;
9562
+ return Object.freeze({
9563
+ verifiedAt: evidenceAt,
9564
+ ageMs: Math.max(0, resolvedAt - evidenceAt),
9565
+ ...expiresAt !== void 0 ? { expiresAt } : {}
9566
+ });
9567
+ }
9568
+ async function handleImagesVerifyLive(req, res, deps) {
9569
+ const verifier = deps.imageLiveVerifier;
9570
+ if (!verifier) {
9571
+ return writeJsonError(res, 501, "Images live verification is not available");
9572
+ }
9573
+ const serverConfig = await loadServerConfig3(deps.settingsStore);
9574
+ const images = serverConfig.images ?? DEFAULT_IMAGES_SERVER_CONFIG;
9575
+ req.resume();
9576
+ const controller = new AbortController();
9577
+ req.on("close", () => controller.abort());
9578
+ const result = await verifier.verifyLive(images, controller.signal);
9579
+ const antigravityRouted = Object.values(images.models).includes("antigravity-subscription");
9580
+ return writeJson4(res, 200, {
9581
+ ...result,
9582
+ ...antigravityRouted ? { antigravityDeferred: true } : {}
9583
+ });
9584
+ }
9585
+ async function handleImages(req, res, method, rest, deps) {
9586
+ if (rest.length === 1 && rest[0] === "verify-live") {
9587
+ if (method !== "POST") {
9588
+ return writeJsonError(res, 405, `method ${method} not allowed on Images verify-live`);
9589
+ }
9590
+ return handleImagesVerifyLive(req, res, deps);
9591
+ }
9007
9592
  if (rest.length !== 1 || rest[0] !== "capabilities") {
9008
9593
  return writeJsonError(res, 404, "unknown Images admin resource");
9009
9594
  }
@@ -9018,14 +9603,14 @@ async function handleImages(res, method, rest, deps) {
9018
9603
  const capability = await reader.inspectCapability(IMAGE_ADMIN_STATUS_TENANT);
9019
9604
  const resources = safeRuntimeResources(reader.resourceStatus());
9020
9605
  const outbound = deps.outboundApiServer.getStatus();
9021
- const evidenceAt = safeStatusTimestamp(capability.capabilities?.oldestEvidenceAt);
9022
- const resolvedAt = safeStatusTimestamp(capability.capabilities?.resolvedAt);
9023
- const expiresAt = evidenceAt !== void 0 && evidenceAt <= Number.MAX_SAFE_INTEGER - images.evidenceTtlMs ? evidenceAt + images.evidenceTtlMs : void 0;
9024
- const evidence = evidenceAt !== void 0 && resolvedAt !== void 0 ? Object.freeze({
9025
- verifiedAt: evidenceAt,
9026
- ageMs: Math.max(0, resolvedAt - evidenceAt),
9027
- ...expiresAt !== void 0 ? { expiresAt } : {}
9028
- }) : null;
9606
+ const evidence = imageProviderEvidence(images, capability.capabilities);
9607
+ const providers = (capability.providers ?? []).map((provider) => Object.freeze({
9608
+ providerId: provider.providerId,
9609
+ available: provider.available === true,
9610
+ reason: provider.available ? null : safeImageCapabilityReason(provider.reason),
9611
+ models: Object.freeze([...provider.models]),
9612
+ evidence: imageProviderEvidence(images, provider.capabilities)
9613
+ }));
9029
9614
  const draining = lifecycle.draining.map((generation) => Object.freeze({
9030
9615
  generationId: safeImageGenerationId(generation.generationId),
9031
9616
  enabled: generation.enabled,
@@ -9035,7 +9620,7 @@ async function handleImages(res, method, rest, deps) {
9035
9620
  return writeJson4(res, 200, {
9036
9621
  configured: {
9037
9622
  enabled: images.enabled,
9038
- provider: images.provider,
9623
+ provider: images.models[images.defaultModel] ?? "codex-subscription",
9039
9624
  model: images.defaultModel,
9040
9625
  remoteUrlsEnabled: images.remote.enabled,
9041
9626
  referenceTtlMs: images.references.ttlMs
@@ -9046,6 +9631,7 @@ async function handleImages(res, method, rest, deps) {
9046
9631
  evidence,
9047
9632
  features: safeCapabilityValues(capability.capabilities, images.defaultModel)
9048
9633
  },
9634
+ providers,
9049
9635
  runtime: {
9050
9636
  disposed: lifecycle.disposed,
9051
9637
  generationId: safeImageGenerationId(lifecycle.current.generationId),
@@ -9135,12 +9721,12 @@ async function handlePlayground(req, res, method, deps) {
9135
9721
  const payload = body["body"];
9136
9722
  const status = deps.outboundApiServer.getStatus();
9137
9723
  if (!status.running || !status.port) return writeJsonError(res, 503, "outbound server not running");
9138
- const path2 = resolvePlaygroundPath(endpoint, isRecord7(payload) ? payload : {});
9724
+ const path2 = resolvePlaygroundPath(endpoint, isRecord9(payload) ? payload : {});
9139
9725
  if (!path2) return writeJsonError(res, 400, `unknown endpoint '${endpoint}'`);
9140
9726
  const upstreamBody = typeof payload === "string" ? payload : JSON.stringify(payload ?? {});
9141
9727
  await proxyToOutbound(res, status.port, path2, key, upstreamBody);
9142
9728
  }
9143
- function isRecord7(v) {
9729
+ function isRecord9(v) {
9144
9730
  return !!v && typeof v === "object" && !Array.isArray(v);
9145
9731
  }
9146
9732
  function proxyToOutbound(res, outboundPort, path2, key, body) {
@@ -9169,8 +9755,8 @@ function proxyToOutbound(res, outboundPort, path2, key, body) {
9169
9755
  });
9170
9756
  }
9171
9757
  );
9172
- upstream.on("error", (err8) => {
9173
- if (!res.headersSent) writeJsonError(res, 502, `playground proxy failed: ${err8.message}`);
9758
+ upstream.on("error", (err9) => {
9759
+ if (!res.headersSent) writeJsonError(res, 502, `playground proxy failed: ${err9.message}`);
9174
9760
  else res.end();
9175
9761
  resolve10();
9176
9762
  });
@@ -9275,7 +9861,7 @@ async function handleUiStatic(req, res, urlPath, uiDist) {
9275
9861
  }
9276
9862
 
9277
9863
  // src/admin/version.ts
9278
- var DAEMON_VERSION = true ? "0.4.2" : "0.0.0-dev";
9864
+ var DAEMON_VERSION = true ? "0.4.4" : "0.0.0-dev";
9279
9865
 
9280
9866
  // src/admin/AdminServer.ts
9281
9867
  var LOOPBACK_ADDR = "127.0.0.1";
@@ -9318,13 +9904,13 @@ var AdminServer = class {
9318
9904
  const server = http2.createServer((req, res) => {
9319
9905
  this.onRequest(req, res);
9320
9906
  });
9321
- const onError = (err8) => {
9322
- if (err8.code === "EADDRINUSE" && port !== 0) {
9907
+ const onError = (err9) => {
9908
+ if (err9.code === "EADDRINUSE" && port !== 0) {
9323
9909
  server.removeListener("error", onError);
9324
9910
  this.listen(bindAddr, 0).then(resolve10, reject);
9325
9911
  return;
9326
9912
  }
9327
- reject(err8);
9913
+ reject(err9);
9328
9914
  };
9329
9915
  server.on("error", onError);
9330
9916
  server.listen(port, bindAddr, () => {
@@ -9342,8 +9928,8 @@ var AdminServer = class {
9342
9928
  }
9343
9929
  /** Per-request handler: auth gate (when a token is set) → routing. */
9344
9930
  onRequest(req, res) {
9345
- void this.dispatch(req, res).catch((err8) => {
9346
- const message = err8 instanceof Error ? err8.message : String(err8);
9931
+ void this.dispatch(req, res).catch((err9) => {
9932
+ const message = err9 instanceof Error ? err9.message : String(err9);
9347
9933
  this.deps.logger.error("[AdminServer] unhandled error:", message);
9348
9934
  if (!res.headersSent) {
9349
9935
  res.writeHead(500, { "Content-Type": "application/json" });
@@ -9566,7 +10152,10 @@ var HTML_HEADERS = {
9566
10152
  function pageHtml(message) {
9567
10153
  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>`;
9568
10154
  }
9569
- function awaitLoopbackCode(expectedState, timeoutMs = DEFAULT_TIMEOUT_MS, signal) {
10155
+ function awaitLoopbackCode(expectedState, timeoutMs = DEFAULT_TIMEOUT_MS, signal, binding = {}) {
10156
+ const port = binding.port ?? LOOPBACK_PORT;
10157
+ const callbackPath = binding.path ?? CALLBACK_PATH;
10158
+ const label = binding.label ?? "codex";
9570
10159
  return new Promise((resolve10, reject) => {
9571
10160
  let settled = false;
9572
10161
  const finish = (server2, fn) => {
@@ -9577,8 +10166,8 @@ function awaitLoopbackCode(expectedState, timeoutMs = DEFAULT_TIMEOUT_MS, signal
9577
10166
  server2.close();
9578
10167
  };
9579
10168
  const server = createServer2((req, res) => {
9580
- const url = new URL(req.url ?? "", `http://${LOOPBACK_HOST}:${LOOPBACK_PORT}`);
9581
- if (url.pathname !== CALLBACK_PATH) {
10169
+ const url = new URL(req.url ?? "", `http://${LOOPBACK_HOST}:${port}`);
10170
+ if (url.pathname !== callbackPath) {
9582
10171
  res.writeHead(404, HTML_HEADERS);
9583
10172
  res.end(pageHtml("Not found"));
9584
10173
  return;
@@ -9607,25 +10196,25 @@ function awaitLoopbackCode(expectedState, timeoutMs = DEFAULT_TIMEOUT_MS, signal
9607
10196
  return;
9608
10197
  }
9609
10198
  signal?.addEventListener("abort", abort, { once: true });
9610
- server.on("error", (err8) => {
10199
+ server.on("error", (err9) => {
9611
10200
  if (settled) return;
9612
10201
  settled = true;
9613
10202
  clearTimeout(timer);
9614
- if (err8.code === "EADDRINUSE") {
10203
+ if (err9.code === "EADDRINUSE") {
9615
10204
  reject(
9616
10205
  new Error(
9617
- `login: cannot bind ${LOOPBACK_HOST}:${LOOPBACK_PORT} (address in use) \u2014 another codex login or process is holding the port`
10206
+ `login: cannot bind ${LOOPBACK_HOST}:${port} (address in use) \u2014 another ${label} login or process is holding the port`
9618
10207
  )
9619
10208
  );
9620
10209
  } else {
9621
- reject(err8);
10210
+ reject(err9);
9622
10211
  }
9623
10212
  });
9624
10213
  const timer = setTimeout(() => {
9625
10214
  finish(server, () => reject(new Error(`login: timed out after ${Math.round(timeoutMs / 1e3)}s waiting for the callback`)));
9626
10215
  }, timeoutMs);
9627
10216
  if (typeof timer.unref === "function") timer.unref();
9628
- server.listen(LOOPBACK_PORT, LOOPBACK_HOST);
10217
+ server.listen(port, LOOPBACK_HOST);
9629
10218
  });
9630
10219
  }
9631
10220
 
@@ -9695,7 +10284,7 @@ function createPoolKeysLoader(getProviderRow, autoDisabled) {
9695
10284
 
9696
10285
  // src/allowance/ProviderKeyQuotaService.ts
9697
10286
  import { mergeExtraHeaders as mergeExtraHeaders2 } from "@omnicross/core";
9698
- import { fetchUpstream as fetchUpstream9 } from "@omnicross/core/pipeline/upstreamFetch";
10287
+ import { fetchUpstream as fetchUpstream11 } from "@omnicross/core/pipeline/upstreamFetch";
9699
10288
 
9700
10289
  // src/allowance/ProviderKeyQuota.ts
9701
10290
  var MINUTE_MS3 = 6e4;
@@ -9724,11 +10313,11 @@ function isoInstant3(value) {
9724
10313
  }
9725
10314
  return void 0;
9726
10315
  }
9727
- function secondsUntil8(instant, now) {
10316
+ function secondsUntil9(instant, now) {
9728
10317
  if (!instant) return void 0;
9729
10318
  return Math.max(0, Math.floor((Date.parse(instant) - now) / 1e3));
9730
10319
  }
9731
- function isRecord8(value) {
10320
+ function isRecord10(value) {
9732
10321
  return !!value && typeof value === "object" && !Array.isArray(value);
9733
10322
  }
9734
10323
  function detectProviderKeyQuotaAdapter(baseUrl) {
@@ -9795,17 +10384,17 @@ function zaiWindowIdLabel(durationMs) {
9795
10384
  return { id: "quota", label: "Quota" };
9796
10385
  }
9797
10386
  function parseZaiQuotaPayload(payload, now) {
9798
- if (!isRecord8(payload)) return null;
9799
- const data = isRecord8(payload["data"]) ? payload["data"] : payload;
10387
+ if (!isRecord10(payload)) return null;
10388
+ const data = isRecord10(payload["data"]) ? payload["data"] : payload;
9800
10389
  if (payload["success"] === false) return null;
9801
10390
  const limits = Array.isArray(data["limits"]) ? data["limits"] : [];
9802
10391
  const byWindow = /* @__PURE__ */ new Map();
9803
10392
  for (const raw of limits) {
9804
- if (!isRecord8(raw)) continue;
10393
+ if (!isRecord10(raw)) continue;
9805
10394
  const item = raw;
9806
10395
  if (item.type === void 0) continue;
9807
10396
  const details = raw["usageDetails"];
9808
- if (Array.isArray(details) && details.some((d) => isRecord8(d) && d["modelCode"] === "zread")) {
10397
+ if (Array.isArray(details) && details.some((d) => isRecord10(d) && d["modelCode"] === "zread")) {
9809
10398
  continue;
9810
10399
  }
9811
10400
  const durationMs = zaiWindowDurationMs(item);
@@ -9824,7 +10413,7 @@ function parseZaiQuotaPayload(payload, now) {
9824
10413
  usedPercent,
9825
10414
  ...durationMs !== void 0 ? { windowMinutes: Math.round(durationMs / MINUTE_MS3) } : {},
9826
10415
  ...resetsAt !== void 0 ? { resetsAt } : {},
9827
- remainingSeconds: secondsUntil8(resetsAt, now),
10416
+ remainingSeconds: secondsUntil9(resetsAt, now),
9828
10417
  state: "fresh"
9829
10418
  };
9830
10419
  const existing = byWindow.get(id);
@@ -9838,7 +10427,7 @@ function parseZaiQuotaPayload(payload, now) {
9838
10427
  var MINIMAX_STATUS_EXHAUSTED = 2;
9839
10428
  var MINIMAX_SHARED_BUCKET = "general";
9840
10429
  function parseMiniMaxBucket(value) {
9841
- if (!isRecord8(value)) return null;
10430
+ if (!isRecord10(value)) return null;
9842
10431
  const modelName = typeof value["model_name"] === "string" ? value["model_name"].trim() : "";
9843
10432
  if (!modelName) return null;
9844
10433
  const instant = (v) => {
@@ -9865,14 +10454,14 @@ function minimaxWindow(id, label, windowMinutes, resetsAtMs, remainingPercent, s
9865
10454
  usedPercent,
9866
10455
  ...windowMinutes !== void 0 ? { windowMinutes } : {},
9867
10456
  ...resetsAt !== void 0 ? { resetsAt } : {},
9868
- remainingSeconds: secondsUntil8(resetsAt, now),
10457
+ remainingSeconds: secondsUntil9(resetsAt, now),
9869
10458
  state: usedPercent !== null ? "fresh" : "unavailable"
9870
10459
  };
9871
10460
  }
9872
10461
  function parseMiniMaxTokenPlanPayload(payload, now) {
9873
- if (!isRecord8(payload)) return null;
10462
+ if (!isRecord10(payload)) return null;
9874
10463
  const baseResp = payload["base_resp"];
9875
- if (!isRecord8(baseResp) || baseResp["status_code"] !== 0) return null;
10464
+ if (!isRecord10(baseResp) || baseResp["status_code"] !== 0) return null;
9876
10465
  const buckets = Array.isArray(payload["model_remains"]) ? payload["model_remains"] : [];
9877
10466
  let general = null;
9878
10467
  for (const raw of buckets) {
@@ -9905,11 +10494,11 @@ function parseMiniMaxTokenPlanPayload(payload, now) {
9905
10494
  ];
9906
10495
  }
9907
10496
  function parseUmansUsagePayload(payload, now) {
9908
- if (!isRecord8(payload)) return null;
9909
- const limits = isRecord8(payload["limits"]) ? payload["limits"] : void 0;
9910
- const requests = limits && isRecord8(limits["requests"]) ? limits["requests"] : void 0;
9911
- const usage = isRecord8(payload["usage"]) ? payload["usage"] : void 0;
9912
- const window = isRecord8(payload["window"]) ? payload["window"] : void 0;
10497
+ if (!isRecord10(payload)) return null;
10498
+ const limits = isRecord10(payload["limits"]) ? payload["limits"] : void 0;
10499
+ const requests = limits && isRecord10(limits["requests"]) ? limits["requests"] : void 0;
10500
+ const usage = isRecord10(payload["usage"]) ? payload["usage"] : void 0;
10501
+ const window = isRecord10(payload["window"]) ? payload["window"] : void 0;
9913
10502
  const hardCap = finiteNumber5(requests?.["hard_cap"]);
9914
10503
  const softLimit = finiteNumber5(requests?.["limit"]);
9915
10504
  const requestsInWindow = finiteNumber5(usage?.["requests_in_window"]);
@@ -9930,15 +10519,15 @@ function parseUmansUsagePayload(payload, now) {
9930
10519
  usedPercent,
9931
10520
  windowMinutes: 5 * 60,
9932
10521
  ...resetsAt !== void 0 ? { resetsAt } : {},
9933
- remainingSeconds: secondsUntil8(resetsAt, now),
10522
+ remainingSeconds: secondsUntil9(resetsAt, now),
9934
10523
  state: "fresh"
9935
10524
  }
9936
10525
  ];
9937
10526
  }
9938
10527
  function parseSyntheticQuotasPayload(payload, now) {
9939
- if (!isRecord8(payload)) return null;
9940
- const fiveHour = isRecord8(payload["rollingFiveHourLimit"]) ? payload["rollingFiveHourLimit"] : void 0;
9941
- const weekly = isRecord8(payload["weeklyTokenLimit"]) ? payload["weeklyTokenLimit"] : void 0;
10528
+ if (!isRecord10(payload)) return null;
10529
+ const fiveHour = isRecord10(payload["rollingFiveHourLimit"]) ? payload["rollingFiveHourLimit"] : void 0;
10530
+ const weekly = isRecord10(payload["weeklyTokenLimit"]) ? payload["weeklyTokenLimit"] : void 0;
9942
10531
  const windows = [];
9943
10532
  if (fiveHour) {
9944
10533
  const max = finiteNumber5(fiveHour["max"]);
@@ -9952,7 +10541,7 @@ function parseSyntheticQuotasPayload(payload, now) {
9952
10541
  usedPercent,
9953
10542
  windowMinutes: 5 * 60,
9954
10543
  ...resetsAt !== void 0 ? { resetsAt } : {},
9955
- remainingSeconds: secondsUntil8(resetsAt, now),
10544
+ remainingSeconds: secondsUntil9(resetsAt, now),
9956
10545
  state: usedPercent !== null || resetsAt ? "fresh" : "unavailable"
9957
10546
  });
9958
10547
  }
@@ -9967,7 +10556,7 @@ function parseSyntheticQuotasPayload(payload, now) {
9967
10556
  usedPercent,
9968
10557
  windowMinutes: 7 * 24 * 60,
9969
10558
  ...resetsAt !== void 0 ? { resetsAt } : {},
9970
- remainingSeconds: secondsUntil8(resetsAt, now),
10559
+ remainingSeconds: secondsUntil9(resetsAt, now),
9971
10560
  state: usedPercent !== null || resetsAt ? "fresh" : "unavailable"
9972
10561
  });
9973
10562
  }
@@ -9979,12 +10568,12 @@ var CLINE_WINDOW_CONFIG = {
9979
10568
  monthly: { id: "thirty-day", label: "30 days", minutes: 30 * 24 * 60 }
9980
10569
  };
9981
10570
  function parseClinePassUsageLimitsPayload(payload, now) {
9982
- if (!isRecord8(payload)) return null;
9983
- const data = isRecord8(payload["data"]) ? payload["data"] : payload;
10571
+ if (!isRecord10(payload)) return null;
10572
+ const data = isRecord10(payload["data"]) ? payload["data"] : payload;
9984
10573
  const limits = Array.isArray(data["limits"]) ? data["limits"] : [];
9985
10574
  const windows = [];
9986
10575
  for (const raw of limits) {
9987
- if (!isRecord8(raw)) continue;
10576
+ if (!isRecord10(raw)) continue;
9988
10577
  const config = CLINE_WINDOW_CONFIG[typeof raw["type"] === "string" ? raw["type"] : ""];
9989
10578
  if (!config) continue;
9990
10579
  const usedPercent = finitePercent4(raw["percentUsed"]);
@@ -9997,7 +10586,7 @@ function parseClinePassUsageLimitsPayload(payload, now) {
9997
10586
  usedPercent,
9998
10587
  windowMinutes: config.minutes,
9999
10588
  ...resetsAt !== void 0 ? { resetsAt } : {},
10000
- remainingSeconds: secondsUntil8(resetsAt, now),
10589
+ remainingSeconds: secondsUntil9(resetsAt, now),
10001
10590
  state: "fresh"
10002
10591
  });
10003
10592
  }
@@ -10036,7 +10625,7 @@ function rowKeyEntries(row) {
10036
10625
  return [];
10037
10626
  }
10038
10627
  var ProviderKeyQuotaService = class {
10039
- constructor(box, fetchImpl = (url, init) => fetchUpstream9(url, init, { redactBodies: true }), now = Date.now) {
10628
+ constructor(box, fetchImpl = (url, init) => fetchUpstream11(url, init, { redactBodies: true }), now = Date.now) {
10040
10629
  this.box = box;
10041
10630
  this.fetchImpl = fetchImpl;
10042
10631
  this.now = now;
@@ -10643,12 +11232,12 @@ function createImageDoctorService(options) {
10643
11232
  authStrategy: strategy,
10644
11233
  generationTimeoutMs: config.queue.generationTimeoutMs
10645
11234
  }));
10646
- const readAccount = async () => {
10647
- const codex = (await options.subscriptionAccounts.listAll()).find((entry) => entry.providerId === "codex");
11235
+ const readAccount = async (providerId) => {
11236
+ const entry = (await options.subscriptionAccounts.listAll()).find((candidate) => candidate.providerId === providerId);
10648
11237
  return Object.freeze({
10649
- present: codex !== void 0,
10650
- usable: codex?.credentialStatus.ok === true,
10651
- reason: codex === void 0 ? "missing" : codex.credentialStatus.ok ? "ready" : "unavailable"
11238
+ present: entry !== void 0,
11239
+ usable: entry?.credentialStatus.ok === true,
11240
+ reason: entry === void 0 ? "missing" : entry.credentialStatus.ok ? "ready" : "unavailable"
10652
11241
  });
10653
11242
  };
10654
11243
  const activePaths = () => options.storageCatalog.active().resolver;
@@ -10686,6 +11275,7 @@ function createImageDoctorService(options) {
10686
11275
  } catch {
10687
11276
  storesValid = false;
10688
11277
  }
11278
+ const antigravityAccount = await readAccount("antigravity");
10689
11279
  const rows = await options.keyDb.outboundApiKeysList();
10690
11280
  let legacyRows = 0;
10691
11281
  let invalidRows = 0;
@@ -10702,7 +11292,7 @@ function createImageDoctorService(options) {
10702
11292
  invalidRows += 1;
10703
11293
  }
10704
11294
  }
10705
- const account = await readAccount();
11295
+ const account = await readAccount("codex");
10706
11296
  let evidence;
10707
11297
  let evidenceStore;
10708
11298
  try {
@@ -10716,10 +11306,11 @@ function createImageDoctorService(options) {
10716
11306
  return Object.freeze({
10717
11307
  config: Object.freeze({
10718
11308
  enabled: config.enabled,
10719
- provider: config.provider,
11309
+ provider: config.models[config.defaultModel] ?? "codex-subscription",
10720
11310
  model: config.defaultModel,
10721
11311
  valid: configErrors.length === 0,
10722
- errorCount: configErrors.length
11312
+ errorCount: configErrors.length,
11313
+ routedProviders: Object.freeze([...new Set(Object.values(config.models))])
10723
11314
  }),
10724
11315
  roots: Object.freeze({
10725
11316
  valid: verifiedAreas === ROOT_AREAS.length,
@@ -10744,12 +11335,13 @@ function createImageDoctorService(options) {
10744
11335
  imagesAuthorizedRows
10745
11336
  }),
10746
11337
  account,
11338
+ antigravityAccount,
10747
11339
  evidence: Object.freeze(evidence)
10748
11340
  });
10749
11341
  },
10750
11342
  verifyLive: async (config, signal) => {
10751
11343
  if (!config.enabled) return Object.freeze({ ok: false, code: "images_disabled" });
10752
- const account = await readAccount();
11344
+ const account = await readAccount("codex");
10753
11345
  if (!account.usable) {
10754
11346
  return Object.freeze({ ok: false, code: "codex_account_unavailable" });
10755
11347
  }
@@ -11010,6 +11602,7 @@ import {
11010
11602
  validateImagesServerConfig as validateImagesServerConfig3
11011
11603
  } from "@omnicross/core/outbound-api";
11012
11604
  import {
11605
+ createAntigravitySubscriptionImageProvider,
11013
11606
  createCodexSubscriptionImageProvider
11014
11607
  } from "@omnicross/subscriptions";
11015
11608
 
@@ -11041,10 +11634,11 @@ function createTrustedImageApiRuntimeResolver(options) {
11041
11634
  throw new TypeError("enabled image remote loading requires a proven resolver");
11042
11635
  }
11043
11636
  const hmacKey = Buffer.from(options.hmacKey);
11044
- const modelAliases = new Map(Object.entries(options.config.modelAliases));
11637
+ const modelAliases = new Map(Object.entries(options.config.aliases));
11638
+ const modelRoutes = new Map(Object.entries(options.config.models));
11045
11639
  const limits = Object.freeze({ ...options.config.limits });
11046
- const providerId = options.config.provider;
11047
11640
  const defaultModel = options.config.defaultModel;
11641
+ const providerId = modelRoutes.get(defaultModel) ?? "codex-subscription";
11048
11642
  const referenceStore = options.referenceStore;
11049
11643
  const retention = Object.freeze({
11050
11644
  enabled: true,
@@ -11065,6 +11659,7 @@ function createTrustedImageApiRuntimeResolver(options) {
11065
11659
  providerId,
11066
11660
  defaultModel,
11067
11661
  modelAliases,
11662
+ modelRoutes,
11068
11663
  limits,
11069
11664
  ...preferredAccountId ? { preferredAccountId } : {},
11070
11665
  ...preferredAccountGroup ? { preferredAccountGroup } : {},
@@ -11469,7 +12064,9 @@ var GENERATION_ID = /^[A-Za-z0-9][A-Za-z0-9_.:-]{0,127}$/u;
11469
12064
  function snapshotConfig(config) {
11470
12065
  return {
11471
12066
  ...config,
11472
- modelAliases: { ...config.modelAliases },
12067
+ models: { ...config.models },
12068
+ aliases: { ...config.aliases },
12069
+ codex: { ...config.codex },
11473
12070
  account: { ...config.account },
11474
12071
  queue: { ...config.queue },
11475
12072
  temporary: { ...config.temporary },
@@ -11503,10 +12100,15 @@ function createImageRuntimeGeneration(options) {
11503
12100
  }
11504
12101
  });
11505
12102
  }
11506
- const authStrategy = options.subscriptionAccounts.getStrategy("codex");
11507
- if (!authStrategy || authStrategy.providerId !== "codex") {
12103
+ const routedProviders = [...new Set(Object.values(config.models))];
12104
+ const codexStrategy = routedProviders.includes("codex-subscription") ? options.subscriptionAccounts.getStrategy("codex") : void 0;
12105
+ if (routedProviders.includes("codex-subscription") && (!codexStrategy || codexStrategy.providerId !== "codex")) {
11508
12106
  throw new TypeError("enabled image runtime requires the Codex subscription strategy");
11509
12107
  }
12108
+ const antigravityStrategy = routedProviders.includes("antigravity-subscription") ? options.subscriptionAccounts.getStrategy("antigravity") : void 0;
12109
+ if (routedProviders.includes("antigravity-subscription") && (!antigravityStrategy || antigravityStrategy.providerId !== "antigravity")) {
12110
+ throw new TypeError("enabled image runtime requires the Antigravity subscription strategy");
12111
+ }
11510
12112
  const privateHmacKey = options.privateHmacKey ? Buffer.from(options.privateHmacKey) : loadOrCreateImageTenantHmacSalt(options.storage.paths, randomBytes6);
11511
12113
  if (privateHmacKey.byteLength !== 32) {
11512
12114
  privateHmacKey.fill(0);
@@ -11541,23 +12143,32 @@ function createImageRuntimeGeneration(options) {
11541
12143
  if (options.testOnlySyntheticVerifiedProvider && options.testOnlySyntheticVerifiedProvider.label !== "synthetic-verified-image-provider-test-only") {
11542
12144
  throw new TypeError("synthetic verified image provider test seam label is invalid");
11543
12145
  }
11544
- const provider = options.testOnlySyntheticVerifiedProvider ? options.testOnlySyntheticVerifiedProvider.createProvider({
12146
+ const providers = options.testOnlySyntheticVerifiedProvider ? [options.testOnlySyntheticVerifiedProvider.createProvider({
11545
12147
  generationId: options.generationId,
11546
12148
  scheduler,
11547
12149
  now: options.now ?? Date.now,
11548
12150
  referenceStore: options.storage.referenceStore,
11549
12151
  stateStore: options.storage.stateStore
11550
- }) : createCodexSubscriptionImageProvider({
11551
- authStrategy,
12152
+ })] : routedProviders.map((providerId) => providerId === "codex-subscription" ? createCodexSubscriptionImageProvider({
12153
+ authStrategy: codexStrategy,
11552
12154
  evidenceSource: generationEvidenceSource,
11553
12155
  executionScheduler: scheduler,
11554
12156
  generationTimeoutMs: config.queue.generationTimeoutMs,
12157
+ now: options.now,
12158
+ wire: {
12159
+ imageModel: config.codex.imageModel,
12160
+ carrierModel: config.codex.carrierModel
12161
+ }
12162
+ }) : createAntigravitySubscriptionImageProvider({
12163
+ authStrategy: antigravityStrategy,
12164
+ executionScheduler: scheduler,
12165
+ generationTimeoutMs: config.queue.generationTimeoutMs,
11555
12166
  now: options.now
11556
- });
11557
- if (provider.id !== config.provider) {
12167
+ }));
12168
+ if (providers.length === 1 && providers[0].id !== "codex-subscription") {
11558
12169
  throw new TypeError("synthetic verified image provider id must match configured provider");
11559
12170
  }
11560
- const providerRegistry = new ImageProviderRegistry([provider]);
12171
+ const providerRegistry = new ImageProviderRegistry(providers);
11561
12172
  const orchestrator = new ImageOrchestrator({
11562
12173
  registry: providerRegistry,
11563
12174
  referenceStore: options.storage.referenceStore,
@@ -11579,35 +12190,72 @@ function createImageRuntimeGeneration(options) {
11579
12190
  ...options.createCallId ? { createCallId: options.createCallId } : {},
11580
12191
  ...options.now ? { now: options.now } : {}
11581
12192
  });
12193
+ const defaultProviderId = config.models[config.defaultModel] ?? "codex-subscription";
12194
+ const inspectOneProvider = async (providerId, apiKeyId) => {
12195
+ const capabilities = await orchestrator.getCapabilities(providerId, {
12196
+ requestId: `${options.generationId}:capability-inspection`,
12197
+ tenantId: apiKeyId,
12198
+ signal: new AbortController().signal,
12199
+ sessionKey: `outbound:images:${apiKeyId}`,
12200
+ ...config.account.id ? { preferredAccountId: config.account.id } : {},
12201
+ ...config.account.group ? { preferredAccountGroup: config.account.group } : {},
12202
+ boundAccountFallbackPolicy: config.account.fallback
12203
+ });
12204
+ return capabilities;
12205
+ };
11582
12206
  const inspectCapability = async (apiKeyId) => {
11583
- try {
11584
- const capabilities = await orchestrator.getCapabilities(config.provider, {
11585
- requestId: `${options.generationId}:capability-inspection`,
11586
- tenantId: apiKeyId,
11587
- signal: new AbortController().signal,
11588
- sessionKey: `outbound:images:${apiKeyId}`,
11589
- ...config.account.id ? { preferredAccountId: config.account.id } : {},
11590
- ...config.account.group ? { preferredAccountGroup: config.account.group } : {},
11591
- boundAccountFallbackPolicy: config.account.fallback
11592
- });
11593
- const available = capabilities.available === true && capabilities.generate === true && capabilities.models.includes(config.defaultModel);
11594
- return Object.freeze({
11595
- enabled: true,
11596
- available,
11597
- providerId: config.provider,
11598
- model: config.defaultModel,
11599
- ...!available ? { reason: capabilities.reason ?? "runtime_unavailable" } : {},
11600
- capabilities
11601
- });
11602
- } catch (error) {
12207
+ const providerCapabilities = /* @__PURE__ */ new Map();
12208
+ let defaultProviderError;
12209
+ const providerRows = [];
12210
+ for (const providerId of [...new Set(Object.values(config.models))]) {
12211
+ try {
12212
+ const capabilities2 = await inspectOneProvider(providerId, apiKeyId);
12213
+ providerCapabilities.set(providerId, capabilities2);
12214
+ const affirmed = capabilities2.available === true && capabilities2.generate === true;
12215
+ providerRows.push({
12216
+ providerId,
12217
+ available: affirmed,
12218
+ ...!affirmed ? { reason: capabilities2.reason ?? "runtime_unavailable" } : {},
12219
+ models: affirmed ? Object.entries(config.models).filter(([model, modelProvider]) => modelProvider === providerId && capabilities2.models.includes(model)).map(([model]) => model) : [],
12220
+ capabilities: capabilities2
12221
+ });
12222
+ } catch (error) {
12223
+ if (providerId === defaultProviderId) defaultProviderError = error;
12224
+ providerRows.push({
12225
+ providerId,
12226
+ available: false,
12227
+ reason: error instanceof ImageGenerationError4 && (error.code === "upstream_auth_required" || error.code === "invalid_api_key") ? "account_unverified" : "runtime_unavailable",
12228
+ models: []
12229
+ });
12230
+ }
12231
+ }
12232
+ const providers2 = Object.freeze(providerRows);
12233
+ const routedModels = Object.freeze(
12234
+ providerRows.flatMap((row) => row.available ? row.models : [])
12235
+ );
12236
+ const capabilities = providerCapabilities.get(defaultProviderId);
12237
+ if (!capabilities) {
11603
12238
  return Object.freeze({
11604
12239
  enabled: true,
11605
12240
  available: false,
11606
- providerId: config.provider,
12241
+ providerId: defaultProviderId,
11607
12242
  model: config.defaultModel,
11608
- reason: error instanceof ImageGenerationError4 && (error.code === "upstream_auth_required" || error.code === "invalid_api_key") ? "account_unverified" : "runtime_unavailable"
12243
+ routedModels,
12244
+ providers: providers2,
12245
+ reason: defaultProviderError instanceof ImageGenerationError4 && (defaultProviderError.code === "upstream_auth_required" || defaultProviderError.code === "invalid_api_key") ? "account_unverified" : "runtime_unavailable"
11609
12246
  });
11610
12247
  }
12248
+ const available = capabilities.available === true && capabilities.generate === true && capabilities.models.includes(config.defaultModel);
12249
+ return Object.freeze({
12250
+ enabled: true,
12251
+ available,
12252
+ providerId: defaultProviderId,
12253
+ model: config.defaultModel,
12254
+ routedModels,
12255
+ providers: providers2,
12256
+ ...!available ? { reason: capabilities.reason ?? "runtime_unavailable" } : {},
12257
+ capabilities
12258
+ });
11611
12259
  };
11612
12260
  const resolverToDispose = runtimeResolver;
11613
12261
  const schedulerToDispose = scheduler;
@@ -11645,7 +12293,7 @@ function createImageRuntimeGeneration(options) {
11645
12293
  imageApi,
11646
12294
  hosted,
11647
12295
  hostedRuntime: Object.freeze({
11648
- providerId: config.provider,
12296
+ providerId: defaultProviderId,
11649
12297
  imageModel: config.defaultModel,
11650
12298
  referenceTtlMs: config.references.ttlMs,
11651
12299
  maxOutputBytes: config.limits.maxOutputBytes,
@@ -14642,6 +15290,9 @@ var ImageRuntimeManager = class {
14642
15290
  }
14643
15291
  async listAvailableModels(apiKeyId) {
14644
15292
  const inspection = await this.inspectCapability(apiKeyId);
15293
+ if (inspection.routedModels !== void 0) {
15294
+ return Object.freeze([...inspection.routedModels]);
15295
+ }
14645
15296
  return inspection.available && inspection.model === "gpt-image-2" ? Object.freeze([inspection.model]) : Object.freeze([]);
14646
15297
  }
14647
15298
  resourceStatus() {
@@ -16857,11 +17508,13 @@ var JsonVoucherDb = class {
16857
17508
  // src/ports/JsonSubscriptionCredentialStore.ts
16858
17509
  import { existsSync as existsSync22, mkdirSync as mkdirSync6, readFileSync as readFileSync18, renameSync as renameSync12 } from "fs";
16859
17510
  import { dirname as dirname15 } from "path";
17511
+ import { getAntigravityProjectResolver as getAntigravityProjectResolver2 } from "@omnicross/core/auth/GeminiCodeAssistProjectResolver";
16860
17512
  import { getSharedAccountHealth as getSharedAccountHealth2 } from "@omnicross/core/pipeline/SubscriptionAccountHealth";
16861
17513
  import { getSharedAccountAllowanceScheduling as getSharedAccountAllowanceScheduling3 } from "@omnicross/core/pipeline/AccountAllowanceScheduling";
16862
- import { fetchUpstream as fetchUpstream10 } from "@omnicross/core/pipeline/upstreamFetch";
17514
+ import { fetchUpstream as fetchUpstream12 } from "@omnicross/core/pipeline/upstreamFetch";
16863
17515
  import { getSharedIdentityStore as getSharedIdentityStore2 } from "@omnicross/core/provider-proxy/identity/SubscriptionIdentityStore";
16864
17516
  import {
17517
+ antigravityOAuth as antigravityOAuth2,
16865
17518
  claudeOAuth as claudeOAuth2,
16866
17519
  codexOAuth as codexOAuth2,
16867
17520
  geminiOAuth as geminiOAuth2,
@@ -17015,7 +17668,7 @@ var JsonSubscriptionCredentialStore = class {
17015
17668
  * a plaintext token pair into `upstream-trace.jsonl`.
17016
17669
  */
17017
17670
  buildRefreshFetch(providerId, accountId) {
17018
- return this.fetchImpl ?? ((url, init) => fetchUpstream10(url, init, { providerId, accountId, redactBodies: true }));
17671
+ return this.fetchImpl ?? ((url, init) => fetchUpstream12(url, init, { providerId, accountId, redactBodies: true }));
17019
17672
  }
17020
17673
  /**
17021
17674
  * In-flight refresh coalescing. OAuth refresh tokens are
@@ -17056,7 +17709,7 @@ var JsonSubscriptionCredentialStore = class {
17056
17709
  * other hot reads. Never returns token material.
17057
17710
  */
17058
17711
  getAccountProxy(providerId, accountId) {
17059
- if (providerId !== "claude" && providerId !== "codex" && providerId !== "gemini" && providerId !== "opencodego" && providerId !== "kimi" && providerId !== "grok" && providerId !== "copilot") {
17712
+ if (providerId !== "claude" && providerId !== "codex" && providerId !== "gemini" && providerId !== "opencodego" && providerId !== "kimi" && providerId !== "grok" && providerId !== "copilot" && providerId !== "antigravity") {
17060
17713
  return void 0;
17061
17714
  }
17062
17715
  return getAccountProxy(this.readConfig(), providerId, accountId);
@@ -17075,7 +17728,7 @@ var JsonSubscriptionCredentialStore = class {
17075
17728
  const fingerprintOn = identityStore.isEnabled();
17076
17729
  const now = Date.now();
17077
17730
  const out = {};
17078
- for (const provider of ["claude", "codex", "gemini", "opencodego", "kimi", "grok", "copilot"]) {
17731
+ for (const provider of ["claude", "codex", "gemini", "opencodego", "kimi", "grok", "copilot", "antigravity"]) {
17079
17732
  const sanitized = sanitizeAccounts(config, provider);
17080
17733
  if (sanitized.length === 0) continue;
17081
17734
  for (const account of sanitized) {
@@ -17334,6 +17987,76 @@ var JsonSubscriptionCredentialStore = class {
17334
17987
  return false;
17335
17988
  });
17336
17989
  }
17990
+ /**
17991
+ * Refresh the Antigravity (Google) OAuth access token. Like gemini, the
17992
+ * Google token endpoint does NOT return a refresh_token on refresh, so this
17993
+ * writes ONLY access+expiresAt (+status/lastRefreshedAt) and DELIBERATELY
17994
+ * preserves the stored `refreshToken` — plus the account's `projectId`
17995
+ * (a handshake product; the post-refresh re-validation is the refresh
17996
+ * scheduler's hook, not this write) and `email`. HONEST `false` when no
17997
+ * refresh_token.
17998
+ */
17999
+ async refreshAntigravityToken() {
18000
+ return this.coalesce("antigravity:active", async () => {
18001
+ const config = this.readConfig();
18002
+ const active = getActiveAccount(config, "antigravity");
18003
+ const antigravity = active?.tokens;
18004
+ if (!active || !antigravity?.refreshToken) return false;
18005
+ const capturedId = active.id;
18006
+ this.materializeMigration(config);
18007
+ const refreshFetch = this.buildRefreshFetch("antigravity", capturedId);
18008
+ try {
18009
+ const result = await antigravityOAuth2.refreshAccessToken(antigravity.refreshToken, refreshFetch);
18010
+ const expiresAt = new Date(Date.now() + result.expiresIn * 1e3).toISOString();
18011
+ const next = {
18012
+ ...antigravity,
18013
+ // KEEP the existing refreshToken/projectId/email.
18014
+ accessToken: result.accessToken,
18015
+ expiresAt,
18016
+ status: "authorized",
18017
+ lastRefreshedAt: (/* @__PURE__ */ new Date()).toISOString(),
18018
+ errorMessage: void 0
18019
+ };
18020
+ this.writeBackById("antigravity", capturedId, next);
18021
+ await this.revalidateAntigravityProject(capturedId);
18022
+ return true;
18023
+ } catch (error) {
18024
+ this.markExpiredById("antigravity", capturedId, antigravity, error);
18025
+ return false;
18026
+ }
18027
+ });
18028
+ }
18029
+ /**
18030
+ * Post-refresh project re-validation hook (antigravity design D8): after a
18031
+ * successful antigravity token refresh, re-run the Code Assist project
18032
+ * handshake and write the (possibly rotated) `projectId` back to the account.
18033
+ * A handshake FAILURE keeps the stored projectId untouched (logged) so the
18034
+ * account keeps serving with the last-known-good project until a later
18035
+ * refresh succeeds. Returns whether the handshake produced a project.
18036
+ */
18037
+ async revalidateAntigravityProject(accountId) {
18038
+ const before = getAccountById(this.readConfig(), "antigravity", accountId);
18039
+ const accessToken = before?.tokens?.accessToken;
18040
+ if (!accessToken) return false;
18041
+ try {
18042
+ const projectId = await getAntigravityProjectResolver2().resolveProject(accessToken);
18043
+ if (projectId !== void 0) {
18044
+ const config = this.readConfig();
18045
+ const account = getAccountById(config, "antigravity", accountId);
18046
+ const tokens = account?.tokens;
18047
+ if (account && tokens?.accessToken === accessToken && tokens.projectId !== projectId) {
18048
+ this.writeBackById("antigravity", accountId, { ...tokens, projectId });
18049
+ }
18050
+ return true;
18051
+ }
18052
+ return false;
18053
+ } catch (error) {
18054
+ console.warn(
18055
+ `[JsonSubscriptionCredentialStore] antigravity project re-validation failed for account ${accountId}: ` + (error instanceof Error ? error.message : String(error))
18056
+ );
18057
+ return false;
18058
+ }
18059
+ }
17337
18060
  /**
17338
18061
  * Refresh a SPECIFIC managed account by id (background scheduler sweep and
17339
18062
  * account-pool resolution). It uses only that account's stored refresh
@@ -17362,6 +18085,7 @@ var JsonSubscriptionCredentialStore = class {
17362
18085
  };
17363
18086
  if (refreshed.idToken) next.idToken = refreshed.idToken;
17364
18087
  this.writeBackById(provider, id, next);
18088
+ if (provider === "antigravity") await this.revalidateAntigravityProject(id);
17365
18089
  return true;
17366
18090
  } catch (error) {
17367
18091
  this.markExpiredById(provider, id, captured, error);
@@ -17386,7 +18110,7 @@ var JsonSubscriptionCredentialStore = class {
17386
18110
  }
17387
18111
  const oauth = account.tokens;
17388
18112
  if (!oauth.accessToken) return null;
17389
- if (providerId === "codex" || providerId === "gemini" || providerId === "kimi" || providerId === "grok" || providerId === "copilot") {
18113
+ if (providerId === "codex" || providerId === "gemini" || providerId === "kimi" || providerId === "grok" || providerId === "copilot" || providerId === "antigravity") {
17390
18114
  const expiresAtMs = oauth.expiresAt ? Date.parse(oauth.expiresAt) : 0;
17391
18115
  const expiringSoon = expiresAtMs > 0 && Date.now() >= expiresAtMs - ACCOUNT_REFRESH_LEAD_MS;
17392
18116
  if (expiringSoon && oauth.refreshToken) {
@@ -17502,6 +18226,13 @@ var JsonSubscriptionCredentialStore = class {
17502
18226
  if (provider === "copilot") {
17503
18227
  throw new Error("GitHub Copilot tokens cannot be refreshed \u2014 re-authenticate the account");
17504
18228
  }
18229
+ if (provider === "antigravity") {
18230
+ const r2 = await antigravityOAuth2.refreshAccessToken(refreshToken, refreshFetch);
18231
+ return {
18232
+ accessToken: r2.accessToken,
18233
+ expiresAt: new Date(Date.now() + r2.expiresIn * 1e3).toISOString()
18234
+ };
18235
+ }
17505
18236
  const flow = provider === "claude" ? claudeOAuth2 : provider === "codex" ? codexOAuth2 : geminiOAuth2;
17506
18237
  const r = await flow.refreshAccessToken(refreshToken, refreshFetch);
17507
18238
  return {
@@ -17745,7 +18476,7 @@ var JsonSubscriptionCredentialStore = class {
17745
18476
  };
17746
18477
 
17747
18478
  // src/AccountHealthProbeScheduler.ts
17748
- import { fetchUpstream as fetchUpstream11 } from "@omnicross/core/pipeline/upstreamFetch";
18479
+ import { fetchUpstream as fetchUpstream13 } from "@omnicross/core/pipeline/upstreamFetch";
17749
18480
 
17750
18481
  // src/probe/CodexGenerationProbe.ts
17751
18482
  import {
@@ -17900,7 +18631,11 @@ var PROVIDER_PROBE_PLANS = {
17900
18631
  // The Copilot quota endpoint (copilot_internal/user) is a verified FREE
17901
18632
  // authed GET but lives on api.github.com with its own auth dialect and a
17902
18633
  // monthly-only window — the allowance collector owns the health surface.
17903
- copilot: { kind: "local" }
18634
+ copilot: { kind: "local" },
18635
+ // Antigravity's quota endpoints are POST RPCs on daily-cloudcode-pa (not a
18636
+ // cheap GET) and need the antigravity/hub UA — the allowance collector owns
18637
+ // the health surface; the probe stays local.
18638
+ antigravity: { kind: "local" }
17904
18639
  };
17905
18640
  function probePlanFor(providerId) {
17906
18641
  return PROVIDER_PROBE_PLANS[providerId] ?? { kind: "local" };
@@ -17922,7 +18657,7 @@ var AccountHealthProbeScheduler = class {
17922
18657
  this.logger = logger;
17923
18658
  this.config = config;
17924
18659
  this.now = opts.now ?? Date.now;
17925
- this.fetchImpl = opts.fetchImpl ?? fetchUpstream11;
18660
+ this.fetchImpl = opts.fetchImpl ?? fetchUpstream13;
17926
18661
  this.sleep = opts.sleep ?? ((ms) => new Promise((r) => setTimeout(r, ms)));
17927
18662
  this.planFor = opts.planFor ?? probePlanFor;
17928
18663
  }
@@ -19627,7 +20362,7 @@ var AuditWriter = class {
19627
20362
  import { appendFileSync as appendFileSync3, mkdirSync as mkdirSync8 } from "fs";
19628
20363
  import { createHmac as createHmac5 } from "crypto";
19629
20364
  import { join as join26 } from "path";
19630
- import { fetchUpstream as fetchUpstream12 } from "@omnicross/core/pipeline/upstreamFetch";
20365
+ import { fetchUpstream as fetchUpstream14 } from "@omnicross/core/pipeline/upstreamFetch";
19631
20366
 
19632
20367
  // src/billing/billingFiles.ts
19633
20368
  var BILLING_FILE_RE = /^billing-(\d{4})-(\d{2})-(\d{2})\.jsonl$/;
@@ -19650,7 +20385,7 @@ var BillingPublisher = class {
19650
20385
  constructor(billingDir, logger, opts = {}) {
19651
20386
  this.billingDir = billingDir;
19652
20387
  this.logger = logger;
19653
- this.fetchImpl = opts.fetchImpl ?? ((url, init) => fetchUpstream12(url, init));
20388
+ this.fetchImpl = opts.fetchImpl ?? ((url, init) => fetchUpstream14(url, init));
19654
20389
  this.defer = opts.defer ?? ((fn) => setTimeout(fn, 0));
19655
20390
  this.timeoutMs = opts.timeoutMs ?? BILLING_POST_TIMEOUT_MS;
19656
20391
  this.now = opts.now ?? Date.now;
@@ -19900,7 +20635,7 @@ var BillingRetrySweeper = class {
19900
20635
  // src/TokenRefreshScheduler.ts
19901
20636
  var REFRESH_LEAD_MS2 = 5 * 6e4;
19902
20637
  var SWEEP_INTERVAL_MS5 = 6e4;
19903
- var OAUTH_PROVIDERS2 = ["claude", "codex", "gemini", "kimi", "grok", "copilot"];
20638
+ var OAUTH_PROVIDERS2 = ["claude", "codex", "gemini", "kimi", "grok", "copilot", "antigravity"];
19904
20639
  var TokenRefreshScheduler = class {
19905
20640
  constructor(store, logger, intervalMs = SWEEP_INTERVAL_MS5, leadMs = REFRESH_LEAD_MS2) {
19906
20641
  this.store = store;
@@ -19991,6 +20726,8 @@ var TokenRefreshScheduler = class {
19991
20726
  // never reaches this — the branch exists for union totality.
19992
20727
  case "copilot":
19993
20728
  return this.store.refreshCopilotToken();
20729
+ case "antigravity":
20730
+ return this.store.refreshAntigravityToken();
19994
20731
  }
19995
20732
  }
19996
20733
  };
@@ -20069,7 +20806,7 @@ function createRouteLeaseSubscriptionPreflight(credentials) {
20069
20806
 
20070
20807
  // src/webhook/WebhookDispatcher.ts
20071
20808
  import { createHmac as createHmac6 } from "crypto";
20072
- import { fetchUpstream as fetchUpstream13 } from "@omnicross/core/pipeline/upstreamFetch";
20809
+ import { fetchUpstream as fetchUpstream15 } from "@omnicross/core/pipeline/upstreamFetch";
20073
20810
  var WEBHOOK_MAX_ATTEMPTS = 3;
20074
20811
  var WEBHOOK_QUEUE_MAX = 1e3;
20075
20812
  var WEBHOOK_SEND_TIMEOUT_MS = 1e4;
@@ -20089,7 +20826,7 @@ var WebhookDispatcher = class {
20089
20826
  sleep;
20090
20827
  now;
20091
20828
  constructor(opts = {}) {
20092
- this.fetchImpl = opts.fetchImpl ?? ((url, init) => fetchUpstream13(url, init));
20829
+ this.fetchImpl = opts.fetchImpl ?? ((url, init) => fetchUpstream15(url, init));
20093
20830
  this.logger = opts.logger;
20094
20831
  this.maxAttempts = opts.maxAttempts ?? WEBHOOK_MAX_ATTEMPTS;
20095
20832
  this.queueMax = opts.queueMax ?? WEBHOOK_QUEUE_MAX;
@@ -20175,8 +20912,8 @@ var WebhookDispatcher = class {
20175
20912
  signal: AbortSignal.timeout(this.timeoutMs)
20176
20913
  });
20177
20914
  return res.ok ? { ok: true, status: res.status } : { ok: false, status: res.status };
20178
- } catch (err8) {
20179
- return { ok: false, error: err8 instanceof Error ? err8.message : String(err8) };
20915
+ } catch (err9) {
20916
+ return { ok: false, error: err9 instanceof Error ? err9.message : String(err9) };
20180
20917
  }
20181
20918
  }
20182
20919
  /**
@@ -20318,7 +21055,7 @@ function buildDaemon(config, paths) {
20318
21055
  setSecretBox(secretBox3);
20319
21056
  setSecretBox2(secretBox3);
20320
21057
  const decryptedConfig = decryptConfigSecrets(config, secretBox3);
20321
- const accountAllowanceStore = new AccountAllowanceStore9(
21058
+ const accountAllowanceStore = new AccountAllowanceStore10(
20322
21059
  Date.now,
20323
21060
  void 0,
20324
21061
  new JsonAccountAllowancePersistence(defaultAccountAllowancePath(paths.configPath))
@@ -20362,6 +21099,8 @@ function buildDaemon(config, paths) {
20362
21099
  })
20363
21100
  );
20364
21101
  setGeminiCodeAssistResolver(getGeminiCodeAssistProjectResolver2());
21102
+ setAntigravitySandboxFailover(decryptedConfig.antigravity?.sandboxFailover === true);
21103
+ setOpenCodeGoUserAgent(decryptedConfig.opencodego?.userAgent ?? null);
20365
21104
  const autoDisableStore = new AutoDisableStore();
20366
21105
  const providerKeyQuotaService = new ProviderKeyQuotaService(secretBox3);
20367
21106
  const apiKeyPool = new ApiKeyPoolService(
@@ -20380,7 +21119,7 @@ function buildDaemon(config, paths) {
20380
21119
  const pricingEngine = new PricingEngine(pricingStore, logger, {
20381
21120
  // Catalog egress follows the same global/env proxy policy as every other
20382
21121
  // daemon upstream call; no provider/account override applies here.
20383
- fetchImpl: ((input, init) => fetchUpstream14(String(input), init ?? {}))
21122
+ fetchImpl: ((input, init) => fetchUpstream16(String(input), init ?? {}))
20384
21123
  });
20385
21124
  const pricingRefreshScheduler = new PricingRefreshScheduler(
20386
21125
  pricingEngine,
@@ -20622,6 +21361,7 @@ function buildDaemon(config, paths) {
20622
21361
  outboundApiServer,
20623
21362
  imageRuntimeConfig,
20624
21363
  imageRuntimeStatus: paths.imageRuntimeStatus ?? imageRuntimeManager,
21364
+ imageLiveVerifier: paths.imageLiveVerifier ?? imageDoctor,
20625
21365
  imageConfigAudit: paths.imageConfigAudit ?? ((record) => {
20626
21366
  imageObservability.recordConfigurationAudit(record);
20627
21367
  }),
@@ -20665,7 +21405,7 @@ function buildDaemon(config, paths) {
20665
21405
  // — `server.proxy.byProvider[...]` was silently skipped — and the call was
20666
21406
  // excluded from the upstream trace, so a failing login left no evidence.
20667
21407
  // `redactBodies` keeps the code/verifier + minted token out of that trace.
20668
- oauthExchangeFetch: paths.oauthExchangeFetch ? () => paths.oauthExchangeFetch : (providerId) => (url, init) => fetchUpstream14(url, init, { providerId, redactBodies: true }),
21408
+ oauthExchangeFetch: paths.oauthExchangeFetch ? () => paths.oauthExchangeFetch : (providerId) => (url, init) => fetchUpstream16(url, init, { providerId, redactBodies: true }),
20669
21409
  subscriptionAccountAppender: credentialStore,
20670
21410
  // Codex interactive OAuth (app-parity-2 child 5) — the async loopback flow store
20671
21411
  // + the one-shot 127.0.0.1:1455 listener. Token captured + persisted daemon-side;
@@ -20680,6 +21420,21 @@ function buildDaemon(config, paths) {
20680
21420
  // Grok interactive OAuth — the same async DEVICE-CODE shape as kimi.
20681
21421
  grokSessions: new CodexOAuthSessionStore(),
20682
21422
  copilotSessions: new CodexOAuthSessionStore(),
21423
+ // Antigravity interactive OAuth — the async LOOPBACK flow store + the
21424
+ // one-shot 127.0.0.1:51121 listener (same shape as codex; test seam below).
21425
+ antigravitySessions: new CodexOAuthSessionStore(),
21426
+ antigravityAwaitLoopback: paths.antigravityAwaitLoopback ?? ((state, timeoutMs, signal) => awaitLoopbackCode(state, timeoutMs, signal, {
21427
+ port: 51121,
21428
+ path: "/oauth-callback",
21429
+ label: "antigravity"
21430
+ })),
21431
+ // The dynamic model-catalog probe's token source (the ACTIVE antigravity
21432
+ // account; refreshed by the by-id near-expiry seam inside the lookup).
21433
+ resolveAntigravityAccessToken: async () => {
21434
+ const config2 = await credentialStore.getFullConfig();
21435
+ const activeId = config2.activeAntigravityAccountId ?? config2.antigravityAccounts?.[0]?.id;
21436
+ return activeId ? credentialStore.getAccessTokenForAccount("antigravity", activeId) : null;
21437
+ },
20683
21438
  // Migration pack (app-parity child 6, design D2/D3) — the concrete credential
20684
21439
  // store provides BOTH the full DECRYPTED read (`getFullConfig`, export) and
20685
21440
  // the multi-account append (`appendProviderAccount`, import re-encrypts at-
@@ -20738,7 +21493,7 @@ function buildDaemon(config, paths) {
20738
21493
  });
20739
21494
  const webhookDispatcher = new WebhookDispatcher({
20740
21495
  logger,
20741
- fetchImpl: (url, init) => fetchUpstream14(url, init)
21496
+ fetchImpl: (url, init) => fetchUpstream16(url, init)
20742
21497
  });
20743
21498
  setWebhookRuntime(webhookDispatcher, getSharedAccountHealth4());
20744
21499
  const auditWriter = new AuditWriter(auditDir, logger);