@omnicross/daemon 0.4.2 → 0.4.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.cjs CHANGED
@@ -953,7 +953,11 @@ var TOKEN_FIELDS = {
953
953
  claude: ["accessToken", "refreshToken"],
954
954
  codex: ["accessToken", "refreshToken", "idToken"],
955
955
  gemini: ["accessToken", "refreshToken"],
956
- opencodego: ["apiKey"]
956
+ opencodego: ["apiKey"],
957
+ kimi: ["accessToken", "refreshToken"],
958
+ grok: ["accessToken", "refreshToken"],
959
+ copilot: ["accessToken", "refreshToken"],
960
+ antigravity: ["accessToken", "refreshToken"]
957
961
  };
958
962
  function transformTokenBlock(block, fields, fn) {
959
963
  const next = { ...block };
@@ -1171,21 +1175,23 @@ var import_node_path36 = require("path");
1171
1175
  var import_audit_types = require("@omnicross/contracts/audit-types");
1172
1176
  var import_billing_types = require("@omnicross/contracts/billing-types");
1173
1177
  var import_core7 = require("@omnicross/core");
1174
- var import_GeminiCodeAssistProjectResolver2 = require("@omnicross/core/auth/GeminiCodeAssistProjectResolver");
1178
+ var import_GeminiCodeAssistProjectResolver6 = require("@omnicross/core/auth/GeminiCodeAssistProjectResolver");
1175
1179
  var import_ApiKeyPoolService = require("@omnicross/core/completion/ApiKeyPoolService");
1176
1180
  var import_outbound_api10 = require("@omnicross/core/outbound-api");
1177
1181
  var import_subscriptionRegistryPort = require("@omnicross/core/outbound-api/subscriptionRegistryPort");
1178
1182
  var import_SubscriptionAccountHealth4 = require("@omnicross/core/pipeline/SubscriptionAccountHealth");
1179
- var import_AccountAllowanceStore10 = require("@omnicross/core/pipeline/AccountAllowanceStore");
1183
+ var import_AccountAllowanceStore11 = require("@omnicross/core/pipeline/AccountAllowanceStore");
1180
1184
  var import_AccountAllowanceScheduling5 = require("@omnicross/core/pipeline/AccountAllowanceScheduling");
1181
- var import_upstreamFetch16 = require("@omnicross/core/pipeline/upstreamFetch");
1185
+ var import_upstreamFetch18 = require("@omnicross/core/pipeline/upstreamFetch");
1182
1186
  var import_SubscriptionIdentityStore3 = require("@omnicross/core/provider-proxy/identity/SubscriptionIdentityStore");
1183
1187
  var import_gemini_code_assist_resolver = require("@omnicross/core/ports/gemini-code-assist-resolver");
1188
+ var import_antigravityFailover = require("@omnicross/core/transformer/transformers/antigravityFailover");
1189
+ var import_openCodeGoHeaders2 = require("@omnicross/core/provider-proxy/identity/openCodeGoHeaders");
1184
1190
  var import_provider_proxy4 = require("@omnicross/core/provider-proxy");
1185
1191
  var import_cli_launcher2 = require("@omnicross/cli-launcher");
1186
1192
  var import_outbound_api11 = require("@omnicross/core/outbound-api");
1187
1193
  var import_usage2 = require("@omnicross/core/usage");
1188
- var import_subscriptions12 = require("@omnicross/subscriptions");
1194
+ var import_subscriptions13 = require("@omnicross/subscriptions");
1189
1195
 
1190
1196
  // src/admin/accountsCodexOAuth.ts
1191
1197
  var import_node_crypto3 = __toESM(require("crypto"), 1);
@@ -1547,7 +1553,7 @@ function handleCopilotOAuthStatus(sessionId, deps) {
1547
1553
  }
1548
1554
 
1549
1555
  // src/allowance/AccountAllowanceService.ts
1550
- var import_AccountAllowanceStore8 = require("@omnicross/core/pipeline/AccountAllowanceStore");
1556
+ var import_AccountAllowanceStore9 = require("@omnicross/core/pipeline/AccountAllowanceStore");
1551
1557
  var import_AccountAllowanceScheduling = require("@omnicross/core/pipeline/AccountAllowanceScheduling");
1552
1558
 
1553
1559
  // src/allowance/ClaudeAllowanceCollector.ts
@@ -2917,9 +2923,321 @@ var GeminiAllowanceCollector = class {
2917
2923
  }
2918
2924
  };
2919
2925
 
2920
- // src/allowance/OpenCodeGoAllowanceCollector.ts
2926
+ // src/allowance/AntigravityAllowanceCollector.ts
2927
+ var import_GeminiCodeAssistProjectResolver2 = require("@omnicross/core/auth/GeminiCodeAssistProjectResolver");
2928
+ var import_antigravityQuotaFamily = require("@omnicross/core/pipeline/antigravityQuotaFamily");
2921
2929
  var import_AccountAllowanceStore7 = require("@omnicross/core/pipeline/AccountAllowanceStore");
2922
2930
  var import_upstreamFetch7 = require("@omnicross/core/pipeline/upstreamFetch");
2931
+ var import_antigravityIdentity = require("@omnicross/core/transformer/transformers/antigravityIdentity");
2932
+ var ANTIGRAVITY_ALLOWANCE_CACHE_MS = 5 * 6e4;
2933
+ var RETRIEVE_USER_QUOTA_SUMMARY_PATH = "/v1internal:retrieveUserQuotaSummary";
2934
+ var FETCH_AVAILABLE_MODELS_PATH = "/v1internal:fetchAvailableModels";
2935
+ var ANTIGRAVITY_DISCOVERY_DENYLIST = /* @__PURE__ */ new Set([
2936
+ "chat_20706",
2937
+ "chat_23310",
2938
+ "gemini-2.5-pro"
2939
+ ]);
2940
+ function isRecord5(value) {
2941
+ return !!value && typeof value === "object" && !Array.isArray(value);
2942
+ }
2943
+ function secondsUntil7(instant, now) {
2944
+ if (!instant) return void 0;
2945
+ return Math.max(0, Math.floor((Date.parse(instant) - now) / 1e3));
2946
+ }
2947
+ var WINDOW_LABELS = {
2948
+ "five-hour": "5 Hour",
2949
+ weekly: "Weekly",
2950
+ daily: "Daily"
2951
+ };
2952
+ function classifyWindowId(...sources) {
2953
+ for (const source of sources) {
2954
+ if (!source) continue;
2955
+ const text = source.toLowerCase();
2956
+ if (text.includes("week") || text.includes("7d") || /7[\s_-]*day/.test(text)) return "weekly";
2957
+ if (text.includes("5h") || text.includes("five hour") || /5[\s_-]*hour/.test(text)) return "five-hour";
2958
+ if (text.includes("day") || text.includes("daily") || text.includes("24h")) return "daily";
2959
+ }
2960
+ return void 0;
2961
+ }
2962
+ function inferWindowFromReset(resetsAt, now) {
2963
+ if (resetsAt !== void 0 && Date.parse(resetsAt) - now > 24 * 60 * 60 * 1e3) return "weekly";
2964
+ return "daily";
2965
+ }
2966
+ function clampFraction(value) {
2967
+ if (value === void 0 || !Number.isFinite(value)) return void 0;
2968
+ return Math.min(1, Math.max(0, value));
2969
+ }
2970
+ function usedPercentFromFraction(fraction) {
2971
+ const clamped = clampFraction(fraction);
2972
+ if (clamped === void 0) return null;
2973
+ return Math.round((1 - clamped) * 1e3) / 10;
2974
+ }
2975
+ function toResetsAt(resetTime) {
2976
+ if (!resetTime || !Number.isFinite(Date.parse(resetTime))) return void 0;
2977
+ return new Date(Date.parse(resetTime)).toISOString();
2978
+ }
2979
+ function parseAntigravityQuotaSummary(payload, now) {
2980
+ if (!isRecord5(payload)) return null;
2981
+ const groups = Array.isArray(payload["groups"]) ? payload["groups"] : [];
2982
+ const topBuckets = Array.isArray(payload["buckets"]) ? payload["buckets"] : [];
2983
+ const hasGrouped = groups.some((group) => Array.isArray(group.buckets) && group.buckets.length > 0);
2984
+ if (!hasGrouped && topBuckets.length === 0) return null;
2985
+ const windows = /* @__PURE__ */ new Map();
2986
+ const addBucket = (bucket, groupName) => {
2987
+ const families = (0, import_antigravityQuotaFamily.antigravityCounterFamiliesForBucketId)(bucket.bucketId, groupName);
2988
+ if (families.length === 0) return;
2989
+ const resetsAt = toResetsAt(bucket.resetTime);
2990
+ const windowId = classifyWindowId(bucket.window, bucket.displayName, bucket.bucketId) ?? (resetsAt !== void 0 ? inferWindowFromReset(resetsAt, now) : void 0);
2991
+ if (windowId === void 0) return;
2992
+ const usedPercent = usedPercentFromFraction(bucket.remainingFraction) ?? (bucket.disabled === true || bucket.resetTime ? bucket.disabled === true ? 100 : null : null);
2993
+ for (const family of families) {
2994
+ const id = `antigravity:${family}:${windowId}`;
2995
+ const candidate = {
2996
+ id,
2997
+ label: `${WINDOW_LABELS[windowId]} (${family})`,
2998
+ scope: "model-family",
2999
+ // The window carries the MODEL family (gemini/claude/gpt-oss) — the
3000
+ // scheduling gate compares it against the requested model's family.
3001
+ modelFamily: import_antigravityQuotaFamily.ANTIGRAVITY_COUNTER_TO_MODEL_FAMILY[family],
3002
+ usedPercent,
3003
+ ...resetsAt !== void 0 ? { resetsAt } : {},
3004
+ remainingSeconds: secondsUntil7(resetsAt, now),
3005
+ state: "fresh",
3006
+ ...bucket.disabled === true ? { disabled: true } : {}
3007
+ };
3008
+ const existing = windows.get(id);
3009
+ if (!existing || candidate.disabled === true || existing.disabled !== true && (candidate.usedPercent ?? -1) > (existing.usedPercent ?? -1)) {
3010
+ windows.set(id, candidate);
3011
+ }
3012
+ }
3013
+ };
3014
+ if (hasGrouped) {
3015
+ for (const group of groups) {
3016
+ for (const bucket of group.buckets ?? []) addBucket(bucket, group.displayName);
3017
+ }
3018
+ } else {
3019
+ for (const bucket of topBuckets) addBucket(bucket);
3020
+ }
3021
+ const result = [...windows.values()];
3022
+ return result.length > 0 ? result : null;
3023
+ }
3024
+ function legacyQuotaInfos(model) {
3025
+ const out = [];
3026
+ const source = {
3027
+ ...model.apiProvider ? { apiProvider: model.apiProvider } : {},
3028
+ ...model.modelProvider ? { modelProvider: model.modelProvider } : {}
3029
+ };
3030
+ const add = (value, windowDefault) => {
3031
+ if (!value) return;
3032
+ const list = Array.isArray(value) ? value : [value];
3033
+ for (const info of list) {
3034
+ out.push({ ...source, ...windowDefault ? { windowId: windowDefault } : {}, ...info });
3035
+ }
3036
+ };
3037
+ add(model.quotaInfo);
3038
+ add(model.quotaInfos);
3039
+ add(model.dailyQuotaInfo, "daily");
3040
+ add(model.dailyQuotaInfos, "daily");
3041
+ add(model.weeklyQuotaInfo, "weekly");
3042
+ add(model.weeklyQuotaInfos, "weekly");
3043
+ return out;
3044
+ }
3045
+ function legacyCounterFamily(info) {
3046
+ switch (info.modelProvider ?? info.apiProvider) {
3047
+ case "MODEL_PROVIDER_ANTHROPIC":
3048
+ case "API_PROVIDER_ANTHROPIC_VERTEX":
3049
+ return "anthropic";
3050
+ case "MODEL_PROVIDER_GOOGLE":
3051
+ case "API_PROVIDER_GOOGLE_GEMINI":
3052
+ return "google";
3053
+ case "MODEL_PROVIDER_OPENAI":
3054
+ case "API_PROVIDER_OPENAI_VERTEX":
3055
+ return "openai";
3056
+ default:
3057
+ return void 0;
3058
+ }
3059
+ }
3060
+ function parseAntigravityLegacyQuota(payload, now) {
3061
+ if (!isRecord5(payload)) return null;
3062
+ const models = payload["models"];
3063
+ if (!isRecord5(models)) return null;
3064
+ const windows = /* @__PURE__ */ new Map();
3065
+ for (const info of Object.values(models).flatMap(legacyQuotaInfos)) {
3066
+ const family = legacyCounterFamily(info);
3067
+ if (!family) continue;
3068
+ const resetsAt = toResetsAt(info.resetTime);
3069
+ const windowId = classifyWindowId(info.windowId, info.windowLabel) ?? (resetsAt !== void 0 ? inferWindowFromReset(resetsAt, now) : void 0);
3070
+ if (windowId === void 0) continue;
3071
+ const id = `antigravity:${family}:${windowId}`;
3072
+ const candidate = {
3073
+ id,
3074
+ label: `${WINDOW_LABELS[windowId]} (${family})`,
3075
+ scope: "model-family",
3076
+ modelFamily: import_antigravityQuotaFamily.ANTIGRAVITY_COUNTER_TO_MODEL_FAMILY[family],
3077
+ usedPercent: usedPercentFromFraction(info.remainingFraction),
3078
+ ...resetsAt !== void 0 ? { resetsAt } : {},
3079
+ remainingSeconds: secondsUntil7(resetsAt, now),
3080
+ state: "fresh"
3081
+ };
3082
+ const existing = windows.get(id);
3083
+ if (!existing || (candidate.usedPercent ?? -1) > (existing.usedPercent ?? -1)) {
3084
+ windows.set(id, candidate);
3085
+ }
3086
+ }
3087
+ const result = [...windows.values()];
3088
+ return result.length > 0 ? result : null;
3089
+ }
3090
+ var AntigravityAllowanceCollector = class {
3091
+ constructor(credentials, store = (0, import_AccountAllowanceStore7.getSharedAccountAllowanceStore)(), fetchImpl = (url, init, accountId) => (0, import_upstreamFetch7.fetchUpstream)(url, init, { providerId: "antigravity", accountId, redactBodies: true }), now = Date.now) {
3092
+ this.credentials = credentials;
3093
+ this.store = store;
3094
+ this.fetchImpl = fetchImpl;
3095
+ this.now = now;
3096
+ }
3097
+ credentials;
3098
+ store;
3099
+ fetchImpl;
3100
+ now;
3101
+ inFlight = /* @__PURE__ */ new Map();
3102
+ async collectMany(accounts, options = {}) {
3103
+ const settled = await Promise.allSettled(
3104
+ accounts.map((account) => this.collect(account, options))
3105
+ );
3106
+ return settled.flatMap((result) => result.status === "fulfilled" ? [result.value] : []);
3107
+ }
3108
+ collect(account, options = {}) {
3109
+ const now = this.now();
3110
+ if (account.tokens.authMethod !== "oauth") {
3111
+ const existing = this.store.get("antigravity", account.id, now);
3112
+ if (existing?.windows.every((window) => window.state === "unsupported")) {
3113
+ return Promise.resolve(existing);
3114
+ }
3115
+ const snapshot = this.unsupportedSnapshot(account.id, now);
3116
+ this.store.set(snapshot);
3117
+ return Promise.resolve(snapshot);
3118
+ }
3119
+ const cached = this.store.get("antigravity", account.id, now);
3120
+ if (!options.force && cached && this.isCacheValid(cached, now, options.refreshAheadMs)) {
3121
+ return Promise.resolve(cached);
3122
+ }
3123
+ const running = this.inFlight.get(account.id);
3124
+ if (running) return running;
3125
+ const promise = this.fetchAccount(account.id).catch(() => this.failureSnapshot(account.id, "antigravity_usage_request_failed", this.now())).finally(() => this.inFlight.delete(account.id));
3126
+ this.inFlight.set(account.id, promise);
3127
+ return promise;
3128
+ }
3129
+ isCacheValid(snapshot, now, refreshAheadMs) {
3130
+ if (snapshot.windows.every((window) => window.state === "unsupported")) return true;
3131
+ const expiresAt = snapshot.expiresAt ? Date.parse(snapshot.expiresAt) : 0;
3132
+ const ahead = typeof refreshAheadMs === "number" && Number.isFinite(refreshAheadMs) ? Math.max(0, refreshAheadMs) : 0;
3133
+ return Number.isFinite(expiresAt) && expiresAt > now + ahead;
3134
+ }
3135
+ async fetchAccount(accountId) {
3136
+ let accessToken = await this.credentials.getAccessTokenForAccount("antigravity", accountId);
3137
+ if (!accessToken) return this.failureSnapshot(accountId, "antigravity_usage_token_unavailable", this.now());
3138
+ let response = await this.request(accountId, accessToken, RETRIEVE_USER_QUOTA_SUMMARY_PATH, {
3139
+ project: void 0
3140
+ });
3141
+ if (response.status === 401 || response.status === 403) {
3142
+ const refreshed = await this.credentials.refreshAccountToken("antigravity", accountId);
3143
+ if (!refreshed) return this.failureSnapshot(accountId, "antigravity_usage_unauthorized", this.now());
3144
+ accessToken = await this.credentials.getAccessTokenForAccount("antigravity", accountId);
3145
+ if (!accessToken) return this.failureSnapshot(accountId, "antigravity_usage_token_unavailable", this.now());
3146
+ response = await this.request(accountId, accessToken, RETRIEVE_USER_QUOTA_SUMMARY_PATH, {
3147
+ project: void 0
3148
+ });
3149
+ if (response.status === 401 || response.status === 403) {
3150
+ return this.failureSnapshot(accountId, "antigravity_usage_unauthorized", this.now());
3151
+ }
3152
+ }
3153
+ if (response.ok) {
3154
+ const payload = await response.json().catch(() => null);
3155
+ const windows = parseAntigravityQuotaSummary(payload, this.now());
3156
+ if (windows) {
3157
+ const snapshot2 = this.snapshot(accountId, windows);
3158
+ this.store.set(snapshot2);
3159
+ return snapshot2;
3160
+ }
3161
+ }
3162
+ const legacy = await this.request(accountId, accessToken, FETCH_AVAILABLE_MODELS_PATH, {});
3163
+ if (!legacy.ok) {
3164
+ return this.failureSnapshot(accountId, "antigravity_usage_http_error", this.now());
3165
+ }
3166
+ const legacyPayload = await legacy.json().catch(() => null);
3167
+ const legacyWindows = parseAntigravityLegacyQuota(legacyPayload, this.now());
3168
+ if (!legacyWindows) {
3169
+ return this.failureSnapshot(accountId, "antigravity_usage_invalid_response", this.now());
3170
+ }
3171
+ const snapshot = this.snapshot(accountId, legacyWindows);
3172
+ this.store.set(snapshot);
3173
+ return snapshot;
3174
+ }
3175
+ /** One upstream round-trip with the antigravity/hub masquerade UA. */
3176
+ request(accountId, accessToken, path2, body) {
3177
+ return this.fetchImpl(`${import_GeminiCodeAssistProjectResolver2.ANTIGRAVITY_CODE_ASSIST_ENDPOINT}${path2}`, {
3178
+ method: "POST",
3179
+ headers: {
3180
+ Authorization: `Bearer ${accessToken}`,
3181
+ Accept: "application/json",
3182
+ "Content-Type": "application/json",
3183
+ "User-Agent": (0, import_antigravityIdentity.getAntigravityUserAgent)()
3184
+ },
3185
+ body: JSON.stringify(body),
3186
+ signal: AbortSignal.timeout(15e3)
3187
+ }, accountId);
3188
+ }
3189
+ snapshot(accountId, windows, now = this.now()) {
3190
+ return {
3191
+ providerId: "antigravity",
3192
+ accountId,
3193
+ source: "oauth-usage-api",
3194
+ observedAt: new Date(now).toISOString(),
3195
+ expiresAt: new Date(now + ANTIGRAVITY_ALLOWANCE_CACHE_MS).toISOString(),
3196
+ windows
3197
+ };
3198
+ }
3199
+ failureSnapshot(accountId, code, now) {
3200
+ const existing = this.store.get("antigravity", accountId, now);
3201
+ const snapshot = existing ? {
3202
+ ...existing,
3203
+ expiresAt: new Date(now + ANTIGRAVITY_ALLOWANCE_CACHE_MS).toISOString(),
3204
+ windows: existing.windows.map((window) => ({
3205
+ ...window,
3206
+ state: window.state === "unsupported" ? "unsupported" : window.usedPercent !== null || window.resetsAt || window.disabled ? "stale" : "unavailable"
3207
+ })),
3208
+ lastErrorCode: code
3209
+ } : {
3210
+ providerId: "antigravity",
3211
+ accountId,
3212
+ source: "oauth-usage-api",
3213
+ observedAt: new Date(now).toISOString(),
3214
+ expiresAt: new Date(now + ANTIGRAVITY_ALLOWANCE_CACHE_MS).toISOString(),
3215
+ windows: [
3216
+ { id: "antigravity-quota", label: "Antigravity quota", scope: "all", usedPercent: null, state: "unavailable" }
3217
+ ],
3218
+ lastErrorCode: code
3219
+ };
3220
+ this.store.set(snapshot);
3221
+ return snapshot;
3222
+ }
3223
+ unsupportedSnapshot(accountId, now) {
3224
+ return {
3225
+ providerId: "antigravity",
3226
+ accountId,
3227
+ source: "oauth-usage-api",
3228
+ observedAt: new Date(now).toISOString(),
3229
+ windows: [
3230
+ { id: "antigravity-quota", label: "Antigravity quota", scope: "all", usedPercent: null, state: "unsupported" }
3231
+ ],
3232
+ lastErrorCode: "antigravity_usage_unsupported_auth"
3233
+ };
3234
+ }
3235
+ };
3236
+
3237
+ // src/allowance/OpenCodeGoAllowanceCollector.ts
3238
+ var import_AccountAllowanceStore8 = require("@omnicross/core/pipeline/AccountAllowanceStore");
3239
+ var import_upstreamFetch8 = require("@omnicross/core/pipeline/upstreamFetch");
3240
+ var import_openCodeGoHeaders = require("@omnicross/core/provider-proxy/identity/openCodeGoHeaders");
2923
3241
  var import_subscriptions7 = require("@omnicross/subscriptions");
2924
3242
  var OPENCODEGO_ALLOWANCE_CACHE_MS = 5 * 6e4;
2925
3243
  var OPENCODEGO_DEFAULT_GO_BASE = "https://opencode.ai/zen/go";
@@ -2933,7 +3251,7 @@ function isoInstant2(value) {
2933
3251
  const time = Date.parse(value);
2934
3252
  return Number.isFinite(time) ? new Date(time).toISOString() : void 0;
2935
3253
  }
2936
- function secondsUntil7(instant, now) {
3254
+ function secondsUntil8(instant, now) {
2937
3255
  if (!instant) return void 0;
2938
3256
  return Math.max(0, Math.floor((Date.parse(instant) - now) / 1e3));
2939
3257
  }
@@ -2948,12 +3266,12 @@ function windowFromPayload3(id, label, minutes, payload, now) {
2948
3266
  usedPercent,
2949
3267
  windowMinutes: minutes,
2950
3268
  ...resetsAt !== void 0 ? { resetsAt } : {},
2951
- remainingSeconds: secondsUntil7(resetsAt, now),
3269
+ remainingSeconds: secondsUntil8(resetsAt, now),
2952
3270
  state: usedPercent !== null || resetsAt ? "fresh" : "unavailable"
2953
3271
  };
2954
3272
  }
2955
3273
  var OpenCodeGoAllowanceCollector = class {
2956
- constructor(credentials, store = (0, import_AccountAllowanceStore7.getSharedAccountAllowanceStore)(), fetchImpl = (url, init, accountId) => (0, import_upstreamFetch7.fetchUpstream)(url, init, { providerId: "opencodego", accountId, redactBodies: true }), now = Date.now) {
3274
+ constructor(credentials, store = (0, import_AccountAllowanceStore8.getSharedAccountAllowanceStore)(), fetchImpl = (url, init, accountId) => (0, import_upstreamFetch8.fetchUpstream)(url, init, { providerId: "opencodego", accountId, redactBodies: true }), now = Date.now) {
2957
3275
  this.credentials = credentials;
2958
3276
  this.store = store;
2959
3277
  this.fetchImpl = fetchImpl;
@@ -2986,7 +3304,14 @@ var OpenCodeGoAllowanceCollector = class {
2986
3304
  const base = account.tokens.baseUrl ? (0, import_subscriptions7.normalizeOpenCodeGoBaseUrl)(account.tokens.baseUrl) : OPENCODEGO_DEFAULT_GO_BASE;
2987
3305
  const response = await this.fetchImpl(`${base}/v1/usage`, {
2988
3306
  method: "GET",
2989
- headers: { Authorization: `Bearer ${apiKey}`, Accept: "application/json" },
3307
+ // opencodego-egress-identity: the background poll identifies itself with
3308
+ // the same configured/default UA the relay carries (no session header —
3309
+ // a poll has no conversation).
3310
+ headers: {
3311
+ Authorization: `Bearer ${apiKey}`,
3312
+ Accept: "application/json",
3313
+ "User-Agent": (0, import_openCodeGoHeaders.getOpenCodeGoUserAgent)()
3314
+ },
2990
3315
  signal: AbortSignal.timeout(15e3)
2991
3316
  }, account.id);
2992
3317
  if (response.status === 401 || response.status === 403) {
@@ -3058,7 +3383,7 @@ function codexUnavailable(accountId, now) {
3058
3383
  };
3059
3384
  }
3060
3385
  var AccountAllowanceService = class {
3061
- constructor(credentials, store = (0, import_AccountAllowanceStore8.getSharedAccountAllowanceStore)(), collector, codexCollector, kimiCollector, opencodegoCollector, grokCollector, copilotCollector, geminiCollector, now = Date.now) {
3386
+ constructor(credentials, store = (0, import_AccountAllowanceStore9.getSharedAccountAllowanceStore)(), collector, codexCollector, kimiCollector, opencodegoCollector, grokCollector, copilotCollector, geminiCollector, antigravityCollector, now = Date.now) {
3062
3387
  this.credentials = credentials;
3063
3388
  this.store = store;
3064
3389
  this.now = now;
@@ -3069,6 +3394,7 @@ var AccountAllowanceService = class {
3069
3394
  this.grokCollector = grokCollector ?? new GrokAllowanceCollector(credentials, store);
3070
3395
  this.copilotCollector = copilotCollector ?? new CopilotAllowanceCollector(credentials, store);
3071
3396
  this.geminiCollector = geminiCollector ?? new GeminiAllowanceCollector(credentials, store);
3397
+ this.antigravityCollector = antigravityCollector ?? new AntigravityAllowanceCollector(credentials, store);
3072
3398
  }
3073
3399
  credentials;
3074
3400
  store;
@@ -3080,6 +3406,7 @@ var AccountAllowanceService = class {
3080
3406
  copilotCollector;
3081
3407
  opencodegoCollector;
3082
3408
  geminiCollector;
3409
+ antigravityCollector;
3083
3410
  /**
3084
3411
  * Read all/filtered snapshots. Claude's and Codex's five-minute caches are
3085
3412
  * refreshed lazily on read (Codex polls `/backend-api/wham/usage`; the
@@ -3128,6 +3455,11 @@ var AccountAllowanceService = class {
3128
3455
  (account) => !filter.accountId || account.id === filter.accountId
3129
3456
  );
3130
3457
  if (wantsGemini) await this.geminiCollector.collectMany(geminiAccounts);
3458
+ const wantsAntigravity = !filter.providerId || filter.providerId === "antigravity";
3459
+ const antigravityAccounts = (config.antigravityAccounts ?? []).filter(
3460
+ (account) => !filter.accountId || account.id === filter.accountId
3461
+ );
3462
+ if (wantsAntigravity) await this.antigravityCollector.collectMany(antigravityAccounts);
3131
3463
  const known = /* @__PURE__ */ new Set();
3132
3464
  if (wantsClaude) for (const account of claudeAccounts) known.add(`claude\0${account.id}`);
3133
3465
  if (wantsCodex) for (const account of codexAccounts) known.add(`codex\0${account.id}`);
@@ -3136,6 +3468,7 @@ var AccountAllowanceService = class {
3136
3468
  if (wantsGrok) for (const account of grokAccounts) known.add(`grok\0${account.id}`);
3137
3469
  if (wantsCopilot) for (const account of copilotAccounts) known.add(`copilot\0${account.id}`);
3138
3470
  if (wantsGemini) for (const account of geminiAccounts) known.add(`gemini\0${account.id}`);
3471
+ if (wantsAntigravity) for (const account of antigravityAccounts) known.add(`antigravity\0${account.id}`);
3139
3472
  return this.store.list(filter).filter((snapshot) => known.has(`${snapshot.providerId}\0${snapshot.accountId}`));
3140
3473
  }
3141
3474
  knownAccounts(config) {
@@ -3146,7 +3479,8 @@ var AccountAllowanceService = class {
3146
3479
  ...(config.opencodegoAccounts ?? []).map((account) => ({ providerId: "opencodego", accountId: account.id })),
3147
3480
  ...(config.grokAccounts ?? []).map((account) => ({ providerId: "grok", accountId: account.id })),
3148
3481
  ...(config.copilotAccounts ?? []).map((account) => ({ providerId: "copilot", accountId: account.id })),
3149
- ...(config.geminiAccounts ?? []).map((account) => ({ providerId: "gemini", accountId: account.id }))
3482
+ ...(config.geminiAccounts ?? []).map((account) => ({ providerId: "gemini", accountId: account.id })),
3483
+ ...(config.antigravityAccounts ?? []).map((account) => ({ providerId: "antigravity", accountId: account.id }))
3150
3484
  ];
3151
3485
  }
3152
3486
  /** Force-refresh Claude usage for one account or every stored Claude account. */
@@ -3216,6 +3550,15 @@ var AccountAllowanceService = class {
3216
3550
  );
3217
3551
  return this.geminiCollector.collectMany(accounts, { force: true });
3218
3552
  }
3553
+ /** Force-refresh Antigravity usage (quotaSummary dual buckets) for one/all accounts. */
3554
+ async refreshAntigravity(accountId) {
3555
+ const config = await this.credentials.getFullConfig();
3556
+ this.store.pruneToKnownAccounts(this.knownAccounts(config));
3557
+ const accounts = (config.antigravityAccounts ?? []).filter(
3558
+ (account) => !accountId || account.id === accountId
3559
+ );
3560
+ return this.antigravityCollector.collectMany(accounts, { force: true });
3561
+ }
3219
3562
  /**
3220
3563
  * Keep Claude + Codex + Kimi snapshots warm for allowance-aware routing. All
3221
3564
  * collectors preserve their cache + per-account in-flight coalescing; a tick
@@ -3233,6 +3576,7 @@ var AccountAllowanceService = class {
3233
3576
  await this.grokCollector.collectMany(config.grokAccounts ?? [], { refreshAheadMs });
3234
3577
  await this.copilotCollector.collectMany(config.copilotAccounts ?? [], { refreshAheadMs });
3235
3578
  await this.geminiCollector.collectMany(config.geminiAccounts ?? [], { refreshAheadMs });
3579
+ await this.antigravityCollector.collectMany(config.antigravityAccounts ?? [], { refreshAheadMs });
3236
3580
  }
3237
3581
  /** Remove a cache row as soon as an account is deleted by the admin path. */
3238
3582
  removeAccountSnapshot(providerId, accountId) {
@@ -3327,7 +3671,7 @@ var ClaudeAllowanceRefreshScheduler = class {
3327
3671
  var import_node_crypto4 = require("crypto");
3328
3672
  var import_node_fs6 = require("fs");
3329
3673
  var import_node_path6 = require("path");
3330
- var import_AccountAllowanceStore9 = require("@omnicross/core/pipeline/AccountAllowanceStore");
3674
+ var import_AccountAllowanceStore10 = require("@omnicross/core/pipeline/AccountAllowanceStore");
3331
3675
  var ACCOUNT_ALLOWANCE_CACHE_VERSION = 1;
3332
3676
  var MAX_PERSISTED_ALLOWANCE_SNAPSHOTS = 256;
3333
3677
  var MAX_ALLOWANCE_CACHE_BYTES = 1e6;
@@ -3356,7 +3700,7 @@ var JsonAccountAllowancePersistence = class {
3356
3700
  save(snapshots) {
3357
3701
  const rows = [];
3358
3702
  for (const snapshot of snapshots) {
3359
- const normalized2 = (0, import_AccountAllowanceStore9.normalizeAccountAllowanceSnapshot)(snapshot);
3703
+ const normalized2 = (0, import_AccountAllowanceStore10.normalizeAccountAllowanceSnapshot)(snapshot);
3360
3704
  if (!normalized2) continue;
3361
3705
  rows.push(normalized2);
3362
3706
  if (rows.length >= MAX_PERSISTED_ALLOWANCE_SNAPSHOTS) break;
@@ -3632,7 +3976,7 @@ var import_outbound_api5 = require("@omnicross/core/outbound-api");
3632
3976
  var import_image_generation_types = require("@omnicross/contracts/image-generation-types");
3633
3977
  var import_AccountAllowanceScheduling2 = require("@omnicross/core/pipeline/AccountAllowanceScheduling");
3634
3978
  var import_SubscriptionAccountHealth = require("@omnicross/core/pipeline/SubscriptionAccountHealth");
3635
- var import_upstreamFetch10 = require("@omnicross/core/pipeline/upstreamFetch");
3979
+ var import_upstreamFetch12 = require("@omnicross/core/pipeline/upstreamFetch");
3636
3980
  var import_core3 = require("@omnicross/core");
3637
3981
 
3638
3982
  // src/image-generation/imagesConfigValidation.ts
@@ -3949,6 +4293,19 @@ function resolveAdminConfig(admin) {
3949
4293
  token: typeof admin?.token === "string" && admin.token.length > 0 ? admin.token : void 0
3950
4294
  };
3951
4295
  }
4296
+ function validateAntigravity(raw) {
4297
+ if (!raw || typeof raw !== "object" || Array.isArray(raw)) return void 0;
4298
+ const a = raw;
4299
+ if (typeof a["sandboxFailover"] !== "boolean") return void 0;
4300
+ return { sandboxFailover: a["sandboxFailover"] };
4301
+ }
4302
+ function validateOpenCodeGo(raw) {
4303
+ if (!raw || typeof raw !== "object" || Array.isArray(raw)) return void 0;
4304
+ const o = raw;
4305
+ const ua = o["userAgent"];
4306
+ if (typeof ua !== "string" || ua.trim().length === 0) return void 0;
4307
+ return { userAgent: ua.trim() };
4308
+ }
3952
4309
  function validateUsage(raw) {
3953
4310
  if (!raw || typeof raw !== "object" || Array.isArray(raw)) return void 0;
3954
4311
  const u = raw;
@@ -4242,7 +4599,9 @@ function validateConfig(raw) {
4242
4599
  const admin = validateAdmin(obj["admin"]);
4243
4600
  const logging = validateLogging(obj["logging"]);
4244
4601
  const usage = validateUsage(obj["usage"]);
4245
- return { providers, server, admin, logging };
4602
+ const antigravity = validateAntigravity(obj["antigravity"]);
4603
+ const opencodego = validateOpenCodeGo(obj["opencodego"]);
4604
+ return { providers, server, admin, logging, usage, antigravity, opencodego };
4246
4605
  }
4247
4606
  var secretBox = null;
4248
4607
  function setSecretBox(box) {
@@ -5286,11 +5645,11 @@ function preserveOutboundProxySecrets(incoming, current) {
5286
5645
  }
5287
5646
 
5288
5647
  // src/proxy/upstreamProxyResolver.ts
5289
- var import_upstreamFetch8 = require("@omnicross/core/pipeline/upstreamFetch");
5648
+ var import_upstreamFetch9 = require("@omnicross/core/pipeline/upstreamFetch");
5290
5649
  var serverProxy;
5291
5650
  function setServerProxyConfig(proxy) {
5292
5651
  serverProxy = proxy;
5293
- (0, import_upstreamFetch8.bumpUpstreamProxyGeneration)();
5652
+ (0, import_upstreamFetch9.bumpUpstreamProxyGeneration)();
5294
5653
  }
5295
5654
  function getServerProxyConfig() {
5296
5655
  return serverProxy;
@@ -5357,8 +5716,169 @@ function createUpstreamProxyResolver(src = {}) {
5357
5716
  };
5358
5717
  }
5359
5718
 
5360
- // src/admin/accountsOAuth.ts
5719
+ // src/admin/accountsAntigravityOAuth.ts
5720
+ var import_GeminiCodeAssistProjectResolver3 = require("@omnicross/core/auth/GeminiCodeAssistProjectResolver");
5361
5721
  var import_subscriptions8 = require("@omnicross/subscriptions");
5722
+ function err5(status, message) {
5723
+ return { status, body: { error: { type: "admin_api_error", message } } };
5724
+ }
5725
+ var DEFAULT_ANTIGRAVITY_OAUTH_TTL_MS = 10 * 6e4;
5726
+ function handleAntigravityOAuthStart(deps) {
5727
+ if (deps.antigravitySessions.isBusy()) {
5728
+ return err5(
5729
+ 409,
5730
+ "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"
5731
+ );
5732
+ }
5733
+ const { authUrl, state } = import_subscriptions8.antigravityOAuth.generateAuthParams();
5734
+ const { sessionId, signal } = deps.antigravitySessions.begin();
5735
+ void runAntigravityLoopback(sessionId, state, signal, deps);
5736
+ return { status: 200, body: { authUrl, sessionId } };
5737
+ }
5738
+ async function runAntigravityLoopback(sessionId, state, signal, deps) {
5739
+ const isPending = () => !signal.aborted && deps.antigravitySessions.get(sessionId)?.status === "pending";
5740
+ try {
5741
+ const code = await deps.antigravityAwaitLoopback(state, void 0, signal);
5742
+ if (!isPending()) return;
5743
+ const exchangeFetch = deps.oauthExchangeFetch("antigravity");
5744
+ const result = await import_subscriptions8.antigravityOAuth.exchangeCodeForTokens(code, exchangeFetch);
5745
+ if (!isPending()) return;
5746
+ const expiresAt = new Date(Date.now() + result.expiresIn * 1e3).toISOString();
5747
+ const email = await import_subscriptions8.antigravityOAuth.fetchUserEmail(result.accessToken, exchangeFetch);
5748
+ if (!isPending()) return;
5749
+ const projectId = await (0, import_GeminiCodeAssistProjectResolver3.getAntigravityProjectResolver)().resolveProject(result.accessToken);
5750
+ if (!isPending()) return;
5751
+ const block = {
5752
+ authMethod: "oauth",
5753
+ status: "authorized",
5754
+ accessToken: result.accessToken,
5755
+ refreshToken: result.refreshToken,
5756
+ expiresAt,
5757
+ ...email ? { email } : {},
5758
+ ...projectId ? { projectId } : {},
5759
+ lastRefreshedAt: (/* @__PURE__ */ new Date()).toISOString()
5760
+ };
5761
+ await deps.subscriptionAccountAppender.appendProviderAccount("antigravity", block);
5762
+ if (isPending()) deps.antigravitySessions.settle(sessionId, "done");
5763
+ } catch (e) {
5764
+ if (!isPending()) return;
5765
+ const reason = e instanceof Error ? e.message : "antigravity sign-in failed";
5766
+ deps.antigravitySessions.settle(sessionId, "error", reason);
5767
+ }
5768
+ }
5769
+ function handleAntigravityOAuthCancel(sessionId, deps) {
5770
+ if (!deps.antigravitySessions.cancel(sessionId)) {
5771
+ return err5(404, "unknown or expired antigravity sign-in session");
5772
+ }
5773
+ return { status: 200, body: { ok: true } };
5774
+ }
5775
+ function handleAntigravityOAuthStatus(sessionId, deps) {
5776
+ const s = deps.antigravitySessions.get(sessionId);
5777
+ if (!s) return err5(404, "unknown or expired antigravity sign-in session");
5778
+ return { status: 200, body: { state: s.status, ...s.error ? { message: s.error } : {} } };
5779
+ }
5780
+
5781
+ // src/allowance/AntigravityModelDiscovery.ts
5782
+ var import_canonical_models = require("@omnicross/contracts/canonical-models");
5783
+ var import_subscription_model_catalog = require("@omnicross/contracts/subscription-model-catalog");
5784
+ var import_GeminiCodeAssistProjectResolver4 = require("@omnicross/core/auth/GeminiCodeAssistProjectResolver");
5785
+ var import_upstreamFetch10 = require("@omnicross/core/pipeline/upstreamFetch");
5786
+ var import_antigravityIdentity2 = require("@omnicross/core/transformer/transformers/antigravityIdentity");
5787
+ function isRecord6(value) {
5788
+ return !!value && typeof value === "object" && !Array.isArray(value);
5789
+ }
5790
+ function optionalString(value) {
5791
+ return typeof value === "string" && value.length > 0 ? value : void 0;
5792
+ }
5793
+ function optionalNumber(value) {
5794
+ return typeof value === "number" && Number.isFinite(value) && value > 0 ? value : void 0;
5795
+ }
5796
+ function optionalBoolean(value) {
5797
+ return typeof value === "boolean" ? value : void 0;
5798
+ }
5799
+ function parseAntigravityAvailableModels(payload) {
5800
+ if (!isRecord6(payload)) return [];
5801
+ const models = payload["models"];
5802
+ if (!isRecord6(models)) return [];
5803
+ const out = [];
5804
+ for (const [id, raw] of Object.entries(models)) {
5805
+ if (ANTIGRAVITY_DISCOVERY_DENYLIST.has(id)) continue;
5806
+ if (!isRecord6(raw)) continue;
5807
+ if (raw["isInternal"] === true) continue;
5808
+ out.push({
5809
+ id,
5810
+ ...optionalString(raw["displayName"]) ? { displayName: optionalString(raw["displayName"]) } : {},
5811
+ ...optionalBoolean(raw["supportsImages"]) !== void 0 ? { supportsImages: optionalBoolean(raw["supportsImages"]) } : {},
5812
+ ...optionalBoolean(raw["supportsThinking"]) !== void 0 ? { supportsThinking: optionalBoolean(raw["supportsThinking"]) } : {},
5813
+ ...optionalNumber(raw["thinkingBudget"]) !== void 0 ? { thinkingBudget: optionalNumber(raw["thinkingBudget"]) } : {},
5814
+ ...optionalNumber(raw["maxTokens"]) !== void 0 ? { maxTokens: optionalNumber(raw["maxTokens"]) } : {},
5815
+ ...optionalNumber(raw["maxOutputTokens"]) !== void 0 ? { maxOutputTokens: optionalNumber(raw["maxOutputTokens"]) } : {}
5816
+ });
5817
+ }
5818
+ out.sort((a, b) => a.id.localeCompare(b.id));
5819
+ return out;
5820
+ }
5821
+ function mergeAntigravityCatalog(discovered, log = (line) => console.warn(line), staticIds = import_subscription_model_catalog.SUBSCRIPTION_MODEL_CATALOG.antigravity) {
5822
+ const entries = staticIds.map((id) => {
5823
+ const capabilities = (0, import_canonical_models.lookupCanonicalCapabilities)(id);
5824
+ return {
5825
+ id,
5826
+ origin: "static",
5827
+ displayName: id,
5828
+ ...capabilities?.vision !== void 0 ? { supportsImages: capabilities.vision } : {},
5829
+ ...capabilities?.reasoning !== void 0 ? { supportsThinking: capabilities.reasoning } : {},
5830
+ ...capabilities?.thinkingTokenLimit ? { thinkingBudget: capabilities.thinkingTokenLimit.max } : {},
5831
+ // Discovery calls the context window maxTokens, not the output ceiling.
5832
+ ...capabilities?.contextLength !== void 0 ? { maxTokens: capabilities.contextLength } : {},
5833
+ ...capabilities?.maxTokens !== void 0 ? { maxOutputTokens: capabilities.maxTokens } : {}
5834
+ };
5835
+ });
5836
+ const staticSet = new Set(staticIds);
5837
+ for (const model of discovered) {
5838
+ if (staticSet.has(model.id)) {
5839
+ log(
5840
+ `[AntigravityModelDiscovery] dynamic model '${model.id}' conflicts with the static catalog \u2014 static entry kept`
5841
+ );
5842
+ continue;
5843
+ }
5844
+ entries.push({ ...model, origin: "discovered" });
5845
+ }
5846
+ return entries;
5847
+ }
5848
+ async function fetchAntigravityAvailableModels(accessToken, fetchImpl = (url, init) => (0, import_upstreamFetch10.fetchUpstream)(url, init, { providerId: "antigravity", redactBodies: true })) {
5849
+ let response;
5850
+ try {
5851
+ response = await fetchImpl(`${import_GeminiCodeAssistProjectResolver4.ANTIGRAVITY_CODE_ASSIST_ENDPOINT}/v1internal:fetchAvailableModels`, {
5852
+ method: "POST",
5853
+ headers: {
5854
+ Authorization: `Bearer ${accessToken}`,
5855
+ Accept: "application/json",
5856
+ "Content-Type": "application/json",
5857
+ "User-Agent": (0, import_antigravityIdentity2.getAntigravityUserAgent)()
5858
+ },
5859
+ body: JSON.stringify({}),
5860
+ signal: AbortSignal.timeout(15e3)
5861
+ });
5862
+ } catch {
5863
+ return null;
5864
+ }
5865
+ if (!response.ok) return null;
5866
+ const payload = await response.json().catch(() => null);
5867
+ if (!isRecord6(payload) || !isRecord6(payload["models"])) return null;
5868
+ return parseAntigravityAvailableModels(payload);
5869
+ }
5870
+ async function handleAntigravityModelsRoute(deps) {
5871
+ const accessToken = await deps.resolveAntigravityAccessToken().catch(() => null);
5872
+ const discovered = accessToken ? await fetchAntigravityAvailableModels(accessToken, deps.fetchImpl) : null;
5873
+ const models = mergeAntigravityCatalog(discovered ?? []);
5874
+ return {
5875
+ status: 200,
5876
+ body: { models, discovered: discovered !== null }
5877
+ };
5878
+ }
5879
+
5880
+ // src/admin/accountsOAuth.ts
5881
+ var import_subscriptions9 = require("@omnicross/subscriptions");
5362
5882
 
5363
5883
  // src/admin/accountsWrite.ts
5364
5884
  var VALID_PROVIDER_IDS = [
@@ -5368,7 +5888,8 @@ var VALID_PROVIDER_IDS = [
5368
5888
  "opencodego",
5369
5889
  "kimi",
5370
5890
  "grok",
5371
- "copilot"
5891
+ "copilot",
5892
+ "antigravity"
5372
5893
  ];
5373
5894
  function asSubscriptionProviderId(id) {
5374
5895
  return VALID_PROVIDER_IDS.includes(id) ? id : null;
@@ -5550,7 +6071,7 @@ function validateCopilot(body) {
5550
6071
  ]);
5551
6072
  return out;
5552
6073
  }
5553
- function validateOpenCodeGo(body) {
6074
+ function validateOpenCodeGo2(body) {
5554
6075
  const authMethod = str(body["authMethod"]);
5555
6076
  const status = str(body["status"]);
5556
6077
  if (authMethod !== "manual") return null;
@@ -5584,7 +6105,7 @@ function validateTokenBody(providerId, body) {
5584
6105
  case "gemini":
5585
6106
  return validateGemini(body);
5586
6107
  case "opencodego":
5587
- return validateOpenCodeGo(body);
6108
+ return validateOpenCodeGo2(body);
5588
6109
  case "kimi":
5589
6110
  return validateKimi(body);
5590
6111
  case "grok":
@@ -5620,37 +6141,37 @@ async function statusEntryFor(reader, providerId) {
5620
6141
 
5621
6142
  // src/admin/accountsOAuth.ts
5622
6143
  var OAUTH_HTTP_PROVIDERS = /* @__PURE__ */ new Set(["claude", "gemini"]);
5623
- function err5(status, message) {
6144
+ function err6(status, message) {
5624
6145
  return { status, body: { error: { type: "admin_api_error", message } } };
5625
6146
  }
5626
6147
  function handleOAuthStart(providerId, deps) {
5627
6148
  if (!OAUTH_HTTP_PROVIDERS.has(providerId)) {
5628
- return err5(400, `oauth not available for provider '${providerId}'`);
6149
+ return err6(400, `oauth not available for provider '${providerId}'`);
5629
6150
  }
5630
- const flow = providerId === "claude" ? import_subscriptions8.claudeOAuth : import_subscriptions8.geminiOAuth;
6151
+ const flow = providerId === "claude" ? import_subscriptions9.claudeOAuth : import_subscriptions9.geminiOAuth;
5631
6152
  const { authUrl, codeVerifier, state } = flow.generateAuthParams();
5632
6153
  const sessionId = deps.oauthSessions.put({ providerId, codeVerifier, state });
5633
6154
  return { status: 200, body: { authUrl, sessionId } };
5634
6155
  }
5635
6156
  async function handleOAuthComplete(providerId, body, deps) {
5636
6157
  if (!OAUTH_HTTP_PROVIDERS.has(providerId)) {
5637
- return err5(400, `oauth not available for provider '${providerId}'`);
6158
+ return err6(400, `oauth not available for provider '${providerId}'`);
5638
6159
  }
5639
6160
  const sessionId = typeof body["sessionId"] === "string" ? body["sessionId"] : "";
5640
6161
  const rawCode = typeof body["code"] === "string" ? body["code"] : "";
5641
- if (!sessionId) return err5(400, "oauth complete requires { sessionId }");
5642
- if (!rawCode) return err5(400, "oauth complete requires { code }");
6162
+ if (!sessionId) return err6(400, "oauth complete requires { sessionId }");
6163
+ if (!rawCode) return err6(400, "oauth complete requires { code }");
5643
6164
  const session = deps.oauthSessions.peek(sessionId);
5644
- if (!session) return err5(410, "oauth session is unknown, expired, or already used");
6165
+ if (!session) return err6(410, "oauth session is unknown, expired, or already used");
5645
6166
  if (session.providerId !== providerId) {
5646
- return err5(400, `oauth session does not match provider '${providerId}'`);
6167
+ return err6(400, `oauth session does not match provider '${providerId}'`);
5647
6168
  }
5648
6169
  let code = rawCode.trim();
5649
6170
  if (providerId === "claude") {
5650
6171
  const [splitCode, pastedState] = code.split("#");
5651
- if (!splitCode) return err5(400, "no authorization code was provided");
6172
+ if (!splitCode) return err6(400, "no authorization code was provided");
5652
6173
  if (pastedState && pastedState !== session.state) {
5653
- return err5(400, "oauth state did not match (possible CSRF) \u2014 aborting");
6174
+ return err6(400, "oauth state did not match (possible CSRF) \u2014 aborting");
5654
6175
  }
5655
6176
  code = splitCode;
5656
6177
  }
@@ -5660,7 +6181,7 @@ async function handleOAuthComplete(providerId, body, deps) {
5660
6181
  block = providerId === "claude" ? await exchangeClaude(code, session.codeVerifier, session.state, exchangeFetch) : await exchangeGemini(code, session.codeVerifier, exchangeFetch);
5661
6182
  } catch (exchangeError) {
5662
6183
  const reason = exchangeError instanceof Error ? exchangeError.message : "token exchange failed";
5663
- return err5(502, `oauth token exchange failed for '${providerId}': ${reason}`);
6184
+ return err6(502, `oauth token exchange failed for '${providerId}': ${reason}`);
5664
6185
  }
5665
6186
  deps.oauthSessions.consume(sessionId);
5666
6187
  const label = typeof body["label"] === "string" && body["label"].trim() ? body["label"].trim() : void 0;
@@ -5669,7 +6190,7 @@ async function handleOAuthComplete(providerId, body, deps) {
5669
6190
  return { status: 200, body: status ? { account: status } : { ok: true } };
5670
6191
  }
5671
6192
  async function exchangeClaude(code, codeVerifier, state, exchangeFetch) {
5672
- const result = await import_subscriptions8.claudeOAuth.exchangeCodeForTokens(
6193
+ const result = await import_subscriptions9.claudeOAuth.exchangeCodeForTokens(
5673
6194
  { authorizationCode: code, codeVerifier, state },
5674
6195
  exchangeFetch
5675
6196
  );
@@ -5685,7 +6206,7 @@ async function exchangeClaude(code, codeVerifier, state, exchangeFetch) {
5685
6206
  };
5686
6207
  }
5687
6208
  async function exchangeGemini(code, codeVerifier, exchangeFetch) {
5688
- const result = await import_subscriptions8.geminiOAuth.exchangeCodeForTokens(code, codeVerifier, exchangeFetch);
6209
+ const result = await import_subscriptions9.geminiOAuth.exchangeCodeForTokens(code, codeVerifier, exchangeFetch);
5689
6210
  const expiresAt = new Date(Date.now() + result.expiresIn * 1e3).toISOString();
5690
6211
  return {
5691
6212
  authMethod: "oauth",
@@ -5990,8 +6511,8 @@ function errBody(message) {
5990
6511
  return { error: { type: "admin_api_error", message } };
5991
6512
  }
5992
6513
  var defaultCommandRunner = (command) => new Promise((resolve11) => {
5993
- (0, import_node_child_process.exec)(command, { timeout: 18e4 }, (err8, _stdout, stderr) => {
5994
- if (err8) resolve11({ ok: false, error: stderr.trim() || err8.message });
6514
+ (0, import_node_child_process.exec)(command, { timeout: 18e4 }, (err9, _stdout, stderr) => {
6515
+ if (err9) resolve11({ ok: false, error: stderr.trim() || err9.message });
5995
6516
  else resolve11({ ok: true });
5996
6517
  });
5997
6518
  });
@@ -6037,8 +6558,8 @@ async function handleCliLaunch(cli, body, ctx) {
6037
6558
  providerId: typeof body["providerId"] === "string" ? body["providerId"] : void 0,
6038
6559
  model: typeof body["model"] === "string" ? body["model"] : void 0
6039
6560
  });
6040
- } catch (err8) {
6041
- return { status: 400, body: errBody(err8 instanceof Error ? err8.message : "no launch target") };
6561
+ } catch (err9) {
6562
+ return { status: 400, body: errBody(err9 instanceof Error ? err9.message : "no launch target") };
6042
6563
  }
6043
6564
  const id = (0, import_node_crypto7.randomUUID)();
6044
6565
  let leaseId2;
@@ -6066,9 +6587,9 @@ async function handleCliLaunch(cli, body, ctx) {
6066
6587
  } else {
6067
6588
  launch = await buildLaunchEnv(cli, ctx.llmConfig, target);
6068
6589
  }
6069
- } catch (err8) {
6070
- const status = err8 instanceof import_provider_proxy2.RouteLeaseError ? err8.status : 400;
6071
- return { status, body: errBody(err8 instanceof Error ? err8.message : "failed to build launch env") };
6590
+ } catch (err9) {
6591
+ const status = err9 instanceof import_provider_proxy2.RouteLeaseError ? err9.status : 400;
6592
+ return { status, body: errBody(err9 instanceof Error ? err9.message : "failed to build launch env") };
6072
6593
  }
6073
6594
  const cwd = typeof body["cwd"] === "string" && body["cwd"].trim() ? body["cwd"].trim() : void 0;
6074
6595
  const opener = ctx.opener ?? defaultTerminalOpener;
@@ -6096,9 +6617,9 @@ async function handleCliLaunch(cli, body, ctx) {
6096
6617
  onFailure: onSessionEnd
6097
6618
  });
6098
6619
  if (cleanup) openerCleanup = cleanup;
6099
- } catch (err8) {
6620
+ } catch (err9) {
6100
6621
  onSessionEnd();
6101
- return { status: 500, body: errBody(err8 instanceof Error ? err8.message : "failed to open terminal") };
6622
+ return { status: 500, body: errBody(err9 instanceof Error ? err9.message : "failed to open terminal") };
6102
6623
  }
6103
6624
  if (ended) {
6104
6625
  openerCleanup?.();
@@ -6353,7 +6874,7 @@ async function runSearchLiveChecks(contributions, now = () => (/* @__PURE__ */ n
6353
6874
  }
6354
6875
 
6355
6876
  // src/search/SearchAssembly.ts
6356
- var import_upstreamFetch9 = require("@omnicross/core/pipeline/upstreamFetch");
6877
+ var import_upstreamFetch11 = require("@omnicross/core/pipeline/upstreamFetch");
6357
6878
  var import_search = require("@omnicross/core/search");
6358
6879
  var import_api2 = require("@omnicross/core/search/api");
6359
6880
  var import_http2 = require("@omnicross/core/search/http");
@@ -6371,7 +6892,7 @@ function searchPolicyFrom(config) {
6371
6892
  };
6372
6893
  }
6373
6894
  function resolveSearchUpstreamDispatcher(url) {
6374
- return (0, import_upstreamFetch9.resolveUpstreamDispatcher)({ url });
6895
+ return (0, import_upstreamFetch11.resolveUpstreamDispatcher)({ url });
6375
6896
  }
6376
6897
  var searchUpstreamProxyConfig = createUpstreamProxyResolver();
6377
6898
  function resolveSearchUpstreamProxyConfig(url) {
@@ -6653,7 +7174,7 @@ async function handleSearchQuery(req, res, deps) {
6653
7174
  // src/admin/searchAdminView.ts
6654
7175
  var API_KEY_PROVIDERS = /* @__PURE__ */ new Set(["tavily", "jina", "zhipu", "z.ai"]);
6655
7176
  var BASIC_AUTH_PROVIDERS = /* @__PURE__ */ new Set(["searxng"]);
6656
- function isRecord5(value) {
7177
+ function isRecord7(value) {
6657
7178
  return value !== null && typeof value === "object" && !Array.isArray(value);
6658
7179
  }
6659
7180
  function redactSearchServerConfig(search) {
@@ -6703,13 +7224,13 @@ function resolveSecretField(entry, field, stored) {
6703
7224
  else delete entry[field];
6704
7225
  }
6705
7226
  function preserveSearchSecrets(incoming, current) {
6706
- if (!isRecord5(incoming)) return incoming;
7227
+ if (!isRecord7(incoming)) return incoming;
6707
7228
  const section = { ...incoming };
6708
7229
  const providersValue = section["providers"];
6709
- if (!isRecord5(providersValue)) return section;
7230
+ if (!isRecord7(providersValue)) return section;
6710
7231
  const providers = {};
6711
7232
  for (const [id, entryValue] of Object.entries(providersValue)) {
6712
- if (!isRecord5(entryValue)) {
7233
+ if (!isRecord7(entryValue)) {
6713
7234
  providers[id] = entryValue;
6714
7235
  continue;
6715
7236
  }
@@ -6787,7 +7308,7 @@ function parseKeyPolicyBody(body) {
6787
7308
  var ENDPOINTS = /* @__PURE__ */ new Set(["chat", "responses", "messages", "gemini"]);
6788
7309
  var TARGET_KINDS = /* @__PURE__ */ new Set(["account", "account-group", "account-pool", "provider"]);
6789
7310
  var FALLBACKS = /* @__PURE__ */ new Set(["next", "fail", "global"]);
6790
- function isRecord6(value) {
7311
+ function isRecord8(value) {
6791
7312
  return !!value && typeof value === "object" && !Array.isArray(value);
6792
7313
  }
6793
7314
  function nonBlank(value) {
@@ -6807,7 +7328,7 @@ function validateGatewayBindingsSegment(patch) {
6807
7328
  const ids = /* @__PURE__ */ new Set();
6808
7329
  raw.forEach((entry, index) => {
6809
7330
  const path2 = `bindings[${index}]`;
6810
- if (!isRecord6(entry)) {
7331
+ if (!isRecord8(entry)) {
6811
7332
  errors.push(`${path2} must be an object`);
6812
7333
  return;
6813
7334
  }
@@ -6836,12 +7357,12 @@ function validateGatewayBindingsSegment(patch) {
6836
7357
  } else if (entry.modelMappings.length > 100) {
6837
7358
  errors.push(`${path2}.modelMappings cannot contain more than 100 entries`);
6838
7359
  } else if (entry.modelMappings.some(
6839
- (mapping) => !isRecord6(mapping) || !nonBlank(mapping.source) || !nonBlank(mapping.target)
7360
+ (mapping) => !isRecord8(mapping) || !nonBlank(mapping.source) || !nonBlank(mapping.target)
6840
7361
  )) {
6841
7362
  errors.push(`${path2}.modelMappings must contain non-empty source and target strings`);
6842
7363
  }
6843
7364
  }
6844
- if (!isRecord6(entry.target) || !TARGET_KINDS.has(String(entry.target.kind))) {
7365
+ if (!isRecord8(entry.target) || !TARGET_KINDS.has(String(entry.target.kind))) {
6845
7366
  errors.push(`${path2}.target is invalid`);
6846
7367
  } else {
6847
7368
  if (!nonBlank(entry.target.providerId)) errors.push(`${path2}.target.providerId is required`);
@@ -6856,7 +7377,7 @@ function validateGatewayBindingsSegment(patch) {
6856
7377
  }
6857
7378
  }
6858
7379
  if (entry.modelMap !== void 0) {
6859
- if (!isRecord6(entry.modelMap) || Object.values(entry.modelMap).some((value) => typeof value !== "string")) {
7380
+ if (!isRecord8(entry.modelMap) || Object.values(entry.modelMap).some((value) => typeof value !== "string")) {
6860
7381
  errors.push(`${path2}.modelMap must contain string values`);
6861
7382
  }
6862
7383
  }
@@ -7141,7 +7662,12 @@ var PROVIDER_KEYS = {
7141
7662
  },
7142
7663
  kimi: { block: "kimi", accounts: "kimiAccounts", active: "activeKimiAccountId" },
7143
7664
  grok: { block: "grok", accounts: "grokAccounts", active: "activeGrokAccountId" },
7144
- copilot: { block: "copilot", accounts: "copilotAccounts", active: "activeCopilotAccountId" }
7665
+ copilot: { block: "copilot", accounts: "copilotAccounts", active: "activeCopilotAccountId" },
7666
+ antigravity: {
7667
+ block: "antigravity",
7668
+ accounts: "antigravityAccounts",
7669
+ active: "activeAntigravityAccountId"
7670
+ }
7145
7671
  };
7146
7672
  function clone(value) {
7147
7673
  return JSON.parse(JSON.stringify(value));
@@ -7663,7 +8189,7 @@ async function applyImport(packString, passphrase, mode, deps, parseProviderInpu
7663
8189
  }
7664
8190
 
7665
8191
  // src/admin/adminMigration.ts
7666
- function err6(status, message) {
8192
+ function err7(status, message) {
7667
8193
  return { status, body: { error: { type: "admin_api_error", message } } };
7668
8194
  }
7669
8195
  async function handleExport(body, deps) {
@@ -7673,30 +8199,30 @@ async function handleExport(body, deps) {
7673
8199
  return { status: 200, body: { pack, version: BUNDLE_VERSION } };
7674
8200
  } catch (error) {
7675
8201
  if (error instanceof WeakPassphraseError) {
7676
- return err6(400, error.message);
8202
+ return err7(400, error.message);
7677
8203
  }
7678
- return err6(500, "failed to build the migration pack");
8204
+ return err7(500, "failed to build the migration pack");
7679
8205
  }
7680
8206
  }
7681
8207
  async function handleImport(body, deps) {
7682
8208
  const blob = typeof body["blob"] === "string" ? body["blob"] : "";
7683
8209
  const passphrase = typeof body["passphrase"] === "string" ? body["passphrase"] : "";
7684
8210
  const mode = body["mode"] === "overwrite" ? "overwrite" : "merge";
7685
- if (!blob) return err6(400, "import requires { blob }");
8211
+ if (!blob) return err7(400, "import requires { blob }");
7686
8212
  try {
7687
8213
  const counts = await applyImport(blob, passphrase, mode, deps, deps.parseProviderInput);
7688
8214
  return { status: 200, body: counts };
7689
8215
  } catch (error) {
7690
8216
  if (error instanceof WeakPassphraseError) {
7691
- return err6(400, error.message);
8217
+ return err7(400, error.message);
7692
8218
  }
7693
- return err6(400, error instanceof Error ? error.message : "import failed");
8219
+ return err7(400, error instanceof Error ? error.message : "import failed");
7694
8220
  }
7695
8221
  }
7696
8222
 
7697
8223
  // src/admin/usagePricing.ts
7698
8224
  var import_usage = require("@omnicross/core/usage");
7699
- var err7 = (status, message) => ({
8225
+ var err8 = (status, message) => ({
7700
8226
  status,
7701
8227
  body: { error: { type: "admin_api_error", message } }
7702
8228
  });
@@ -7709,7 +8235,7 @@ function parseRange(query2) {
7709
8235
  const startTs = parseFiniteInt(query2.get("startTs"));
7710
8236
  const endTs = parseFiniteInt(query2.get("endTs"));
7711
8237
  if (startTs === null || endTs === null) {
7712
- return err7(400, "startTs and endTs are required finite-integer unix-millis query params");
8238
+ return err8(400, "startTs and endTs are required finite-integer unix-millis query params");
7713
8239
  }
7714
8240
  return { startTs, endTs };
7715
8241
  }
@@ -7734,14 +8260,14 @@ async function handleUsageGet(view, query2, deps) {
7734
8260
  case "timeseries": {
7735
8261
  const bucket = query2.get("bucket");
7736
8262
  if (bucket !== "hour" && bucket !== "day" && bucket !== "month") {
7737
- return err7(400, "bucket must be one of 'hour', 'day', 'month'");
8263
+ return err8(400, "bucket must be one of 'hour', 'day', 'month'");
7738
8264
  }
7739
8265
  const now = Date.now();
7740
8266
  const clamped = { startTs: range.startTs, endTs: Math.min(range.endTs, now) };
7741
8267
  if (clamped.startTs < clamped.endTs) {
7742
8268
  const projected = Math.ceil((clamped.endTs - clamped.startTs) / BUCKET_SPAN_MS[bucket]) + 1;
7743
8269
  if (projected > MAX_TIMESERIES_BUCKETS) {
7744
- return err7(
8270
+ return err8(
7745
8271
  400,
7746
8272
  `requested range projects ~${projected} '${bucket}' buckets (max ${MAX_TIMESERIES_BUCKETS}); narrow the range or use a coarser bucket`
7747
8273
  );
@@ -7764,7 +8290,7 @@ async function handleUsageGet(view, query2, deps) {
7764
8290
  };
7765
8291
  }
7766
8292
  default:
7767
- return err7(404, `unknown usage view '${view ?? ""}'`);
8293
+ return err8(404, `unknown usage view '${view ?? ""}'`);
7768
8294
  }
7769
8295
  }
7770
8296
  function poolKeyLabels(cfg) {
@@ -7813,7 +8339,7 @@ async function handlePricingList(deps) {
7813
8339
  async function handlePricingUpsert(body, deps) {
7814
8340
  const input = parsePricingEntryInput(body);
7815
8341
  if (!input) {
7816
- return err7(400, "invalid pricing entry (providerId, modelId, finite numeric inputPricePer1m/outputPricePer1m required)");
8342
+ return err8(400, "invalid pricing entry (providerId, modelId, finite numeric inputPricePer1m/outputPricePer1m required)");
7817
8343
  }
7818
8344
  const entry = await deps.pricingEngine.upsertManual(input);
7819
8345
  return { status: 200, body: { entry } };
@@ -7822,7 +8348,7 @@ async function handlePricingDelete(query2, deps) {
7822
8348
  const providerId = query2.get("providerId")?.trim() ?? "";
7823
8349
  const modelId = query2.get("modelId")?.trim() ?? "";
7824
8350
  if (!providerId || !modelId) {
7825
- return err7(400, "delete requires providerId and modelId query params");
8351
+ return err8(400, "delete requires providerId and modelId query params");
7826
8352
  }
7827
8353
  const deleted = await deps.pricingStore.delete(providerId, modelId);
7828
8354
  if (deleted) await deps.pricingEngine.invalidateCache();
@@ -7842,13 +8368,13 @@ async function handlePricingFetchLatest(deps) {
7842
8368
  }
7843
8369
  };
7844
8370
  } catch (e) {
7845
- return err7(502, `pricing-source fetch failed: ${e instanceof Error ? e.message : String(e)}`);
8371
+ return err8(502, `pricing-source fetch failed: ${e instanceof Error ? e.message : String(e)}`);
7846
8372
  }
7847
8373
  }
7848
8374
  async function handlePricingResolveConflicts(body, deps) {
7849
8375
  const raw = body["resolutions"];
7850
8376
  if (!Array.isArray(raw)) {
7851
- return err7(400, "resolve-conflicts requires { resolutions: [...] }");
8377
+ return err8(400, "resolve-conflicts requires { resolutions: [...] }");
7852
8378
  }
7853
8379
  const currentRows = await deps.pricingStore.getAll();
7854
8380
  const userEditedKeys = new Set(
@@ -7858,21 +8384,21 @@ async function handlePricingResolveConflicts(body, deps) {
7858
8384
  const pendingIncoming = /* @__PURE__ */ new Map();
7859
8385
  let staleCount = 0;
7860
8386
  for (const item of raw) {
7861
- if (!item || typeof item !== "object") return err7(400, "invalid resolution entry");
8387
+ if (!item || typeof item !== "object") return err8(400, "invalid resolution entry");
7862
8388
  const r = item;
7863
8389
  const action = r["action"];
7864
8390
  if (action !== "overwrite" && action !== "skip") {
7865
- return err7(400, "resolution action must be 'overwrite' or 'skip'");
8391
+ return err8(400, "resolution action must be 'overwrite' or 'skip'");
7866
8392
  }
7867
8393
  const providerId = typeof r["providerId"] === "string" && r["providerId"].trim() ? r["providerId"].trim() : "";
7868
8394
  const modelId = typeof r["modelId"] === "string" && r["modelId"].trim() ? r["modelId"].trim() : "";
7869
8395
  if (!providerId || !modelId) {
7870
- return err7(400, "each resolution requires top-level providerId and modelId");
8396
+ return err8(400, "each resolution requires top-level providerId and modelId");
7871
8397
  }
7872
8398
  const incoming = parsePricingEntryInput(r["incoming"]);
7873
- if (!incoming) return err7(400, "each resolution must echo a valid incoming pricing entry");
8399
+ if (!incoming) return err8(400, "each resolution must echo a valid incoming pricing entry");
7874
8400
  if (incoming.providerId !== providerId || incoming.modelId !== modelId) {
7875
- return err7(400, "resolution providerId/modelId must match the echoed incoming entry");
8401
+ return err8(400, "resolution providerId/modelId must match the echoed incoming entry");
7876
8402
  }
7877
8403
  const key = `${providerId}::${modelId}`;
7878
8404
  if (action === "overwrite" && !userEditedKeys.has(key)) {
@@ -7917,7 +8443,7 @@ function query(req) {
7917
8443
  }
7918
8444
  function allowanceProvider(value) {
7919
8445
  if (!value) return void 0;
7920
- return value === "claude" || value === "codex" || value === "kimi" || value === "opencodego" || value === "grok" || value === "copilot" || value === "gemini" ? value : null;
8446
+ return value === "claude" || value === "codex" || value === "kimi" || value === "opencodego" || value === "grok" || value === "copilot" || value === "gemini" || value === "antigravity" ? value : null;
7921
8447
  }
7922
8448
  async function handleAccountAllowanceApi(req, res, method, rest, service) {
7923
8449
  if (!service) return writeError2(res, 501, "account allowance service is not available");
@@ -7994,6 +8520,16 @@ async function handleAccountAllowanceApi(req, res, method, rest, service) {
7994
8520
  }
7995
8521
  return writeJson3(res, 200, { allowances: allowances2 });
7996
8522
  }
8523
+ if (requestedProvider === "antigravity") {
8524
+ if (!service.refreshAntigravity) {
8525
+ return writeError2(res, 501, "antigravity allowance refresh is not available");
8526
+ }
8527
+ const allowances2 = await service.refreshAntigravity(accountId);
8528
+ if (accountId && allowances2.length === 0) {
8529
+ return writeError2(res, 404, `Antigravity account '${accountId}' not found`);
8530
+ }
8531
+ return writeJson3(res, 200, { allowances: allowances2 });
8532
+ }
7997
8533
  if (requestedProvider === "gemini") {
7998
8534
  if (!service.refreshGemini) {
7999
8535
  return writeError2(res, 501, "gemini allowance refresh is not available");
@@ -8174,8 +8710,8 @@ async function handleAdminApi(req, res, path2, deps) {
8174
8710
  default:
8175
8711
  return writeJsonError(res, 404, `unknown admin resource '${resource}'`);
8176
8712
  }
8177
- } catch (err8) {
8178
- writeJsonError(res, 500, err8 instanceof Error ? err8.message : String(err8));
8713
+ } catch (err9) {
8714
+ writeJsonError(res, 500, err9 instanceof Error ? err9.message : String(err9));
8179
8715
  }
8180
8716
  }
8181
8717
  function requestQuery(req) {
@@ -8350,7 +8886,7 @@ async function handleDiscoverModels(res, id, cfg) {
8350
8886
  const headers = { Accept: "application/json" };
8351
8887
  if (resolvedKey) headers["Authorization"] = `Bearer ${resolvedKey}`;
8352
8888
  Object.assign(headers, expandRowExtraHeaders(row));
8353
- const response = await (0, import_upstreamFetch10.fetchUpstream)(url, { method: "GET", headers }, { providerId: "byo" });
8889
+ const response = await (0, import_upstreamFetch12.fetchUpstream)(url, { method: "GET", headers }, { providerId: "byo" });
8354
8890
  if (!response.ok) {
8355
8891
  const text = await response.text().catch(() => "");
8356
8892
  let message = text.slice(0, 300);
@@ -8367,8 +8903,8 @@ async function handleDiscoverModels(res, id, cfg) {
8367
8903
  const data = await response.json();
8368
8904
  const models = Array.isArray(data?.data) ? data.data.map((m) => typeof m?.id === "string" ? m.id : "").filter((m) => m.length > 0) : [];
8369
8905
  return writeJson4(res, 200, { models });
8370
- } catch (err8) {
8371
- const message = err8 instanceof Error ? err8.message : String(err8);
8906
+ } catch (err9) {
8907
+ const message = err9 instanceof Error ? err9.message : String(err9);
8372
8908
  return writeJson4(res, 200, { models: [], error: `discovery failed: ${message}` });
8373
8909
  }
8374
8910
  }
@@ -8410,7 +8946,7 @@ async function handleTestModel(req, res, id, cfg) {
8410
8946
  Object.assign(headers, expandRowExtraHeaders(row));
8411
8947
  const startedAt = Date.now();
8412
8948
  try {
8413
- const response = await (0, import_upstreamFetch10.fetchUpstream)(
8949
+ const response = await (0, import_upstreamFetch12.fetchUpstream)(
8414
8950
  url,
8415
8951
  { method: "POST", headers, body: JSON.stringify(payload) },
8416
8952
  { providerId: "byo" }
@@ -8432,8 +8968,8 @@ async function handleTestModel(req, res, id, cfg) {
8432
8968
  latencyMs,
8433
8969
  sample: extractSampleText(text, row.apiFormat)
8434
8970
  });
8435
- } catch (err8) {
8436
- const message = err8 instanceof Error ? err8.message : String(err8);
8971
+ } catch (err9) {
8972
+ const message = err9 instanceof Error ? err9.message : String(err9);
8437
8973
  return writeJson4(res, 200, { ok: false, latencyMs: Date.now() - startedAt, message });
8438
8974
  }
8439
8975
  }
@@ -9018,8 +9554,8 @@ function imageConfigurationAuditFields(previous, next) {
9018
9554
  const after = next ?? import_outbound_api5.DEFAULT_IMAGES_SERVER_CONFIG;
9019
9555
  const fields = [];
9020
9556
  if (before.enabled !== after.enabled) fields.push("enablement");
9021
- if (before.provider !== after.provider) fields.push("provider");
9022
- if (before.defaultModel !== after.defaultModel || !sameConfigValue(before.modelAliases, after.modelAliases)) fields.push("model");
9557
+ if (!sameConfigValue(before.models, after.models)) fields.push("provider");
9558
+ if (before.defaultModel !== after.defaultModel || !sameConfigValue(before.aliases, after.aliases) || !sameConfigValue(before.codex, after.codex)) fields.push("model");
9023
9559
  if (!sameConfigValue(before.account, after.account)) fields.push("account");
9024
9560
  if (!sameConfigValue(before.queue, after.queue)) fields.push("queue");
9025
9561
  if (!sameConfigValue(before.temporary, after.temporary)) fields.push("temporary");
@@ -9223,6 +9759,12 @@ async function handleAccounts(req, res, method, rest, deps) {
9223
9759
  deps.accountAllowanceService
9224
9760
  );
9225
9761
  }
9762
+ if (method === "GET" && rest[0] === "antigravity" && rest[1] === "models") {
9763
+ const result = await handleAntigravityModelsRoute({
9764
+ resolveAntigravityAccessToken: deps.resolveAntigravityAccessToken ?? (async () => null)
9765
+ });
9766
+ return writeJson4(res, result.status, result.body);
9767
+ }
9226
9768
  if (method === "GET" && rest.length === 0) {
9227
9769
  const accounts = await deps.subscriptionAccounts.listAll();
9228
9770
  const providerAccounts = await deps.subscriptionTokenWriter.listSanitizedAccounts();
@@ -9248,12 +9790,12 @@ async function handleAccounts(req, res, method, rest, deps) {
9248
9790
  }
9249
9791
  return writeJson4(res, 200, { ok: true, affected: result.affected });
9250
9792
  }
9251
- if (method === "GET" && (rest[0] === "codex" || rest[0] === "kimi" || rest[0] === "grok" || rest[0] === "copilot") && rest[1] === "oauth" && rest[3] === "status") {
9252
- 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);
9793
+ if (method === "GET" && (rest[0] === "codex" || rest[0] === "kimi" || rest[0] === "grok" || rest[0] === "copilot" || rest[0] === "antigravity") && rest[1] === "oauth" && rest[3] === "status") {
9794
+ 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);
9253
9795
  return writeJson4(res, result.status, result.body);
9254
9796
  }
9255
- if (method === "DELETE" && (rest[0] === "codex" || rest[0] === "kimi" || rest[0] === "grok" || rest[0] === "copilot") && rest[1] === "oauth" && rest[2]) {
9256
- 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);
9797
+ if (method === "DELETE" && (rest[0] === "codex" || rest[0] === "kimi" || rest[0] === "grok" || rest[0] === "copilot" || rest[0] === "antigravity") && rest[1] === "oauth" && rest[2]) {
9798
+ 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);
9257
9799
  return writeJson4(res, result.status, result.body);
9258
9800
  }
9259
9801
  if (method === "GET" && rest.length === 3 && rest[2] === "diagnostics") {
@@ -9323,6 +9865,10 @@ async function handleAccounts(req, res, method, rest, deps) {
9323
9865
  const result2 = await handleCopilotOAuthStart(deps, body2["enterpriseUrl"]);
9324
9866
  return writeJson4(res, result2.status, result2.body);
9325
9867
  }
9868
+ if (providerId === "antigravity") {
9869
+ const result2 = handleAntigravityOAuthStart(deps);
9870
+ return writeJson4(res, result2.status, result2.body);
9871
+ }
9326
9872
  const result = handleOAuthStart(providerId, deps);
9327
9873
  return writeJson4(res, result.status, result.body);
9328
9874
  }
@@ -9717,7 +10263,7 @@ async function handleImages(res, method, rest, deps) {
9717
10263
  return writeJson4(res, 200, {
9718
10264
  configured: {
9719
10265
  enabled: images.enabled,
9720
- provider: images.provider,
10266
+ provider: images.models[images.defaultModel] ?? "codex-subscription",
9721
10267
  model: images.defaultModel,
9722
10268
  remoteUrlsEnabled: images.remote.enabled,
9723
10269
  referenceTtlMs: images.references.ttlMs
@@ -9817,12 +10363,12 @@ async function handlePlayground(req, res, method, deps) {
9817
10363
  const payload = body["body"];
9818
10364
  const status = deps.outboundApiServer.getStatus();
9819
10365
  if (!status.running || !status.port) return writeJsonError(res, 503, "outbound server not running");
9820
- const path2 = resolvePlaygroundPath(endpoint, isRecord7(payload) ? payload : {});
10366
+ const path2 = resolvePlaygroundPath(endpoint, isRecord9(payload) ? payload : {});
9821
10367
  if (!path2) return writeJsonError(res, 400, `unknown endpoint '${endpoint}'`);
9822
10368
  const upstreamBody = typeof payload === "string" ? payload : JSON.stringify(payload ?? {});
9823
10369
  await proxyToOutbound(res, status.port, path2, key, upstreamBody);
9824
10370
  }
9825
- function isRecord7(v) {
10371
+ function isRecord9(v) {
9826
10372
  return !!v && typeof v === "object" && !Array.isArray(v);
9827
10373
  }
9828
10374
  function proxyToOutbound(res, outboundPort, path2, key, body) {
@@ -9851,8 +10397,8 @@ function proxyToOutbound(res, outboundPort, path2, key, body) {
9851
10397
  });
9852
10398
  }
9853
10399
  );
9854
- upstream.on("error", (err8) => {
9855
- if (!res.headersSent) writeJsonError(res, 502, `playground proxy failed: ${err8.message}`);
10400
+ upstream.on("error", (err9) => {
10401
+ if (!res.headersSent) writeJsonError(res, 502, `playground proxy failed: ${err9.message}`);
9856
10402
  else res.end();
9857
10403
  resolve11();
9858
10404
  });
@@ -9958,7 +10504,7 @@ async function handleUiStatic(req, res, urlPath, uiDist) {
9958
10504
  }
9959
10505
 
9960
10506
  // src/admin/version.ts
9961
- var DAEMON_VERSION = true ? "0.4.2" : "0.0.0-dev";
10507
+ var DAEMON_VERSION = true ? "0.4.3" : "0.0.0-dev";
9962
10508
 
9963
10509
  // src/admin/AdminServer.ts
9964
10510
  var LOOPBACK_ADDR = "127.0.0.1";
@@ -10001,13 +10547,13 @@ var AdminServer = class {
10001
10547
  const server = import_node_http2.default.createServer((req, res) => {
10002
10548
  this.onRequest(req, res);
10003
10549
  });
10004
- const onError = (err8) => {
10005
- if (err8.code === "EADDRINUSE" && port !== 0) {
10550
+ const onError = (err9) => {
10551
+ if (err9.code === "EADDRINUSE" && port !== 0) {
10006
10552
  server.removeListener("error", onError);
10007
10553
  this.listen(bindAddr, 0).then(resolve11, reject);
10008
10554
  return;
10009
10555
  }
10010
- reject(err8);
10556
+ reject(err9);
10011
10557
  };
10012
10558
  server.on("error", onError);
10013
10559
  server.listen(port, bindAddr, () => {
@@ -10025,8 +10571,8 @@ var AdminServer = class {
10025
10571
  }
10026
10572
  /** Per-request handler: auth gate (when a token is set) → routing. */
10027
10573
  onRequest(req, res) {
10028
- void this.dispatch(req, res).catch((err8) => {
10029
- const message = err8 instanceof Error ? err8.message : String(err8);
10574
+ void this.dispatch(req, res).catch((err9) => {
10575
+ const message = err9 instanceof Error ? err9.message : String(err9);
10030
10576
  this.deps.logger.error("[AdminServer] unhandled error:", message);
10031
10577
  if (!res.headersSent) {
10032
10578
  res.writeHead(500, { "Content-Type": "application/json" });
@@ -10249,7 +10795,10 @@ var HTML_HEADERS = {
10249
10795
  function pageHtml(message) {
10250
10796
  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>`;
10251
10797
  }
10252
- function awaitLoopbackCode(expectedState, timeoutMs = DEFAULT_TIMEOUT_MS, signal) {
10798
+ function awaitLoopbackCode(expectedState, timeoutMs = DEFAULT_TIMEOUT_MS, signal, binding = {}) {
10799
+ const port = binding.port ?? LOOPBACK_PORT;
10800
+ const callbackPath = binding.path ?? CALLBACK_PATH;
10801
+ const label = binding.label ?? "codex";
10253
10802
  return new Promise((resolve11, reject) => {
10254
10803
  let settled = false;
10255
10804
  const finish = (server2, fn) => {
@@ -10260,8 +10809,8 @@ function awaitLoopbackCode(expectedState, timeoutMs = DEFAULT_TIMEOUT_MS, signal
10260
10809
  server2.close();
10261
10810
  };
10262
10811
  const server = (0, import_node_http3.createServer)((req, res) => {
10263
- const url = new URL(req.url ?? "", `http://${LOOPBACK_HOST}:${LOOPBACK_PORT}`);
10264
- if (url.pathname !== CALLBACK_PATH) {
10812
+ const url = new URL(req.url ?? "", `http://${LOOPBACK_HOST}:${port}`);
10813
+ if (url.pathname !== callbackPath) {
10265
10814
  res.writeHead(404, HTML_HEADERS);
10266
10815
  res.end(pageHtml("Not found"));
10267
10816
  return;
@@ -10290,25 +10839,25 @@ function awaitLoopbackCode(expectedState, timeoutMs = DEFAULT_TIMEOUT_MS, signal
10290
10839
  return;
10291
10840
  }
10292
10841
  signal?.addEventListener("abort", abort, { once: true });
10293
- server.on("error", (err8) => {
10842
+ server.on("error", (err9) => {
10294
10843
  if (settled) return;
10295
10844
  settled = true;
10296
10845
  clearTimeout(timer);
10297
- if (err8.code === "EADDRINUSE") {
10846
+ if (err9.code === "EADDRINUSE") {
10298
10847
  reject(
10299
10848
  new Error(
10300
- `login: cannot bind ${LOOPBACK_HOST}:${LOOPBACK_PORT} (address in use) \u2014 another codex login or process is holding the port`
10849
+ `login: cannot bind ${LOOPBACK_HOST}:${port} (address in use) \u2014 another ${label} login or process is holding the port`
10301
10850
  )
10302
10851
  );
10303
10852
  } else {
10304
- reject(err8);
10853
+ reject(err9);
10305
10854
  }
10306
10855
  });
10307
10856
  const timer = setTimeout(() => {
10308
10857
  finish(server, () => reject(new Error(`login: timed out after ${Math.round(timeoutMs / 1e3)}s waiting for the callback`)));
10309
10858
  }, timeoutMs);
10310
10859
  if (typeof timer.unref === "function") timer.unref();
10311
- server.listen(LOOPBACK_PORT, LOOPBACK_HOST);
10860
+ server.listen(port, LOOPBACK_HOST);
10312
10861
  });
10313
10862
  }
10314
10863
 
@@ -10378,7 +10927,7 @@ function createPoolKeysLoader(getProviderRow, autoDisabled) {
10378
10927
 
10379
10928
  // src/allowance/ProviderKeyQuotaService.ts
10380
10929
  var import_core4 = require("@omnicross/core");
10381
- var import_upstreamFetch11 = require("@omnicross/core/pipeline/upstreamFetch");
10930
+ var import_upstreamFetch13 = require("@omnicross/core/pipeline/upstreamFetch");
10382
10931
 
10383
10932
  // src/allowance/ProviderKeyQuota.ts
10384
10933
  var MINUTE_MS3 = 6e4;
@@ -10407,11 +10956,11 @@ function isoInstant3(value) {
10407
10956
  }
10408
10957
  return void 0;
10409
10958
  }
10410
- function secondsUntil8(instant, now) {
10959
+ function secondsUntil9(instant, now) {
10411
10960
  if (!instant) return void 0;
10412
10961
  return Math.max(0, Math.floor((Date.parse(instant) - now) / 1e3));
10413
10962
  }
10414
- function isRecord8(value) {
10963
+ function isRecord10(value) {
10415
10964
  return !!value && typeof value === "object" && !Array.isArray(value);
10416
10965
  }
10417
10966
  function detectProviderKeyQuotaAdapter(baseUrl) {
@@ -10478,17 +11027,17 @@ function zaiWindowIdLabel(durationMs) {
10478
11027
  return { id: "quota", label: "Quota" };
10479
11028
  }
10480
11029
  function parseZaiQuotaPayload(payload, now) {
10481
- if (!isRecord8(payload)) return null;
10482
- const data = isRecord8(payload["data"]) ? payload["data"] : payload;
11030
+ if (!isRecord10(payload)) return null;
11031
+ const data = isRecord10(payload["data"]) ? payload["data"] : payload;
10483
11032
  if (payload["success"] === false) return null;
10484
11033
  const limits = Array.isArray(data["limits"]) ? data["limits"] : [];
10485
11034
  const byWindow = /* @__PURE__ */ new Map();
10486
11035
  for (const raw of limits) {
10487
- if (!isRecord8(raw)) continue;
11036
+ if (!isRecord10(raw)) continue;
10488
11037
  const item = raw;
10489
11038
  if (item.type === void 0) continue;
10490
11039
  const details = raw["usageDetails"];
10491
- if (Array.isArray(details) && details.some((d) => isRecord8(d) && d["modelCode"] === "zread")) {
11040
+ if (Array.isArray(details) && details.some((d) => isRecord10(d) && d["modelCode"] === "zread")) {
10492
11041
  continue;
10493
11042
  }
10494
11043
  const durationMs = zaiWindowDurationMs(item);
@@ -10507,7 +11056,7 @@ function parseZaiQuotaPayload(payload, now) {
10507
11056
  usedPercent,
10508
11057
  ...durationMs !== void 0 ? { windowMinutes: Math.round(durationMs / MINUTE_MS3) } : {},
10509
11058
  ...resetsAt !== void 0 ? { resetsAt } : {},
10510
- remainingSeconds: secondsUntil8(resetsAt, now),
11059
+ remainingSeconds: secondsUntil9(resetsAt, now),
10511
11060
  state: "fresh"
10512
11061
  };
10513
11062
  const existing = byWindow.get(id);
@@ -10521,7 +11070,7 @@ function parseZaiQuotaPayload(payload, now) {
10521
11070
  var MINIMAX_STATUS_EXHAUSTED = 2;
10522
11071
  var MINIMAX_SHARED_BUCKET = "general";
10523
11072
  function parseMiniMaxBucket(value) {
10524
- if (!isRecord8(value)) return null;
11073
+ if (!isRecord10(value)) return null;
10525
11074
  const modelName = typeof value["model_name"] === "string" ? value["model_name"].trim() : "";
10526
11075
  if (!modelName) return null;
10527
11076
  const instant = (v) => {
@@ -10548,14 +11097,14 @@ function minimaxWindow(id, label, windowMinutes, resetsAtMs, remainingPercent, s
10548
11097
  usedPercent,
10549
11098
  ...windowMinutes !== void 0 ? { windowMinutes } : {},
10550
11099
  ...resetsAt !== void 0 ? { resetsAt } : {},
10551
- remainingSeconds: secondsUntil8(resetsAt, now),
11100
+ remainingSeconds: secondsUntil9(resetsAt, now),
10552
11101
  state: usedPercent !== null ? "fresh" : "unavailable"
10553
11102
  };
10554
11103
  }
10555
11104
  function parseMiniMaxTokenPlanPayload(payload, now) {
10556
- if (!isRecord8(payload)) return null;
11105
+ if (!isRecord10(payload)) return null;
10557
11106
  const baseResp = payload["base_resp"];
10558
- if (!isRecord8(baseResp) || baseResp["status_code"] !== 0) return null;
11107
+ if (!isRecord10(baseResp) || baseResp["status_code"] !== 0) return null;
10559
11108
  const buckets = Array.isArray(payload["model_remains"]) ? payload["model_remains"] : [];
10560
11109
  let general = null;
10561
11110
  for (const raw of buckets) {
@@ -10588,11 +11137,11 @@ function parseMiniMaxTokenPlanPayload(payload, now) {
10588
11137
  ];
10589
11138
  }
10590
11139
  function parseUmansUsagePayload(payload, now) {
10591
- if (!isRecord8(payload)) return null;
10592
- const limits = isRecord8(payload["limits"]) ? payload["limits"] : void 0;
10593
- const requests = limits && isRecord8(limits["requests"]) ? limits["requests"] : void 0;
10594
- const usage = isRecord8(payload["usage"]) ? payload["usage"] : void 0;
10595
- const window = isRecord8(payload["window"]) ? payload["window"] : void 0;
11140
+ if (!isRecord10(payload)) return null;
11141
+ const limits = isRecord10(payload["limits"]) ? payload["limits"] : void 0;
11142
+ const requests = limits && isRecord10(limits["requests"]) ? limits["requests"] : void 0;
11143
+ const usage = isRecord10(payload["usage"]) ? payload["usage"] : void 0;
11144
+ const window = isRecord10(payload["window"]) ? payload["window"] : void 0;
10596
11145
  const hardCap = finiteNumber5(requests?.["hard_cap"]);
10597
11146
  const softLimit = finiteNumber5(requests?.["limit"]);
10598
11147
  const requestsInWindow = finiteNumber5(usage?.["requests_in_window"]);
@@ -10613,15 +11162,15 @@ function parseUmansUsagePayload(payload, now) {
10613
11162
  usedPercent,
10614
11163
  windowMinutes: 5 * 60,
10615
11164
  ...resetsAt !== void 0 ? { resetsAt } : {},
10616
- remainingSeconds: secondsUntil8(resetsAt, now),
11165
+ remainingSeconds: secondsUntil9(resetsAt, now),
10617
11166
  state: "fresh"
10618
11167
  }
10619
11168
  ];
10620
11169
  }
10621
11170
  function parseSyntheticQuotasPayload(payload, now) {
10622
- if (!isRecord8(payload)) return null;
10623
- const fiveHour = isRecord8(payload["rollingFiveHourLimit"]) ? payload["rollingFiveHourLimit"] : void 0;
10624
- const weekly = isRecord8(payload["weeklyTokenLimit"]) ? payload["weeklyTokenLimit"] : void 0;
11171
+ if (!isRecord10(payload)) return null;
11172
+ const fiveHour = isRecord10(payload["rollingFiveHourLimit"]) ? payload["rollingFiveHourLimit"] : void 0;
11173
+ const weekly = isRecord10(payload["weeklyTokenLimit"]) ? payload["weeklyTokenLimit"] : void 0;
10625
11174
  const windows = [];
10626
11175
  if (fiveHour) {
10627
11176
  const max = finiteNumber5(fiveHour["max"]);
@@ -10635,7 +11184,7 @@ function parseSyntheticQuotasPayload(payload, now) {
10635
11184
  usedPercent,
10636
11185
  windowMinutes: 5 * 60,
10637
11186
  ...resetsAt !== void 0 ? { resetsAt } : {},
10638
- remainingSeconds: secondsUntil8(resetsAt, now),
11187
+ remainingSeconds: secondsUntil9(resetsAt, now),
10639
11188
  state: usedPercent !== null || resetsAt ? "fresh" : "unavailable"
10640
11189
  });
10641
11190
  }
@@ -10650,7 +11199,7 @@ function parseSyntheticQuotasPayload(payload, now) {
10650
11199
  usedPercent,
10651
11200
  windowMinutes: 7 * 24 * 60,
10652
11201
  ...resetsAt !== void 0 ? { resetsAt } : {},
10653
- remainingSeconds: secondsUntil8(resetsAt, now),
11202
+ remainingSeconds: secondsUntil9(resetsAt, now),
10654
11203
  state: usedPercent !== null || resetsAt ? "fresh" : "unavailable"
10655
11204
  });
10656
11205
  }
@@ -10662,12 +11211,12 @@ var CLINE_WINDOW_CONFIG = {
10662
11211
  monthly: { id: "thirty-day", label: "30 days", minutes: 30 * 24 * 60 }
10663
11212
  };
10664
11213
  function parseClinePassUsageLimitsPayload(payload, now) {
10665
- if (!isRecord8(payload)) return null;
10666
- const data = isRecord8(payload["data"]) ? payload["data"] : payload;
11214
+ if (!isRecord10(payload)) return null;
11215
+ const data = isRecord10(payload["data"]) ? payload["data"] : payload;
10667
11216
  const limits = Array.isArray(data["limits"]) ? data["limits"] : [];
10668
11217
  const windows = [];
10669
11218
  for (const raw of limits) {
10670
- if (!isRecord8(raw)) continue;
11219
+ if (!isRecord10(raw)) continue;
10671
11220
  const config = CLINE_WINDOW_CONFIG[typeof raw["type"] === "string" ? raw["type"] : ""];
10672
11221
  if (!config) continue;
10673
11222
  const usedPercent = finitePercent4(raw["percentUsed"]);
@@ -10680,7 +11229,7 @@ function parseClinePassUsageLimitsPayload(payload, now) {
10680
11229
  usedPercent,
10681
11230
  windowMinutes: config.minutes,
10682
11231
  ...resetsAt !== void 0 ? { resetsAt } : {},
10683
- remainingSeconds: secondsUntil8(resetsAt, now),
11232
+ remainingSeconds: secondsUntil9(resetsAt, now),
10684
11233
  state: "fresh"
10685
11234
  });
10686
11235
  }
@@ -10719,7 +11268,7 @@ function rowKeyEntries(row) {
10719
11268
  return [];
10720
11269
  }
10721
11270
  var ProviderKeyQuotaService = class {
10722
- constructor(box, fetchImpl = (url, init) => (0, import_upstreamFetch11.fetchUpstream)(url, init, { redactBodies: true }), now = Date.now) {
11271
+ constructor(box, fetchImpl = (url, init) => (0, import_upstreamFetch13.fetchUpstream)(url, init, { redactBodies: true }), now = Date.now) {
10723
11272
  this.box = box;
10724
11273
  this.fetchImpl = fetchImpl;
10725
11274
  this.now = now;
@@ -10822,7 +11371,7 @@ var ProviderKeyQuotaService = class {
10822
11371
  // src/image-generation/ImageDoctorService.ts
10823
11372
  var import_image_generation = require("@omnicross/core/image-generation");
10824
11373
  var import_outbound_api7 = require("@omnicross/core/outbound-api");
10825
- var import_subscriptions9 = require("@omnicross/subscriptions");
11374
+ var import_subscriptions10 = require("@omnicross/subscriptions");
10826
11375
 
10827
11376
  // src/image-generation/FileCodexImageCapabilityEvidenceSource.ts
10828
11377
  var import_node_crypto13 = require("crypto");
@@ -11260,16 +11809,16 @@ function createImageDoctorService(options) {
11260
11809
  paths,
11261
11810
  ttlMs: config.evidenceTtlMs
11262
11811
  }));
11263
- const createLiveVerifier = options.createLiveVerifier ?? ((strategy, config) => (0, import_subscriptions9.createCodexImageLiveVerifier)({
11812
+ const createLiveVerifier = options.createLiveVerifier ?? ((strategy, config) => (0, import_subscriptions10.createCodexImageLiveVerifier)({
11264
11813
  authStrategy: strategy,
11265
11814
  generationTimeoutMs: config.queue.generationTimeoutMs
11266
11815
  }));
11267
- const readAccount = async () => {
11268
- const codex = (await options.subscriptionAccounts.listAll()).find((entry) => entry.providerId === "codex");
11816
+ const readAccount = async (providerId) => {
11817
+ const entry = (await options.subscriptionAccounts.listAll()).find((candidate) => candidate.providerId === providerId);
11269
11818
  return Object.freeze({
11270
- present: codex !== void 0,
11271
- usable: codex?.credentialStatus.ok === true,
11272
- reason: codex === void 0 ? "missing" : codex.credentialStatus.ok ? "ready" : "unavailable"
11819
+ present: entry !== void 0,
11820
+ usable: entry?.credentialStatus.ok === true,
11821
+ reason: entry === void 0 ? "missing" : entry.credentialStatus.ok ? "ready" : "unavailable"
11273
11822
  });
11274
11823
  };
11275
11824
  const activePaths = () => options.storageCatalog.active().resolver;
@@ -11307,6 +11856,7 @@ function createImageDoctorService(options) {
11307
11856
  } catch {
11308
11857
  storesValid = false;
11309
11858
  }
11859
+ const antigravityAccount = await readAccount("antigravity");
11310
11860
  const rows = await options.keyDb.outboundApiKeysList();
11311
11861
  let legacyRows = 0;
11312
11862
  let invalidRows = 0;
@@ -11323,7 +11873,7 @@ function createImageDoctorService(options) {
11323
11873
  invalidRows += 1;
11324
11874
  }
11325
11875
  }
11326
- const account = await readAccount();
11876
+ const account = await readAccount("codex");
11327
11877
  let evidence;
11328
11878
  let evidenceStore;
11329
11879
  try {
@@ -11337,10 +11887,11 @@ function createImageDoctorService(options) {
11337
11887
  return Object.freeze({
11338
11888
  config: Object.freeze({
11339
11889
  enabled: config.enabled,
11340
- provider: config.provider,
11890
+ provider: config.models[config.defaultModel] ?? "codex-subscription",
11341
11891
  model: config.defaultModel,
11342
11892
  valid: configErrors.length === 0,
11343
- errorCount: configErrors.length
11893
+ errorCount: configErrors.length,
11894
+ routedProviders: Object.freeze([...new Set(Object.values(config.models))])
11344
11895
  }),
11345
11896
  roots: Object.freeze({
11346
11897
  valid: verifiedAreas === ROOT_AREAS.length,
@@ -11365,12 +11916,13 @@ function createImageDoctorService(options) {
11365
11916
  imagesAuthorizedRows
11366
11917
  }),
11367
11918
  account,
11919
+ antigravityAccount,
11368
11920
  evidence: Object.freeze(evidence)
11369
11921
  });
11370
11922
  },
11371
11923
  verifyLive: async (config, signal) => {
11372
11924
  if (!config.enabled) return Object.freeze({ ok: false, code: "images_disabled" });
11373
- const account = await readAccount();
11925
+ const account = await readAccount("codex");
11374
11926
  if (!account.usable) {
11375
11927
  return Object.freeze({ ok: false, code: "codex_account_unavailable" });
11376
11928
  }
@@ -11622,7 +12174,7 @@ var ImageCleanupService = class {
11622
12174
  var import_node_crypto16 = require("crypto");
11623
12175
  var import_image_generation5 = require("@omnicross/core/image-generation");
11624
12176
  var import_outbound_api8 = require("@omnicross/core/outbound-api");
11625
- var import_subscriptions10 = require("@omnicross/subscriptions");
12177
+ var import_subscriptions11 = require("@omnicross/subscriptions");
11626
12178
 
11627
12179
  // src/image-generation/ImageApiRuntimeResolver.ts
11628
12180
  var import_node_crypto14 = require("crypto");
@@ -11650,10 +12202,11 @@ function createTrustedImageApiRuntimeResolver(options) {
11650
12202
  throw new TypeError("enabled image remote loading requires a proven resolver");
11651
12203
  }
11652
12204
  const hmacKey = Buffer.from(options.hmacKey);
11653
- const modelAliases = new Map(Object.entries(options.config.modelAliases));
12205
+ const modelAliases = new Map(Object.entries(options.config.aliases));
12206
+ const modelRoutes = new Map(Object.entries(options.config.models));
11654
12207
  const limits = Object.freeze({ ...options.config.limits });
11655
- const providerId = options.config.provider;
11656
12208
  const defaultModel = options.config.defaultModel;
12209
+ const providerId = modelRoutes.get(defaultModel) ?? "codex-subscription";
11657
12210
  const referenceStore = options.referenceStore;
11658
12211
  const retention = Object.freeze({
11659
12212
  enabled: true,
@@ -11674,6 +12227,7 @@ function createTrustedImageApiRuntimeResolver(options) {
11674
12227
  providerId,
11675
12228
  defaultModel,
11676
12229
  modelAliases,
12230
+ modelRoutes,
11677
12231
  limits,
11678
12232
  ...preferredAccountId ? { preferredAccountId } : {},
11679
12233
  ...preferredAccountGroup ? { preferredAccountGroup } : {},
@@ -12075,7 +12629,9 @@ var GENERATION_ID = /^[A-Za-z0-9][A-Za-z0-9_.:-]{0,127}$/u;
12075
12629
  function snapshotConfig(config) {
12076
12630
  return {
12077
12631
  ...config,
12078
- modelAliases: { ...config.modelAliases },
12632
+ models: { ...config.models },
12633
+ aliases: { ...config.aliases },
12634
+ codex: { ...config.codex },
12079
12635
  account: { ...config.account },
12080
12636
  queue: { ...config.queue },
12081
12637
  temporary: { ...config.temporary },
@@ -12109,10 +12665,15 @@ function createImageRuntimeGeneration(options) {
12109
12665
  }
12110
12666
  });
12111
12667
  }
12112
- const authStrategy = options.subscriptionAccounts.getStrategy("codex");
12113
- if (!authStrategy || authStrategy.providerId !== "codex") {
12668
+ const routedProviders = [...new Set(Object.values(config.models))];
12669
+ const codexStrategy = routedProviders.includes("codex-subscription") ? options.subscriptionAccounts.getStrategy("codex") : void 0;
12670
+ if (routedProviders.includes("codex-subscription") && (!codexStrategy || codexStrategy.providerId !== "codex")) {
12114
12671
  throw new TypeError("enabled image runtime requires the Codex subscription strategy");
12115
12672
  }
12673
+ const antigravityStrategy = routedProviders.includes("antigravity-subscription") ? options.subscriptionAccounts.getStrategy("antigravity") : void 0;
12674
+ if (routedProviders.includes("antigravity-subscription") && (!antigravityStrategy || antigravityStrategy.providerId !== "antigravity")) {
12675
+ throw new TypeError("enabled image runtime requires the Antigravity subscription strategy");
12676
+ }
12116
12677
  const privateHmacKey = options.privateHmacKey ? Buffer.from(options.privateHmacKey) : loadOrCreateImageTenantHmacSalt(options.storage.paths, import_node_crypto16.randomBytes);
12117
12678
  if (privateHmacKey.byteLength !== 32) {
12118
12679
  privateHmacKey.fill(0);
@@ -12147,23 +12708,32 @@ function createImageRuntimeGeneration(options) {
12147
12708
  if (options.testOnlySyntheticVerifiedProvider && options.testOnlySyntheticVerifiedProvider.label !== "synthetic-verified-image-provider-test-only") {
12148
12709
  throw new TypeError("synthetic verified image provider test seam label is invalid");
12149
12710
  }
12150
- const provider = options.testOnlySyntheticVerifiedProvider ? options.testOnlySyntheticVerifiedProvider.createProvider({
12711
+ const providers = options.testOnlySyntheticVerifiedProvider ? [options.testOnlySyntheticVerifiedProvider.createProvider({
12151
12712
  generationId: options.generationId,
12152
12713
  scheduler,
12153
12714
  now: options.now ?? Date.now,
12154
12715
  referenceStore: options.storage.referenceStore,
12155
12716
  stateStore: options.storage.stateStore
12156
- }) : (0, import_subscriptions10.createCodexSubscriptionImageProvider)({
12157
- authStrategy,
12717
+ })] : routedProviders.map((providerId) => providerId === "codex-subscription" ? (0, import_subscriptions11.createCodexSubscriptionImageProvider)({
12718
+ authStrategy: codexStrategy,
12158
12719
  evidenceSource: generationEvidenceSource,
12159
12720
  executionScheduler: scheduler,
12160
12721
  generationTimeoutMs: config.queue.generationTimeoutMs,
12722
+ now: options.now,
12723
+ wire: {
12724
+ imageModel: config.codex.imageModel,
12725
+ carrierModel: config.codex.carrierModel
12726
+ }
12727
+ }) : (0, import_subscriptions11.createAntigravitySubscriptionImageProvider)({
12728
+ authStrategy: antigravityStrategy,
12729
+ executionScheduler: scheduler,
12730
+ generationTimeoutMs: config.queue.generationTimeoutMs,
12161
12731
  now: options.now
12162
- });
12163
- if (provider.id !== config.provider) {
12732
+ }));
12733
+ if (providers.length === 1 && providers[0].id !== "codex-subscription") {
12164
12734
  throw new TypeError("synthetic verified image provider id must match configured provider");
12165
12735
  }
12166
- const providerRegistry = new import_image_generation5.ImageProviderRegistry([provider]);
12736
+ const providerRegistry = new import_image_generation5.ImageProviderRegistry(providers);
12167
12737
  const orchestrator = new import_image_generation5.ImageOrchestrator({
12168
12738
  registry: providerRegistry,
12169
12739
  referenceStore: options.storage.referenceStore,
@@ -12185,35 +12755,53 @@ function createImageRuntimeGeneration(options) {
12185
12755
  ...options.createCallId ? { createCallId: options.createCallId } : {},
12186
12756
  ...options.now ? { now: options.now } : {}
12187
12757
  });
12758
+ const defaultProviderId = config.models[config.defaultModel] ?? "codex-subscription";
12759
+ const inspectOneProvider = async (providerId, apiKeyId) => {
12760
+ const capabilities = await orchestrator.getCapabilities(providerId, {
12761
+ requestId: `${options.generationId}:capability-inspection`,
12762
+ tenantId: apiKeyId,
12763
+ signal: new AbortController().signal,
12764
+ sessionKey: `outbound:images:${apiKeyId}`,
12765
+ ...config.account.id ? { preferredAccountId: config.account.id } : {},
12766
+ ...config.account.group ? { preferredAccountGroup: config.account.group } : {},
12767
+ boundAccountFallbackPolicy: config.account.fallback
12768
+ });
12769
+ return capabilities;
12770
+ };
12188
12771
  const inspectCapability = async (apiKeyId) => {
12189
- try {
12190
- const capabilities = await orchestrator.getCapabilities(config.provider, {
12191
- requestId: `${options.generationId}:capability-inspection`,
12192
- tenantId: apiKeyId,
12193
- signal: new AbortController().signal,
12194
- sessionKey: `outbound:images:${apiKeyId}`,
12195
- ...config.account.id ? { preferredAccountId: config.account.id } : {},
12196
- ...config.account.group ? { preferredAccountGroup: config.account.group } : {},
12197
- boundAccountFallbackPolicy: config.account.fallback
12198
- });
12199
- const available = capabilities.available === true && capabilities.generate === true && capabilities.models.includes(config.defaultModel);
12200
- return Object.freeze({
12201
- enabled: true,
12202
- available,
12203
- providerId: config.provider,
12204
- model: config.defaultModel,
12205
- ...!available ? { reason: capabilities.reason ?? "runtime_unavailable" } : {},
12206
- capabilities
12207
- });
12208
- } catch (error) {
12772
+ const providerCapabilities = /* @__PURE__ */ new Map();
12773
+ let defaultProviderError;
12774
+ for (const providerId of [...new Set(Object.values(config.models))]) {
12775
+ try {
12776
+ providerCapabilities.set(providerId, await inspectOneProvider(providerId, apiKeyId));
12777
+ } catch (error) {
12778
+ if (providerId === defaultProviderId) defaultProviderError = error;
12779
+ }
12780
+ }
12781
+ const routedModels = Object.freeze(
12782
+ [...providerCapabilities.entries()].flatMap(([providerId, capabilities2]) => capabilities2.available === true && capabilities2.generate === true ? Object.entries(config.models).filter(([model, modelProvider]) => modelProvider === providerId && capabilities2.models.includes(model)).map(([model]) => model) : [])
12783
+ );
12784
+ const capabilities = providerCapabilities.get(defaultProviderId);
12785
+ if (!capabilities) {
12209
12786
  return Object.freeze({
12210
12787
  enabled: true,
12211
12788
  available: false,
12212
- providerId: config.provider,
12789
+ providerId: defaultProviderId,
12213
12790
  model: config.defaultModel,
12214
- reason: error instanceof import_image_generation5.ImageGenerationError && (error.code === "upstream_auth_required" || error.code === "invalid_api_key") ? "account_unverified" : "runtime_unavailable"
12791
+ routedModels,
12792
+ reason: defaultProviderError instanceof import_image_generation5.ImageGenerationError && (defaultProviderError.code === "upstream_auth_required" || defaultProviderError.code === "invalid_api_key") ? "account_unverified" : "runtime_unavailable"
12215
12793
  });
12216
12794
  }
12795
+ const available = capabilities.available === true && capabilities.generate === true && capabilities.models.includes(config.defaultModel);
12796
+ return Object.freeze({
12797
+ enabled: true,
12798
+ available,
12799
+ providerId: defaultProviderId,
12800
+ model: config.defaultModel,
12801
+ routedModels,
12802
+ ...!available ? { reason: capabilities.reason ?? "runtime_unavailable" } : {},
12803
+ capabilities
12804
+ });
12217
12805
  };
12218
12806
  const resolverToDispose = runtimeResolver;
12219
12807
  const schedulerToDispose = scheduler;
@@ -12251,7 +12839,7 @@ function createImageRuntimeGeneration(options) {
12251
12839
  imageApi,
12252
12840
  hosted,
12253
12841
  hostedRuntime: Object.freeze({
12254
- providerId: config.provider,
12842
+ providerId: defaultProviderId,
12255
12843
  imageModel: config.defaultModel,
12256
12844
  referenceTtlMs: config.references.ttlMs,
12257
12845
  maxOutputBytes: config.limits.maxOutputBytes,
@@ -15194,6 +15782,9 @@ var ImageRuntimeManager = class {
15194
15782
  }
15195
15783
  async listAvailableModels(apiKeyId) {
15196
15784
  const inspection = await this.inspectCapability(apiKeyId);
15785
+ if (inspection.routedModels !== void 0) {
15786
+ return Object.freeze([...inspection.routedModels]);
15787
+ }
15197
15788
  return inspection.available && inspection.model === "gpt-image-2" ? Object.freeze([inspection.model]) : Object.freeze([]);
15198
15789
  }
15199
15790
  resourceStatus() {
@@ -17381,11 +17972,12 @@ var JsonVoucherDb = class {
17381
17972
  // src/ports/JsonSubscriptionCredentialStore.ts
17382
17973
  var import_node_fs28 = require("fs");
17383
17974
  var import_node_path27 = require("path");
17975
+ var import_GeminiCodeAssistProjectResolver5 = require("@omnicross/core/auth/GeminiCodeAssistProjectResolver");
17384
17976
  var import_SubscriptionAccountHealth2 = require("@omnicross/core/pipeline/SubscriptionAccountHealth");
17385
17977
  var import_AccountAllowanceScheduling3 = require("@omnicross/core/pipeline/AccountAllowanceScheduling");
17386
- var import_upstreamFetch12 = require("@omnicross/core/pipeline/upstreamFetch");
17978
+ var import_upstreamFetch14 = require("@omnicross/core/pipeline/upstreamFetch");
17387
17979
  var import_SubscriptionIdentityStore2 = require("@omnicross/core/provider-proxy/identity/SubscriptionIdentityStore");
17388
- var import_subscriptions11 = require("@omnicross/subscriptions");
17980
+ var import_subscriptions12 = require("@omnicross/subscriptions");
17389
17981
 
17390
17982
  // src/ports/account-sync.ts
17391
17983
  function viewOf(tokens) {
@@ -17533,7 +18125,7 @@ var JsonSubscriptionCredentialStore = class {
17533
18125
  * a plaintext token pair into `upstream-trace.jsonl`.
17534
18126
  */
17535
18127
  buildRefreshFetch(providerId, accountId) {
17536
- return this.fetchImpl ?? ((url, init) => (0, import_upstreamFetch12.fetchUpstream)(url, init, { providerId, accountId, redactBodies: true }));
18128
+ return this.fetchImpl ?? ((url, init) => (0, import_upstreamFetch14.fetchUpstream)(url, init, { providerId, accountId, redactBodies: true }));
17537
18129
  }
17538
18130
  /**
17539
18131
  * In-flight refresh coalescing. OAuth refresh tokens are
@@ -17574,7 +18166,7 @@ var JsonSubscriptionCredentialStore = class {
17574
18166
  * other hot reads. Never returns token material.
17575
18167
  */
17576
18168
  getAccountProxy(providerId, accountId) {
17577
- if (providerId !== "claude" && providerId !== "codex" && providerId !== "gemini" && providerId !== "opencodego" && providerId !== "kimi" && providerId !== "grok" && providerId !== "copilot") {
18169
+ if (providerId !== "claude" && providerId !== "codex" && providerId !== "gemini" && providerId !== "opencodego" && providerId !== "kimi" && providerId !== "grok" && providerId !== "copilot" && providerId !== "antigravity") {
17578
18170
  return void 0;
17579
18171
  }
17580
18172
  return getAccountProxy(this.readConfig(), providerId, accountId);
@@ -17593,7 +18185,7 @@ var JsonSubscriptionCredentialStore = class {
17593
18185
  const fingerprintOn = identityStore.isEnabled();
17594
18186
  const now = Date.now();
17595
18187
  const out = {};
17596
- for (const provider of ["claude", "codex", "gemini", "opencodego", "kimi", "grok", "copilot"]) {
18188
+ for (const provider of ["claude", "codex", "gemini", "opencodego", "kimi", "grok", "copilot", "antigravity"]) {
17597
18189
  const sanitized = sanitizeAccounts(config, provider);
17598
18190
  if (sanitized.length === 0) continue;
17599
18191
  for (const account of sanitized) {
@@ -17659,7 +18251,7 @@ var JsonSubscriptionCredentialStore = class {
17659
18251
  this.materializeMigration(config);
17660
18252
  const refreshFetch = this.buildRefreshFetch("claude", capturedId);
17661
18253
  try {
17662
- const result = await import_subscriptions11.claudeOAuth.refreshAccessToken(claude.refreshToken, refreshFetch);
18254
+ const result = await import_subscriptions12.claudeOAuth.refreshAccessToken(claude.refreshToken, refreshFetch);
17663
18255
  const expiresAt = new Date(Date.now() + result.expiresIn * 1e3).toISOString();
17664
18256
  const next = {
17665
18257
  ...claude,
@@ -17694,7 +18286,7 @@ var JsonSubscriptionCredentialStore = class {
17694
18286
  this.materializeMigration(config);
17695
18287
  const refreshFetch = this.buildRefreshFetch("codex", capturedId);
17696
18288
  try {
17697
- const result = await import_subscriptions11.codexOAuth.refreshAccessToken(codex.refreshToken, refreshFetch);
18289
+ const result = await import_subscriptions12.codexOAuth.refreshAccessToken(codex.refreshToken, refreshFetch);
17698
18290
  const expiresAt = new Date(Date.now() + result.expiresIn * 1e3).toISOString();
17699
18291
  const next = {
17700
18292
  ...codex,
@@ -17732,7 +18324,7 @@ var JsonSubscriptionCredentialStore = class {
17732
18324
  this.materializeMigration(config);
17733
18325
  const refreshFetch = this.buildRefreshFetch("gemini", capturedId);
17734
18326
  try {
17735
- const result = await import_subscriptions11.geminiOAuth.refreshAccessToken(gemini.refreshToken, refreshFetch);
18327
+ const result = await import_subscriptions12.geminiOAuth.refreshAccessToken(gemini.refreshToken, refreshFetch);
17736
18328
  const expiresAt = new Date(Date.now() + result.expiresIn * 1e3).toISOString();
17737
18329
  const next = {
17738
18330
  ...gemini,
@@ -17768,10 +18360,10 @@ var JsonSubscriptionCredentialStore = class {
17768
18360
  this.materializeMigration(config);
17769
18361
  const refreshFetch = this.buildRefreshFetch("kimi", capturedId);
17770
18362
  try {
17771
- const result = await import_subscriptions11.kimiOAuth.refreshAccessToken(
18363
+ const result = await import_subscriptions12.kimiOAuth.refreshAccessToken(
17772
18364
  kimi.refreshToken,
17773
18365
  refreshFetch,
17774
- import_subscriptions11.kimiOAuth.kimiFingerprintHeaders(kimi.deviceId)
18366
+ import_subscriptions12.kimiOAuth.kimiFingerprintHeaders(kimi.deviceId)
17775
18367
  );
17776
18368
  const expiresAt = new Date(Date.now() + result.expiresIn * 1e3).toISOString();
17777
18369
  const next = {
@@ -17808,8 +18400,8 @@ var JsonSubscriptionCredentialStore = class {
17808
18400
  this.materializeMigration(config);
17809
18401
  const refreshFetch = this.buildRefreshFetch("grok", capturedId);
17810
18402
  try {
17811
- const tokenEndpoint = await import_subscriptions11.grokOAuth.resolveGrokTokenEndpoint(refreshFetch);
17812
- const result = await import_subscriptions11.grokOAuth.refreshGrokAccessToken(grok.refreshToken, tokenEndpoint, refreshFetch);
18403
+ const tokenEndpoint = await import_subscriptions12.grokOAuth.resolveGrokTokenEndpoint(refreshFetch);
18404
+ const result = await import_subscriptions12.grokOAuth.refreshGrokAccessToken(grok.refreshToken, tokenEndpoint, refreshFetch);
17813
18405
  const expiresAt = new Date(Date.now() + result.expiresIn * 1e3).toISOString();
17814
18406
  const next = {
17815
18407
  ...grok,
@@ -17852,6 +18444,76 @@ var JsonSubscriptionCredentialStore = class {
17852
18444
  return false;
17853
18445
  });
17854
18446
  }
18447
+ /**
18448
+ * Refresh the Antigravity (Google) OAuth access token. Like gemini, the
18449
+ * Google token endpoint does NOT return a refresh_token on refresh, so this
18450
+ * writes ONLY access+expiresAt (+status/lastRefreshedAt) and DELIBERATELY
18451
+ * preserves the stored `refreshToken` — plus the account's `projectId`
18452
+ * (a handshake product; the post-refresh re-validation is the refresh
18453
+ * scheduler's hook, not this write) and `email`. HONEST `false` when no
18454
+ * refresh_token.
18455
+ */
18456
+ async refreshAntigravityToken() {
18457
+ return this.coalesce("antigravity:active", async () => {
18458
+ const config = this.readConfig();
18459
+ const active = getActiveAccount(config, "antigravity");
18460
+ const antigravity = active?.tokens;
18461
+ if (!active || !antigravity?.refreshToken) return false;
18462
+ const capturedId = active.id;
18463
+ this.materializeMigration(config);
18464
+ const refreshFetch = this.buildRefreshFetch("antigravity", capturedId);
18465
+ try {
18466
+ const result = await import_subscriptions12.antigravityOAuth.refreshAccessToken(antigravity.refreshToken, refreshFetch);
18467
+ const expiresAt = new Date(Date.now() + result.expiresIn * 1e3).toISOString();
18468
+ const next = {
18469
+ ...antigravity,
18470
+ // KEEP the existing refreshToken/projectId/email.
18471
+ accessToken: result.accessToken,
18472
+ expiresAt,
18473
+ status: "authorized",
18474
+ lastRefreshedAt: (/* @__PURE__ */ new Date()).toISOString(),
18475
+ errorMessage: void 0
18476
+ };
18477
+ this.writeBackById("antigravity", capturedId, next);
18478
+ await this.revalidateAntigravityProject(capturedId);
18479
+ return true;
18480
+ } catch (error) {
18481
+ this.markExpiredById("antigravity", capturedId, antigravity, error);
18482
+ return false;
18483
+ }
18484
+ });
18485
+ }
18486
+ /**
18487
+ * Post-refresh project re-validation hook (antigravity design D8): after a
18488
+ * successful antigravity token refresh, re-run the Code Assist project
18489
+ * handshake and write the (possibly rotated) `projectId` back to the account.
18490
+ * A handshake FAILURE keeps the stored projectId untouched (logged) so the
18491
+ * account keeps serving with the last-known-good project until a later
18492
+ * refresh succeeds. Returns whether the handshake produced a project.
18493
+ */
18494
+ async revalidateAntigravityProject(accountId) {
18495
+ const before = getAccountById(this.readConfig(), "antigravity", accountId);
18496
+ const accessToken = before?.tokens?.accessToken;
18497
+ if (!accessToken) return false;
18498
+ try {
18499
+ const projectId = await (0, import_GeminiCodeAssistProjectResolver5.getAntigravityProjectResolver)().resolveProject(accessToken);
18500
+ if (projectId !== void 0) {
18501
+ const config = this.readConfig();
18502
+ const account = getAccountById(config, "antigravity", accountId);
18503
+ const tokens = account?.tokens;
18504
+ if (account && tokens?.accessToken === accessToken && tokens.projectId !== projectId) {
18505
+ this.writeBackById("antigravity", accountId, { ...tokens, projectId });
18506
+ }
18507
+ return true;
18508
+ }
18509
+ return false;
18510
+ } catch (error) {
18511
+ console.warn(
18512
+ `[JsonSubscriptionCredentialStore] antigravity project re-validation failed for account ${accountId}: ` + (error instanceof Error ? error.message : String(error))
18513
+ );
18514
+ return false;
18515
+ }
18516
+ }
17855
18517
  /**
17856
18518
  * Refresh a SPECIFIC managed account by id (background scheduler sweep and
17857
18519
  * account-pool resolution). It uses only that account's stored refresh
@@ -17880,6 +18542,7 @@ var JsonSubscriptionCredentialStore = class {
17880
18542
  };
17881
18543
  if (refreshed.idToken) next.idToken = refreshed.idToken;
17882
18544
  this.writeBackById(provider, id, next);
18545
+ if (provider === "antigravity") await this.revalidateAntigravityProject(id);
17883
18546
  return true;
17884
18547
  } catch (error) {
17885
18548
  this.markExpiredById(provider, id, captured, error);
@@ -17904,7 +18567,7 @@ var JsonSubscriptionCredentialStore = class {
17904
18567
  }
17905
18568
  const oauth = account.tokens;
17906
18569
  if (!oauth.accessToken) return null;
17907
- if (providerId === "codex" || providerId === "gemini" || providerId === "kimi" || providerId === "grok" || providerId === "copilot") {
18570
+ if (providerId === "codex" || providerId === "gemini" || providerId === "kimi" || providerId === "grok" || providerId === "copilot" || providerId === "antigravity") {
17908
18571
  const expiresAtMs = oauth.expiresAt ? Date.parse(oauth.expiresAt) : 0;
17909
18572
  const expiringSoon = expiresAtMs > 0 && Date.now() >= expiresAtMs - ACCOUNT_REFRESH_LEAD_MS;
17910
18573
  if (expiringSoon && oauth.refreshToken) {
@@ -17997,10 +18660,10 @@ var JsonSubscriptionCredentialStore = class {
17997
18660
  if (provider === "kimi") {
17998
18661
  const account = accountId ? getAccountById(this.readConfig(), "kimi", accountId) : void 0;
17999
18662
  const deviceId = account?.tokens?.deviceId;
18000
- const r2 = await import_subscriptions11.kimiOAuth.refreshAccessToken(
18663
+ const r2 = await import_subscriptions12.kimiOAuth.refreshAccessToken(
18001
18664
  refreshToken,
18002
18665
  refreshFetch,
18003
- import_subscriptions11.kimiOAuth.kimiFingerprintHeaders(deviceId)
18666
+ import_subscriptions12.kimiOAuth.kimiFingerprintHeaders(deviceId)
18004
18667
  );
18005
18668
  return {
18006
18669
  accessToken: r2.accessToken,
@@ -18009,8 +18672,8 @@ var JsonSubscriptionCredentialStore = class {
18009
18672
  };
18010
18673
  }
18011
18674
  if (provider === "grok") {
18012
- const tokenEndpoint = await import_subscriptions11.grokOAuth.resolveGrokTokenEndpoint(refreshFetch);
18013
- const r2 = await import_subscriptions11.grokOAuth.refreshGrokAccessToken(refreshToken, tokenEndpoint, refreshFetch);
18675
+ const tokenEndpoint = await import_subscriptions12.grokOAuth.resolveGrokTokenEndpoint(refreshFetch);
18676
+ const r2 = await import_subscriptions12.grokOAuth.refreshGrokAccessToken(refreshToken, tokenEndpoint, refreshFetch);
18014
18677
  return {
18015
18678
  accessToken: r2.accessToken,
18016
18679
  refreshToken: r2.refreshToken,
@@ -18020,7 +18683,14 @@ var JsonSubscriptionCredentialStore = class {
18020
18683
  if (provider === "copilot") {
18021
18684
  throw new Error("GitHub Copilot tokens cannot be refreshed \u2014 re-authenticate the account");
18022
18685
  }
18023
- const flow = provider === "claude" ? import_subscriptions11.claudeOAuth : provider === "codex" ? import_subscriptions11.codexOAuth : import_subscriptions11.geminiOAuth;
18686
+ if (provider === "antigravity") {
18687
+ const r2 = await import_subscriptions12.antigravityOAuth.refreshAccessToken(refreshToken, refreshFetch);
18688
+ return {
18689
+ accessToken: r2.accessToken,
18690
+ expiresAt: new Date(Date.now() + r2.expiresIn * 1e3).toISOString()
18691
+ };
18692
+ }
18693
+ const flow = provider === "claude" ? import_subscriptions12.claudeOAuth : provider === "codex" ? import_subscriptions12.codexOAuth : import_subscriptions12.geminiOAuth;
18024
18694
  const r = await flow.refreshAccessToken(refreshToken, refreshFetch);
18025
18695
  return {
18026
18696
  accessToken: r.accessToken,
@@ -18263,7 +18933,7 @@ var JsonSubscriptionCredentialStore = class {
18263
18933
  };
18264
18934
 
18265
18935
  // src/AccountHealthProbeScheduler.ts
18266
- var import_upstreamFetch13 = require("@omnicross/core/pipeline/upstreamFetch");
18936
+ var import_upstreamFetch15 = require("@omnicross/core/pipeline/upstreamFetch");
18267
18937
 
18268
18938
  // src/probe/CodexGenerationProbe.ts
18269
18939
  var import_codexCliHeaders = require("@omnicross/core/provider-proxy/identity/codexCliHeaders");
@@ -18415,7 +19085,11 @@ var PROVIDER_PROBE_PLANS = {
18415
19085
  // The Copilot quota endpoint (copilot_internal/user) is a verified FREE
18416
19086
  // authed GET but lives on api.github.com with its own auth dialect and a
18417
19087
  // monthly-only window — the allowance collector owns the health surface.
18418
- copilot: { kind: "local" }
19088
+ copilot: { kind: "local" },
19089
+ // Antigravity's quota endpoints are POST RPCs on daily-cloudcode-pa (not a
19090
+ // cheap GET) and need the antigravity/hub UA — the allowance collector owns
19091
+ // the health surface; the probe stays local.
19092
+ antigravity: { kind: "local" }
18419
19093
  };
18420
19094
  function probePlanFor(providerId) {
18421
19095
  return PROVIDER_PROBE_PLANS[providerId] ?? { kind: "local" };
@@ -18437,7 +19111,7 @@ var AccountHealthProbeScheduler = class {
18437
19111
  this.logger = logger;
18438
19112
  this.config = config;
18439
19113
  this.now = opts.now ?? Date.now;
18440
- this.fetchImpl = opts.fetchImpl ?? import_upstreamFetch13.fetchUpstream;
19114
+ this.fetchImpl = opts.fetchImpl ?? import_upstreamFetch15.fetchUpstream;
18441
19115
  this.sleep = opts.sleep ?? ((ms) => new Promise((r) => setTimeout(r, ms)));
18442
19116
  this.planFor = opts.planFor ?? probePlanFor;
18443
19117
  }
@@ -19593,7 +20267,7 @@ var AuditWriter = class {
19593
20267
  var import_node_fs34 = require("fs");
19594
20268
  var import_node_crypto24 = require("crypto");
19595
20269
  var import_node_path34 = require("path");
19596
- var import_upstreamFetch14 = require("@omnicross/core/pipeline/upstreamFetch");
20270
+ var import_upstreamFetch16 = require("@omnicross/core/pipeline/upstreamFetch");
19597
20271
 
19598
20272
  // src/billing/billingFiles.ts
19599
20273
  var BILLING_FILE_RE = /^billing-(\d{4})-(\d{2})-(\d{2})\.jsonl$/;
@@ -19616,7 +20290,7 @@ var BillingPublisher = class {
19616
20290
  constructor(billingDir, logger, opts = {}) {
19617
20291
  this.billingDir = billingDir;
19618
20292
  this.logger = logger;
19619
- this.fetchImpl = opts.fetchImpl ?? ((url, init) => (0, import_upstreamFetch14.fetchUpstream)(url, init));
20293
+ this.fetchImpl = opts.fetchImpl ?? ((url, init) => (0, import_upstreamFetch16.fetchUpstream)(url, init));
19620
20294
  this.defer = opts.defer ?? ((fn) => setTimeout(fn, 0));
19621
20295
  this.timeoutMs = opts.timeoutMs ?? BILLING_POST_TIMEOUT_MS;
19622
20296
  this.now = opts.now ?? Date.now;
@@ -19866,7 +20540,7 @@ var BillingRetrySweeper = class {
19866
20540
  // src/TokenRefreshScheduler.ts
19867
20541
  var REFRESH_LEAD_MS2 = 5 * 6e4;
19868
20542
  var SWEEP_INTERVAL_MS5 = 6e4;
19869
- var OAUTH_PROVIDERS2 = ["claude", "codex", "gemini", "kimi", "grok", "copilot"];
20543
+ var OAUTH_PROVIDERS2 = ["claude", "codex", "gemini", "kimi", "grok", "copilot", "antigravity"];
19870
20544
  var TokenRefreshScheduler = class {
19871
20545
  constructor(store, logger, intervalMs = SWEEP_INTERVAL_MS5, leadMs = REFRESH_LEAD_MS2) {
19872
20546
  this.store = store;
@@ -19957,6 +20631,8 @@ var TokenRefreshScheduler = class {
19957
20631
  // never reaches this — the branch exists for union totality.
19958
20632
  case "copilot":
19959
20633
  return this.store.refreshCopilotToken();
20634
+ case "antigravity":
20635
+ return this.store.refreshAntigravityToken();
19960
20636
  }
19961
20637
  }
19962
20638
  };
@@ -20033,7 +20709,7 @@ function createRouteLeaseSubscriptionPreflight(credentials) {
20033
20709
 
20034
20710
  // src/webhook/WebhookDispatcher.ts
20035
20711
  var import_node_crypto25 = require("crypto");
20036
- var import_upstreamFetch15 = require("@omnicross/core/pipeline/upstreamFetch");
20712
+ var import_upstreamFetch17 = require("@omnicross/core/pipeline/upstreamFetch");
20037
20713
  var WEBHOOK_MAX_ATTEMPTS = 3;
20038
20714
  var WEBHOOK_QUEUE_MAX = 1e3;
20039
20715
  var WEBHOOK_SEND_TIMEOUT_MS = 1e4;
@@ -20053,7 +20729,7 @@ var WebhookDispatcher = class {
20053
20729
  sleep;
20054
20730
  now;
20055
20731
  constructor(opts = {}) {
20056
- this.fetchImpl = opts.fetchImpl ?? ((url, init) => (0, import_upstreamFetch15.fetchUpstream)(url, init));
20732
+ this.fetchImpl = opts.fetchImpl ?? ((url, init) => (0, import_upstreamFetch17.fetchUpstream)(url, init));
20057
20733
  this.logger = opts.logger;
20058
20734
  this.maxAttempts = opts.maxAttempts ?? WEBHOOK_MAX_ATTEMPTS;
20059
20735
  this.queueMax = opts.queueMax ?? WEBHOOK_QUEUE_MAX;
@@ -20139,8 +20815,8 @@ var WebhookDispatcher = class {
20139
20815
  signal: AbortSignal.timeout(this.timeoutMs)
20140
20816
  });
20141
20817
  return res.ok ? { ok: true, status: res.status } : { ok: false, status: res.status };
20142
- } catch (err8) {
20143
- return { ok: false, error: err8 instanceof Error ? err8.message : String(err8) };
20818
+ } catch (err9) {
20819
+ return { ok: false, error: err9 instanceof Error ? err9.message : String(err9) };
20144
20820
  }
20145
20821
  }
20146
20822
  /**
@@ -20277,12 +20953,12 @@ function buildDaemon(config, paths) {
20277
20953
  setSecretBox(secretBox3);
20278
20954
  setSecretBox2(secretBox3);
20279
20955
  const decryptedConfig = decryptConfigSecrets(config, secretBox3);
20280
- const accountAllowanceStore = new import_AccountAllowanceStore10.AccountAllowanceStore(
20956
+ const accountAllowanceStore = new import_AccountAllowanceStore11.AccountAllowanceStore(
20281
20957
  Date.now,
20282
20958
  void 0,
20283
20959
  new JsonAccountAllowancePersistence(defaultAccountAllowancePath(paths.configPath))
20284
20960
  );
20285
- (0, import_AccountAllowanceStore10.setSharedAccountAllowanceStore)(accountAllowanceStore);
20961
+ (0, import_AccountAllowanceStore11.setSharedAccountAllowanceStore)(accountAllowanceStore);
20286
20962
  (0, import_AccountAllowanceScheduling5.getSharedAccountAllowanceScheduling)().configure(
20287
20963
  (0, import_outbound_api10.normalizeServerConfig)(decryptedConfig.server).allowanceScheduling
20288
20964
  );
@@ -20307,20 +20983,22 @@ function buildDaemon(config, paths) {
20307
20983
  claudeAllowanceRefreshScheduler.configure(
20308
20984
  (0, import_outbound_api10.normalizeServerConfig)(decryptedConfig.server).allowanceScheduling
20309
20985
  );
20310
- const subscriptionAccounts = new import_subscriptions12.SubscriptionAccountService(credentialStore);
20311
- (0, import_subscriptions12.setSubscriptionAccountService)(subscriptionAccounts);
20312
- const subscriptionRegistry = new import_subscriptions12.SubscriptionProviderRegistry(
20986
+ const subscriptionAccounts = new import_subscriptions13.SubscriptionAccountService(credentialStore);
20987
+ (0, import_subscriptions13.setSubscriptionAccountService)(subscriptionAccounts);
20988
+ const subscriptionRegistry = new import_subscriptions13.SubscriptionProviderRegistry(
20313
20989
  subscriptionAccounts,
20314
20990
  credentialStore
20315
20991
  );
20316
- (0, import_subscriptions12.setSubscriptionProviderRegistry)(subscriptionRegistry);
20992
+ (0, import_subscriptions13.setSubscriptionProviderRegistry)(subscriptionRegistry);
20317
20993
  setServerProxyConfig(decryptedConfig.server?.proxy);
20318
- (0, import_upstreamFetch16.setUpstreamProxyResolver)(
20994
+ (0, import_upstreamFetch18.setUpstreamProxyResolver)(
20319
20995
  createUpstreamProxyResolver({
20320
20996
  getAccountProxy: (providerId, accountId) => credentialStore.getAccountProxy(providerId, accountId)
20321
20997
  })
20322
20998
  );
20323
- (0, import_gemini_code_assist_resolver.setGeminiCodeAssistResolver)((0, import_GeminiCodeAssistProjectResolver2.getGeminiCodeAssistProjectResolver)());
20999
+ (0, import_gemini_code_assist_resolver.setGeminiCodeAssistResolver)((0, import_GeminiCodeAssistProjectResolver6.getGeminiCodeAssistProjectResolver)());
21000
+ (0, import_antigravityFailover.setAntigravitySandboxFailover)(decryptedConfig.antigravity?.sandboxFailover === true);
21001
+ (0, import_openCodeGoHeaders2.setOpenCodeGoUserAgent)(decryptedConfig.opencodego?.userAgent ?? null);
20324
21002
  const autoDisableStore = new AutoDisableStore();
20325
21003
  const providerKeyQuotaService = new ProviderKeyQuotaService(secretBox3);
20326
21004
  const apiKeyPool = new import_ApiKeyPoolService.ApiKeyPoolService(
@@ -20339,7 +21017,7 @@ function buildDaemon(config, paths) {
20339
21017
  const pricingEngine = new import_usage2.PricingEngine(pricingStore, logger, {
20340
21018
  // Catalog egress follows the same global/env proxy policy as every other
20341
21019
  // daemon upstream call; no provider/account override applies here.
20342
- fetchImpl: ((input, init) => (0, import_upstreamFetch16.fetchUpstream)(String(input), init ?? {}))
21020
+ fetchImpl: ((input, init) => (0, import_upstreamFetch18.fetchUpstream)(String(input), init ?? {}))
20343
21021
  });
20344
21022
  const pricingRefreshScheduler = new PricingRefreshScheduler(
20345
21023
  pricingEngine,
@@ -20624,7 +21302,7 @@ function buildDaemon(config, paths) {
20624
21302
  // — `server.proxy.byProvider[...]` was silently skipped — and the call was
20625
21303
  // excluded from the upstream trace, so a failing login left no evidence.
20626
21304
  // `redactBodies` keeps the code/verifier + minted token out of that trace.
20627
- oauthExchangeFetch: paths.oauthExchangeFetch ? () => paths.oauthExchangeFetch : (providerId) => (url, init) => (0, import_upstreamFetch16.fetchUpstream)(url, init, { providerId, redactBodies: true }),
21305
+ oauthExchangeFetch: paths.oauthExchangeFetch ? () => paths.oauthExchangeFetch : (providerId) => (url, init) => (0, import_upstreamFetch18.fetchUpstream)(url, init, { providerId, redactBodies: true }),
20628
21306
  subscriptionAccountAppender: credentialStore,
20629
21307
  // Codex interactive OAuth (app-parity-2 child 5) — the async loopback flow store
20630
21308
  // + the one-shot 127.0.0.1:1455 listener. Token captured + persisted daemon-side;
@@ -20639,6 +21317,21 @@ function buildDaemon(config, paths) {
20639
21317
  // Grok interactive OAuth — the same async DEVICE-CODE shape as kimi.
20640
21318
  grokSessions: new CodexOAuthSessionStore(),
20641
21319
  copilotSessions: new CodexOAuthSessionStore(),
21320
+ // Antigravity interactive OAuth — the async LOOPBACK flow store + the
21321
+ // one-shot 127.0.0.1:51121 listener (same shape as codex; test seam below).
21322
+ antigravitySessions: new CodexOAuthSessionStore(),
21323
+ antigravityAwaitLoopback: paths.antigravityAwaitLoopback ?? ((state, timeoutMs, signal) => awaitLoopbackCode(state, timeoutMs, signal, {
21324
+ port: 51121,
21325
+ path: "/oauth-callback",
21326
+ label: "antigravity"
21327
+ })),
21328
+ // The dynamic model-catalog probe's token source (the ACTIVE antigravity
21329
+ // account; refreshed by the by-id near-expiry seam inside the lookup).
21330
+ resolveAntigravityAccessToken: async () => {
21331
+ const config2 = await credentialStore.getFullConfig();
21332
+ const activeId = config2.activeAntigravityAccountId ?? config2.antigravityAccounts?.[0]?.id;
21333
+ return activeId ? credentialStore.getAccessTokenForAccount("antigravity", activeId) : null;
21334
+ },
20642
21335
  // Migration pack (app-parity child 6, design D2/D3) — the concrete credential
20643
21336
  // store provides BOTH the full DECRYPTED read (`getFullConfig`, export) and
20644
21337
  // the multi-account append (`appendProviderAccount`, import re-encrypts at-
@@ -20697,7 +21390,7 @@ function buildDaemon(config, paths) {
20697
21390
  });
20698
21391
  const webhookDispatcher = new WebhookDispatcher({
20699
21392
  logger,
20700
- fetchImpl: (url, init) => (0, import_upstreamFetch16.fetchUpstream)(url, init)
21393
+ fetchImpl: (url, init) => (0, import_upstreamFetch18.fetchUpstream)(url, init)
20701
21394
  });
20702
21395
  setWebhookRuntime(webhookDispatcher, (0, import_SubscriptionAccountHealth4.getSharedAccountHealth)());
20703
21396
  const auditWriter = new AuditWriter(auditDir, logger);
@@ -20832,15 +21525,59 @@ function buildClaudeDoctorChecks(config) {
20832
21525
  });
20833
21526
  return checks;
20834
21527
  }
21528
+ function buildAntigravityDoctorChecks(snapshot) {
21529
+ const checks = [];
21530
+ checks.push({
21531
+ name: "antigravity credential",
21532
+ ok: snapshot.accountCount > 0 && snapshot.hasAccessToken,
21533
+ detail: snapshot.accountCount === 0 ? "no antigravity account stored \u2014 run `omnicross login antigravity`" : `${snapshot.accountCount} account(s)${snapshot.activeEmail ? `, active: ${snapshot.activeEmail}` : ""}${snapshot.hasAccessToken ? "" : " \u2014 the active account has no access token"}`
21534
+ });
21535
+ const expiresAtMs = snapshot.expiresAt ? Date.parse(snapshot.expiresAt) : 0;
21536
+ const expired = snapshot.expired || expiresAtMs > 0 && Date.now() >= expiresAtMs;
21537
+ const expiringSoon = expiresAtMs > 0 && Date.now() >= expiresAtMs - 10 * 6e4;
21538
+ checks.push({
21539
+ name: "token freshness",
21540
+ ok: !expired,
21541
+ warn: !expired && expiringSoon,
21542
+ detail: expired ? "the active account is expired (its last refresh failed \u2014 re-login or fix the refresh path)" : snapshot.expiresAt ? `expires at ${snapshot.expiresAt}${expiringSoon ? " (inside the refresh lead window)" : ""}` : "no expiry recorded (refresh scheduler treats it as non-expiring)"
21543
+ });
21544
+ return checks;
21545
+ }
21546
+ function hasFreshAntigravityQuota(snapshot, now = Date.now()) {
21547
+ if (!snapshot || snapshot.lastErrorCode) return false;
21548
+ if (snapshot.expiresAt && !(Date.parse(snapshot.expiresAt) > now)) return false;
21549
+ return snapshot.windows.some(
21550
+ (window) => window.state === "fresh" && (!window.resetsAt || Date.parse(window.resetsAt) > now) && (window.disabled === true || typeof window.usedPercent === "number" && Number.isFinite(window.usedPercent))
21551
+ );
21552
+ }
21553
+ function buildAntigravityLiveChecks(result) {
21554
+ return [
21555
+ {
21556
+ name: "token refresh (--live)",
21557
+ ok: result.refreshOk,
21558
+ detail: result.refreshOk ? "the active account refreshed successfully" : "refresh failed (see the daemon log)"
21559
+ },
21560
+ {
21561
+ name: "quota collection (--live)",
21562
+ ok: result.quotaOk,
21563
+ detail: result.quotaOk ? "quotaSummary windows collected" : result.detail
21564
+ }
21565
+ ];
21566
+ }
20835
21567
  function buildImagesDoctorChecks(snapshot) {
20836
21568
  const enabled = snapshot.config.enabled;
20837
- const accountOk = !enabled || snapshot.account.usable;
21569
+ const routed = snapshot.config.routedProviders ?? ["codex-subscription"];
21570
+ const codexRouted = routed.includes("codex-subscription");
21571
+ const antigravityRouted = routed.includes("antigravity-subscription");
21572
+ const antigravity = snapshot.antigravityAccount ?? { present: false, usable: false, reason: "missing" };
21573
+ const accountOk = !enabled || !codexRouted || snapshot.account.usable;
21574
+ const antigravityOk = !enabled || !antigravityRouted || antigravity.usable;
20838
21575
  const evidenceOk = !enabled || snapshot.evidence.valid && snapshot.evidence.freshEntries > 0;
20839
21576
  return [
20840
21577
  {
20841
21578
  name: "normalized Images config",
20842
21579
  ok: snapshot.config.valid,
20843
- detail: snapshot.config.valid ? `enabled=${enabled}, provider=${snapshot.config.provider}, model=${snapshot.config.model}` : `invalid normalized configuration (${snapshot.config.errorCount} issue(s))`
21580
+ detail: snapshot.config.valid ? `enabled=${enabled}, providers=${routed.join("+")}, default=${snapshot.config.model} (${snapshot.config.provider})` : `invalid normalized configuration (${snapshot.config.errorCount} issue(s))`
20844
21581
  },
20845
21582
  {
20846
21583
  name: "private roots",
@@ -20861,8 +21598,14 @@ function buildImagesDoctorChecks(snapshot) {
20861
21598
  {
20862
21599
  name: "Codex account",
20863
21600
  ok: accountOk,
20864
- warn: !snapshot.account.usable,
20865
- detail: snapshot.account.usable ? "eligible local credential is present" : `${snapshot.account.reason}; Images live verification is unavailable`
21601
+ warn: enabled && codexRouted && !snapshot.account.usable,
21602
+ detail: !codexRouted ? "not routed by the current model table (no credential required)" : snapshot.account.usable ? "eligible local credential is present" : `${snapshot.account.reason}; codex-routed image models and live verification are unavailable`
21603
+ },
21604
+ {
21605
+ name: "Antigravity account",
21606
+ ok: antigravityOk,
21607
+ warn: enabled && antigravityRouted && !antigravity.usable,
21608
+ detail: !antigravityRouted ? "not routed by the current model table (no credential required)" : antigravity.usable ? "eligible local credential is present (protocol evidence still unverified)" : `${antigravity.reason}; antigravity-routed image models are unavailable`
20866
21609
  },
20867
21610
  {
20868
21611
  name: "cached capability evidence",
@@ -20877,6 +21620,12 @@ async function runImagesLiveDoctor(config, doctor, signal = new AbortController(
20877
21620
  " [\u26A0] live Images verification may consume subscription quota; one minimal low-quality PNG request will be sent"
20878
21621
  );
20879
21622
  const result = await doctor.verifyLive(config.images ?? import_outbound_api12.DEFAULT_IMAGES_SERVER_CONFIG, signal);
21623
+ const antigravityRouted = Object.values(config.images?.models ?? {}).includes("antigravity-subscription");
21624
+ if (antigravityRouted) {
21625
+ console.info(
21626
+ " [i] live verification covers the Codex wire only; the Antigravity provider has no independent verifier in v1 (its first real request bootstraps)"
21627
+ );
21628
+ }
20880
21629
  if (!result.ok) {
20881
21630
  console.info(` [\u2717] live Images verification: ${result.code}`);
20882
21631
  return false;
@@ -21011,14 +21760,49 @@ async function runLiveProbe(url, key, fetchImpl = fetch) {
21011
21760
  status: res.status,
21012
21761
  estimateHeader: res.headers.get("x-omnicross-count-estimate")
21013
21762
  };
21014
- } catch (err8) {
21763
+ } catch (err9) {
21015
21764
  return {
21016
21765
  status: null,
21017
21766
  estimateHeader: null,
21018
- error: err8 instanceof Error ? err8.message : String(err8)
21767
+ error: err9 instanceof Error ? err9.message : String(err9)
21019
21768
  };
21020
21769
  }
21021
21770
  }
21771
+ async function runAntigravityDoctor(daemon, live) {
21772
+ const config = await daemon.credentialStore.getFullConfig();
21773
+ const accounts = config.antigravityAccounts ?? [];
21774
+ const activeId = config.activeAntigravityAccountId ?? accounts[0]?.id;
21775
+ const active = accounts.find((account) => account.id === activeId);
21776
+ const snapshot = {
21777
+ accountCount: accounts.length,
21778
+ ...active?.tokens.email ? { activeEmail: active.tokens.email } : {},
21779
+ hasAccessToken: Boolean(active?.tokens.accessToken),
21780
+ expired: active?.tokens.status === "expired",
21781
+ ...active?.tokens.expiresAt ? { expiresAt: active.tokens.expiresAt } : {}
21782
+ };
21783
+ const checks = buildAntigravityDoctorChecks(snapshot);
21784
+ if (live && active) {
21785
+ const refreshOk = await daemon.credentialStore.refreshAntigravityToken();
21786
+ let quotaOk = false;
21787
+ let detail = "quotaSummary collection produced no usable windows";
21788
+ try {
21789
+ const snapshots = await daemon.accountAllowanceService.refreshAntigravity(active.id);
21790
+ quotaOk = hasFreshAntigravityQuota(snapshots.find((entry) => entry.accountId === active.id));
21791
+ if (!quotaOk) detail = snapshots[0]?.lastErrorCode ?? detail;
21792
+ } catch (error) {
21793
+ detail = error instanceof Error ? error.message : String(error);
21794
+ }
21795
+ checks.push(...buildAntigravityLiveChecks({ refreshOk, quotaOk, detail }));
21796
+ }
21797
+ console.info("omnicross doctor antigravity \u2014 subscription credential health");
21798
+ let hardFailure = false;
21799
+ for (const check of checks) {
21800
+ const mark = check.ok ? check.warn ? "\u26A0" : "\u2713" : "\u2717";
21801
+ if (!check.ok) hardFailure = true;
21802
+ console.info(` [${mark}] ${check.name}: ${check.detail}`);
21803
+ }
21804
+ return hardFailure ? 1 : 0;
21805
+ }
21022
21806
  async function runDoctor(argv, fetchImpl = fetch) {
21023
21807
  const { values, positionals } = (0, import_node_util2.parseArgs)({
21024
21808
  args: argv,
@@ -21032,8 +21816,8 @@ async function runDoctor(argv, fetchImpl = fetch) {
21032
21816
  allowPositionals: true
21033
21817
  });
21034
21818
  const subject = positionals[0] ?? "claude";
21035
- if (subject !== "claude" && subject !== "images" && subject !== "search") {
21036
- throw new Error(`doctor: unknown subject '${subject}' (supported: 'claude', 'images', 'search')`);
21819
+ if (subject !== "claude" && subject !== "images" && subject !== "search" && subject !== "antigravity") {
21820
+ throw new Error(`doctor: unknown subject '${subject}' (supported: 'claude', 'images', 'search', 'antigravity')`);
21037
21821
  }
21038
21822
  const configPath = values.config;
21039
21823
  if (!configPath) {
@@ -21056,6 +21840,9 @@ async function runDoctor(argv, fetchImpl = fetch) {
21056
21840
  runtime: daemon.searchRuntime
21057
21841
  });
21058
21842
  }
21843
+ if (subject === "antigravity") {
21844
+ return await runAntigravityDoctor(daemon, values.live === true);
21845
+ }
21059
21846
  const checks = subject === "images" ? buildImagesDoctorChecks(await daemon.imageDoctor.inspectLocal(
21060
21847
  serverConfig.images ?? import_outbound_api12.DEFAULT_IMAGES_SERVER_CONFIG
21061
21848
  )) : buildClaudeDoctorChecks(serverConfig);
@@ -21422,9 +22209,9 @@ async function runLaunch(argv, deps) {
21422
22209
  await daemon.llmConfig.ready();
21423
22210
  await daemon.migrateUsageStore();
21424
22211
  await daemon.providerProxy.start();
21425
- } catch (err8) {
22212
+ } catch (err9) {
21426
22213
  await shutdownLaunchDaemon(daemon);
21427
- throw err8;
22214
+ throw err9;
21428
22215
  }
21429
22216
  let launch;
21430
22217
  try {
@@ -21432,9 +22219,9 @@ async function runLaunch(argv, deps) {
21432
22219
  providerId: values.provider,
21433
22220
  model: values.model
21434
22221
  });
21435
- } catch (err8) {
22222
+ } catch (err9) {
21436
22223
  await shutdownLaunchDaemon(daemon);
21437
- throw err8;
22224
+ throw err9;
21438
22225
  }
21439
22226
  try {
21440
22227
  const plan = buildCliSpawnPlan({
@@ -21539,9 +22326,9 @@ function spawnCliInherit(plan) {
21539
22326
  process.removeListener("SIGINT", onSignal);
21540
22327
  process.removeListener("SIGTERM", onSignal);
21541
22328
  };
21542
- child.on("error", (err8) => {
22329
+ child.on("error", (err9) => {
21543
22330
  detach();
21544
- if (err8.code === "ENOENT") {
22331
+ if (err9.code === "ENOENT") {
21545
22332
  reject(
21546
22333
  new Error(
21547
22334
  `launch: "${plan.command}" not found on PATH \u2014 install the CLI first.`
@@ -21549,7 +22336,7 @@ function spawnCliInherit(plan) {
21549
22336
  );
21550
22337
  return;
21551
22338
  }
21552
- reject(err8);
22339
+ reject(err9);
21553
22340
  });
21554
22341
  child.on("exit", (code, signal) => {
21555
22342
  detach();
@@ -21562,9 +22349,10 @@ function spawnCliInherit(plan) {
21562
22349
  var import_node_child_process3 = require("child_process");
21563
22350
  var import_node_readline2 = require("readline");
21564
22351
  var import_node_util7 = require("util");
21565
- var import_upstreamFetch17 = require("@omnicross/core/pipeline/upstreamFetch");
21566
- var import_subscriptions13 = require("@omnicross/subscriptions");
21567
- var PROVIDERS2 = ["claude", "codex", "gemini", "kimi", "grok", "copilot"];
22352
+ var import_GeminiCodeAssistProjectResolver7 = require("@omnicross/core/auth/GeminiCodeAssistProjectResolver");
22353
+ var import_upstreamFetch19 = require("@omnicross/core/pipeline/upstreamFetch");
22354
+ var import_subscriptions14 = require("@omnicross/subscriptions");
22355
+ var PROVIDERS2 = ["claude", "codex", "gemini", "kimi", "grok", "copilot", "antigravity"];
21568
22356
  async function runLogin(argv, deps) {
21569
22357
  const { values, positionals } = (0, import_node_util7.parseArgs)({
21570
22358
  args: argv,
@@ -21591,11 +22379,11 @@ async function runLogin(argv, deps) {
21591
22379
  if (values.enterprise !== void 0 && provider !== "copilot") {
21592
22380
  throw new Error("login: --enterprise is only supported for the copilot provider");
21593
22381
  }
21594
- const enterpriseDomain = values.enterprise !== void 0 ? import_subscriptions13.copilotOAuth.normalizeCopilotEnterpriseDomain(values.enterprise) : void 0;
22382
+ const enterpriseDomain = values.enterprise !== void 0 ? import_subscriptions14.copilotOAuth.normalizeCopilotEnterpriseDomain(values.enterprise) : void 0;
21595
22383
  const resolved = {
21596
22384
  openBrowser: deps?.openBrowser ?? openBrowser,
21597
22385
  promptPaste: deps?.promptPaste ?? promptPaste,
21598
- awaitLoopback: deps?.awaitLoopback ?? ((state) => awaitLoopbackCode(state)),
22386
+ awaitLoopback: deps?.awaitLoopback ?? ((state, timeoutMs, signal, binding) => awaitLoopbackCode(state, timeoutMs, signal, binding)),
21599
22387
  awaitKimiDevice: deps?.awaitKimiDevice ?? ((fetchImpl) => runKimiDeviceFlow(fetchImpl, resolvedOpenBrowser)),
21600
22388
  awaitGrokDevice: deps?.awaitGrokDevice ?? ((fetchImpl) => runGrokDeviceFlow(fetchImpl, resolvedOpenBrowser)),
21601
22389
  awaitCopilotDevice: deps?.awaitCopilotDevice ?? ((fetchImpl, enterpriseUrl) => runCopilotDeviceFlow(fetchImpl, resolvedOpenBrowser, enterpriseUrl)),
@@ -21604,10 +22392,10 @@ async function runLogin(argv, deps) {
21604
22392
  const resolvedOpenBrowser = resolved.openBrowser;
21605
22393
  const box = resolveSecretBox(values["master-key-file"]);
21606
22394
  setSecretBox(box);
21607
- (0, import_upstreamFetch17.setUpstreamProxyResolver)(createUpstreamProxyResolver());
22395
+ (0, import_upstreamFetch19.setUpstreamProxyResolver)(createUpstreamProxyResolver());
21608
22396
  try {
21609
22397
  const tokensPath = defaultTokensPath(values.config);
21610
- const exchangeFetch = resolved.tokensFetch ?? ((url, init) => (0, import_upstreamFetch17.fetchUpstream)(url, init, { providerId: provider, redactBodies: true }));
22398
+ const exchangeFetch = resolved.tokensFetch ?? ((url, init) => (0, import_upstreamFetch19.fetchUpstream)(url, init, { providerId: provider, redactBodies: true }));
21611
22399
  const store = new JsonSubscriptionCredentialStore(tokensPath, box, exchangeFetch);
21612
22400
  const expiresAt = await runProviderLogin(
21613
22401
  provider,
@@ -21621,7 +22409,7 @@ async function runLogin(argv, deps) {
21621
22409
  console.info(` token: [stored, encrypted] expiresAt: ${expiresAt ?? "n/a"}`);
21622
22410
  } finally {
21623
22411
  setSecretBox(null);
21624
- (0, import_upstreamFetch17.setUpstreamProxyResolver)(null);
22412
+ (0, import_upstreamFetch19.setUpstreamProxyResolver)(null);
21625
22413
  }
21626
22414
  }
21627
22415
  async function runProviderLogin(provider, store, deps, exchangeFetch, label, enterpriseUrl) {
@@ -21630,13 +22418,14 @@ async function runProviderLogin(provider, store, deps, exchangeFetch, label, ent
21630
22418
  if (provider === "kimi") return loginKimi(store, deps, exchangeFetch, label);
21631
22419
  if (provider === "grok") return loginGrok(store, deps, exchangeFetch, label);
21632
22420
  if (provider === "copilot") return loginCopilot(store, deps, exchangeFetch, label, enterpriseUrl);
22421
+ if (provider === "antigravity") return loginAntigravity(store, deps, exchangeFetch, label);
21633
22422
  return loginGemini(store, deps, exchangeFetch, label);
21634
22423
  }
21635
22424
  async function loginCodex(store, deps, exchangeFetch, label) {
21636
- const { authUrl, codeVerifier, state } = import_subscriptions13.codexOAuth.generateAuthParams();
22425
+ const { authUrl, codeVerifier, state } = import_subscriptions14.codexOAuth.generateAuthParams();
21637
22426
  await presentUrl(authUrl, deps);
21638
22427
  const code = await deps.awaitLoopback(state);
21639
- const result = await import_subscriptions13.codexOAuth.exchangeCodeForTokens(
22428
+ const result = await import_subscriptions14.codexOAuth.exchangeCodeForTokens(
21640
22429
  { authorizationCode: code, codeVerifier, state },
21641
22430
  exchangeFetch
21642
22431
  );
@@ -21655,7 +22444,7 @@ async function loginCodex(store, deps, exchangeFetch, label) {
21655
22444
  return expiresAt;
21656
22445
  }
21657
22446
  async function loginClaude(store, deps, exchangeFetch, label) {
21658
- const { authUrl, codeVerifier, state } = import_subscriptions13.claudeOAuth.generateAuthParams();
22447
+ const { authUrl, codeVerifier, state } = import_subscriptions14.claudeOAuth.generateAuthParams();
21659
22448
  await presentUrl(authUrl, deps);
21660
22449
  const pasted = (await deps.promptPaste("Paste the authorization code (code#state): ")).trim();
21661
22450
  const [code, pastedState] = pasted.split("#");
@@ -21663,7 +22452,7 @@ async function loginClaude(store, deps, exchangeFetch, label) {
21663
22452
  if (pastedState && pastedState !== state) {
21664
22453
  throw new Error("login: pasted state did not match (possible CSRF) \u2014 aborting");
21665
22454
  }
21666
- const result = await import_subscriptions13.claudeOAuth.exchangeCodeForTokens(
22455
+ const result = await import_subscriptions14.claudeOAuth.exchangeCodeForTokens(
21667
22456
  { authorizationCode: code, codeVerifier, state },
21668
22457
  exchangeFetch
21669
22458
  );
@@ -21682,11 +22471,11 @@ async function loginClaude(store, deps, exchangeFetch, label) {
21682
22471
  return expiresAt;
21683
22472
  }
21684
22473
  async function loginGemini(store, deps, exchangeFetch, label) {
21685
- const { authUrl, codeVerifier } = import_subscriptions13.geminiOAuth.generateAuthParams();
22474
+ const { authUrl, codeVerifier } = import_subscriptions14.geminiOAuth.generateAuthParams();
21686
22475
  await presentUrl(authUrl, deps);
21687
22476
  const code = (await deps.promptPaste("Paste the authorization code: ")).trim();
21688
22477
  if (!code) throw new Error("login: no authorization code was pasted");
21689
- const result = await import_subscriptions13.geminiOAuth.exchangeCodeForTokens(code, codeVerifier, exchangeFetch);
22478
+ const result = await import_subscriptions14.geminiOAuth.exchangeCodeForTokens(code, codeVerifier, exchangeFetch);
21690
22479
  const expiresAt = new Date(Date.now() + result.expiresIn * 1e3).toISOString();
21691
22480
  const block = {
21692
22481
  authMethod: "oauth",
@@ -21701,9 +22490,9 @@ async function loginGemini(store, deps, exchangeFetch, label) {
21701
22490
  return expiresAt;
21702
22491
  }
21703
22492
  async function runKimiDeviceFlow(exchangeFetch, openBrowserFn) {
21704
- const deviceId = import_subscriptions13.kimiOAuth.generateKimiDeviceId();
21705
- const fingerprint = import_subscriptions13.kimiOAuth.kimiFingerprintHeaders(deviceId);
21706
- const authorization = await import_subscriptions13.kimiOAuth.requestDeviceAuthorization(exchangeFetch, fingerprint);
22493
+ const deviceId = import_subscriptions14.kimiOAuth.generateKimiDeviceId();
22494
+ const fingerprint = import_subscriptions14.kimiOAuth.kimiFingerprintHeaders(deviceId);
22495
+ const authorization = await import_subscriptions14.kimiOAuth.requestDeviceAuthorization(exchangeFetch, fingerprint);
21707
22496
  const url = authorization.verificationUriComplete ?? authorization.verificationUri;
21708
22497
  console.info("Open this URL in your browser and approve the request:");
21709
22498
  console.info(` ${url}`);
@@ -21711,14 +22500,14 @@ async function runKimiDeviceFlow(exchangeFetch, openBrowserFn) {
21711
22500
  console.info(` Then enter this code: ${authorization.userCode}`);
21712
22501
  }
21713
22502
  await openBrowserFn(url).catch(() => false);
21714
- const result = await import_subscriptions13.kimiOAuth.awaitDeviceToken(authorization, exchangeFetch, {
22503
+ const result = await import_subscriptions14.kimiOAuth.awaitDeviceToken(authorization, exchangeFetch, {
21715
22504
  fingerprint,
21716
22505
  onPending: () => process.stdout.write(".")
21717
22506
  });
21718
22507
  console.info("");
21719
22508
  return {
21720
22509
  ...result,
21721
- accountId: import_subscriptions13.kimiOAuth.kimiAccountIdFromAccessToken(result.accessToken),
22510
+ accountId: import_subscriptions14.kimiOAuth.kimiAccountIdFromAccessToken(result.accessToken),
21722
22511
  deviceId
21723
22512
  };
21724
22513
  }
@@ -21740,8 +22529,8 @@ async function loginKimi(store, deps, exchangeFetch, label) {
21740
22529
  return expiresAt;
21741
22530
  }
21742
22531
  async function runGrokDeviceFlow(exchangeFetch, openBrowserFn) {
21743
- const tokenEndpoint = await import_subscriptions13.grokOAuth.resolveGrokTokenEndpoint(exchangeFetch);
21744
- const authorization = await import_subscriptions13.grokOAuth.requestGrokDeviceAuthorization(exchangeFetch);
22532
+ const tokenEndpoint = await import_subscriptions14.grokOAuth.resolveGrokTokenEndpoint(exchangeFetch);
22533
+ const authorization = await import_subscriptions14.grokOAuth.requestGrokDeviceAuthorization(exchangeFetch);
21745
22534
  const url = authorization.verificationUriComplete ?? authorization.verificationUri;
21746
22535
  console.info("Open this URL in your browser and approve the request:");
21747
22536
  console.info(` ${url}`);
@@ -21749,13 +22538,13 @@ async function runGrokDeviceFlow(exchangeFetch, openBrowserFn) {
21749
22538
  console.info(` Then enter this code: ${authorization.userCode}`);
21750
22539
  }
21751
22540
  await openBrowserFn(url).catch(() => false);
21752
- const result = await import_subscriptions13.grokOAuth.awaitGrokDeviceToken(authorization, tokenEndpoint, exchangeFetch, {
22541
+ const result = await import_subscriptions14.grokOAuth.awaitGrokDeviceToken(authorization, tokenEndpoint, exchangeFetch, {
21753
22542
  onPending: () => process.stdout.write(".")
21754
22543
  });
21755
22544
  console.info("");
21756
22545
  return {
21757
22546
  ...result,
21758
- accountId: import_subscriptions13.grokOAuth.grokAccountIdFromAccessToken(result.accessToken)
22547
+ accountId: import_subscriptions14.grokOAuth.grokAccountIdFromAccessToken(result.accessToken)
21759
22548
  };
21760
22549
  }
21761
22550
  async function loginGrok(store, deps, exchangeFetch, label) {
@@ -21776,28 +22565,28 @@ async function loginGrok(store, deps, exchangeFetch, label) {
21776
22565
  }
21777
22566
  async function runCopilotDeviceFlow(exchangeFetch, openBrowserFn, enterpriseUrl) {
21778
22567
  if (enterpriseUrl) console.info(`Using GitHub Enterprise host: ${enterpriseUrl}`);
21779
- const authorization = await import_subscriptions13.copilotOAuth.requestCopilotDeviceAuthorization(exchangeFetch, enterpriseUrl);
22568
+ const authorization = await import_subscriptions14.copilotOAuth.requestCopilotDeviceAuthorization(exchangeFetch, enterpriseUrl);
21780
22569
  const url = authorization.verificationUri;
21781
22570
  console.info("Open this URL in your browser and approve the request:");
21782
22571
  console.info(` ${url}`);
21783
22572
  console.info(` Then enter this code: ${authorization.userCode}`);
21784
22573
  await openBrowserFn(url).catch(() => false);
21785
- const result = await import_subscriptions13.copilotOAuth.awaitCopilotDeviceToken(authorization, exchangeFetch, {
22574
+ const result = await import_subscriptions14.copilotOAuth.awaitCopilotDeviceToken(authorization, exchangeFetch, {
21786
22575
  onPending: () => process.stdout.write("."),
21787
22576
  ...enterpriseUrl ? { enterpriseUrl } : {}
21788
22577
  });
21789
22578
  console.info("");
21790
- const identity = await import_subscriptions13.copilotOAuth.fetchCopilotIdentity(result.accessToken, exchangeFetch, enterpriseUrl);
21791
- const apiEndpoint = await import_subscriptions13.copilotOAuth.discoverCopilotApiEndpoint(result.accessToken, exchangeFetch, enterpriseUrl);
22579
+ const identity = await import_subscriptions14.copilotOAuth.fetchCopilotIdentity(result.accessToken, exchangeFetch, enterpriseUrl);
22580
+ const apiEndpoint = await import_subscriptions14.copilotOAuth.discoverCopilotApiEndpoint(result.accessToken, exchangeFetch, enterpriseUrl);
21792
22581
  console.info("Enabling Copilot models (policy)...");
21793
- await import_subscriptions13.copilotOAuth.enableAllCopilotModels(
22582
+ await import_subscriptions14.copilotOAuth.enableAllCopilotModels(
21794
22583
  result.accessToken,
21795
22584
  { apiEndpoint, ...enterpriseUrl ? { enterpriseUrl } : {} },
21796
22585
  exchangeFetch
21797
22586
  );
21798
22587
  return {
21799
22588
  accessToken: result.accessToken,
21800
- expiresIn: Math.floor(import_subscriptions13.copilotOAuth.COPILOT_FAR_FUTURE_MS / 1e3),
22589
+ expiresIn: Math.floor(import_subscriptions14.copilotOAuth.COPILOT_FAR_FUTURE_MS / 1e3),
21801
22590
  ...identity,
21802
22591
  ...apiEndpoint ? { apiEndpoint } : {}
21803
22592
  };
@@ -21823,6 +22612,70 @@ async function loginCopilot(store, deps, exchangeFetch, label, enterpriseUrl) {
21823
22612
  logMasked("copilot", result.accessToken);
21824
22613
  return expiresAt;
21825
22614
  }
22615
+ async function loginAntigravity(store, deps, exchangeFetch, label) {
22616
+ const { authUrl, state } = import_subscriptions14.antigravityOAuth.generateAuthParams();
22617
+ await presentUrl(authUrl, deps);
22618
+ const code = await captureAntigravityCode(deps, state);
22619
+ const result = await import_subscriptions14.antigravityOAuth.exchangeCodeForTokens(code, exchangeFetch);
22620
+ const expiresAt = new Date(Date.now() + result.expiresIn * 1e3).toISOString();
22621
+ const email = await import_subscriptions14.antigravityOAuth.fetchUserEmail(result.accessToken, exchangeFetch);
22622
+ console.info("Resolving the Antigravity Cloud Code Assist project...");
22623
+ const projectId = await (0, import_GeminiCodeAssistProjectResolver7.getAntigravityProjectResolver)().resolveProject(result.accessToken);
22624
+ const block = {
22625
+ authMethod: "oauth",
22626
+ status: "authorized",
22627
+ accessToken: result.accessToken,
22628
+ refreshToken: result.refreshToken,
22629
+ expiresAt,
22630
+ ...email ? { email } : {},
22631
+ ...projectId ? { projectId } : {},
22632
+ lastRefreshedAt: (/* @__PURE__ */ new Date()).toISOString()
22633
+ };
22634
+ await store.appendProviderAccount("antigravity", block, label);
22635
+ logMasked("antigravity", result.accessToken);
22636
+ return expiresAt;
22637
+ }
22638
+ async function captureAntigravityCode(deps, state) {
22639
+ try {
22640
+ return await deps.awaitLoopback(state, void 0, void 0, {
22641
+ port: 51121,
22642
+ path: "/oauth-callback",
22643
+ label: "antigravity"
22644
+ });
22645
+ } catch (loopbackError) {
22646
+ const reason = loopbackError instanceof Error ? loopbackError.message : String(loopbackError);
22647
+ console.warn(`(loopback capture unavailable: ${reason})`);
22648
+ console.info(
22649
+ "Paste fallback: after authorizing, copy the failing redirect URL (or just its code parameter) here."
22650
+ );
22651
+ const pasted = (await deps.promptPaste("Paste the authorization code (or redirect URL): ")).trim();
22652
+ if (!pasted) throw new Error("login: no authorization code was pasted");
22653
+ const { code, state: pastedState } = parseAntigravityPaste(pasted);
22654
+ if (!code) throw new Error("login: the pasted value carried no authorization code");
22655
+ if (pastedState && pastedState !== state) {
22656
+ throw new Error("login: pasted state did not match (possible CSRF) \u2014 aborting");
22657
+ }
22658
+ return code;
22659
+ }
22660
+ }
22661
+ function parseAntigravityPaste(pasted) {
22662
+ if (pasted.includes("://")) {
22663
+ try {
22664
+ const url = new URL(pasted);
22665
+ const code = url.searchParams.get("code") ?? "";
22666
+ const state = url.searchParams.get("state") ?? void 0;
22667
+ return { code, ...state ? { state } : {} };
22668
+ } catch {
22669
+ }
22670
+ }
22671
+ if (/^[?]?code=/.test(pasted)) {
22672
+ const params = new URLSearchParams(pasted.replace(/^\?/, ""));
22673
+ const code = params.get("code") ?? "";
22674
+ const state = params.get("state") ?? void 0;
22675
+ return { code, ...state ? { state } : {} };
22676
+ }
22677
+ return { code: pasted };
22678
+ }
21826
22679
  function isLoginProvider(value) {
21827
22680
  return PROVIDERS2.includes(value);
21828
22681
  }
@@ -22244,7 +23097,11 @@ var TOKEN_FIELDS2 = {
22244
23097
  claude: ["accessToken", "refreshToken"],
22245
23098
  codex: ["accessToken", "refreshToken", "idToken"],
22246
23099
  gemini: ["accessToken", "refreshToken"],
22247
- opencodego: ["apiKey"]
23100
+ opencodego: ["apiKey"],
23101
+ kimi: ["accessToken", "refreshToken"],
23102
+ grok: ["accessToken", "refreshToken"],
23103
+ copilot: ["accessToken", "refreshToken"],
23104
+ antigravity: ["accessToken", "refreshToken"]
22248
23105
  };
22249
23106
  function walkTokens(raw, fn) {
22250
23107
  const next = { ...raw };
@@ -22528,7 +23385,7 @@ async function main() {
22528
23385
  process.exitCode = 1;
22529
23386
  }
22530
23387
  }
22531
- main().catch((err8) => {
22532
- console.error(err8 instanceof Error ? err8.message : String(err8));
23388
+ main().catch((err9) => {
23389
+ console.error(err9 instanceof Error ? err9.message : String(err9));
22533
23390
  process.exitCode = 1;
22534
23391
  });