jeo-code 0.12.4 → 0.12.5

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/CHANGELOG.md CHANGED
@@ -9,6 +9,19 @@ The README mirrors the latest 5 entries — regenerate with `bun run changelog:s
9
9
 
10
10
  ## [Unreleased]
11
11
 
12
+ ## [0.12.5] - 2026-10-17
13
+ _Antigravity and Kimi provider support in interactive setup, Kimi live model cache rehydration, immediate discovery caching on provider probing._
14
+
15
+ ### Added
16
+ - **Interactive Setup Provider Options** (`src/commands/setup.ts`, `src/commands/setup-helpers.ts`) — added `antigravity` (Google Cloud Code Assist OAuth) and `kimi` (Moonshot API key / Kimi Code OAuth) to interactive setup provider selection, enabling browser OAuth, bearer token paste, or API key configuration with default models (`antigravity/gemini-3-flash`, `kimi-k2.5`). Updated `buildEnabledProviders` to recognize configured `kimi` credentials.
17
+ - **Kimi Live Model Cache Rehydration** (`src/ai/model-cache.ts`) — cache hits for Kimi OAuth (`provider === 'kimi' && source === 'oauth'`) now rehydrate `recordLiveKimiCodeModels(entry.models)` alongside OpenAI Codex models.
18
+ - **Immediate Model Cache on Provider Probe** (`src/commands/provider.ts`) — successful `jeo provider test <id>` and `jeo provider add` probing now immediately writes discovered custom/compatible models to the disk cache (`writeModelCache([result])`).
19
+
20
+ ### Fixed
21
+ - **Model Cache Key Scoping** (`src/ai/model-cache.ts`) — fixed `keyOf` helper scoping and included `kimi` in source distinction so OAuth and API key catalogs do not clobber each other.
22
+ - **OAuth Token Preservation in Setup** (`src/commands/setup.ts`) — fixed `delete next.oauth` condition to check `Object.keys(next.oauth).length === 0` so non-Anthropic/OpenAI/Gemini OAuth credentials (such as `antigravity` or `kimi`) are not inadvertently dropped on save.
23
+ - **Auth Import Model Reporting** (`src/commands/auth.ts`) — added `antigravity` reporting to `reportLiveModels` following Gemini OAuth import.
24
+
12
25
  ## [0.12.4] - 2026-10-17
13
26
  _Refresh Antigravity provider (`antigravity/*`) account catalogs with `antigravity/hub/2.23.1` so entitled Gemini 4 Argon and Gemini 3.8 Flash tiers appear directly in `/model provider antigravity`._
14
27
 
package/README.ja.md CHANGED
@@ -416,10 +416,10 @@ CI は `.github/workflows/npm-publish.yml` で公開します — GitHub リリ
416
416
 
417
417
  <!-- CHANGELOG:START (auto-generated from CHANGELOG.md — run `bun run changelog:sync`) -->
418
418
  - **[Unreleased]**
419
+ - **[0.12.5]** (2026-10-17) — Antigravity and Kimi provider support in interactive setup, Kimi live model cache rehydration, immediate discovery caching on provider probing.
419
420
  - **[0.12.4]** (2026-10-17) — Refresh Antigravity provider (`antigravity/*`) account catalogs with `antigravity/hub/2.23.1` so entitled Gemini 4 Argon and Gemini 3.8 Flash tiers appear directly in `/model provider antigravity`.
420
421
  - **[0.12.3]** (2026-10-17) — Anthropic static model catalog trimmed to claude-5.x with live API discovery, and `/route off` strictly fixes the active model with no failover.
421
422
  - **[0.12.2]** (2026-10-16) — Select Argon through the official agy full agent, with its own live catalog and session, separately from jeo's Cloud Code Assist backend.
422
- - **[0.12.1]** (2026-10-16) — Logged-in OpenAI subscription models were invisible on proxy-configured machines.
423
423
 
424
424
  See [CHANGELOG.md](CHANGELOG.md) for the full history.
425
425
  <!-- CHANGELOG:END -->
package/README.ko.md CHANGED
@@ -417,10 +417,10 @@ CI는 `.github/workflows/npm-publish.yml`로 배포합니다 — GitHub 릴리
417
417
 
418
418
  <!-- CHANGELOG:START (auto-generated from CHANGELOG.md — run `bun run changelog:sync`) -->
419
419
  - **[Unreleased]**
420
+ - **[0.12.5]** (2026-10-17) — Antigravity and Kimi provider support in interactive setup, Kimi live model cache rehydration, immediate discovery caching on provider probing.
420
421
  - **[0.12.4]** (2026-10-17) — Refresh Antigravity provider (`antigravity/*`) account catalogs with `antigravity/hub/2.23.1` so entitled Gemini 4 Argon and Gemini 3.8 Flash tiers appear directly in `/model provider antigravity`.
421
422
  - **[0.12.3]** (2026-10-17) — Anthropic static model catalog trimmed to claude-5.x with live API discovery, and `/route off` strictly fixes the active model with no failover.
422
423
  - **[0.12.2]** (2026-10-16) — Select Argon through the official agy full agent, with its own live catalog and session, separately from jeo's Cloud Code Assist backend.
423
- - **[0.12.1]** (2026-10-16) — Logged-in OpenAI subscription models were invisible on proxy-configured machines.
424
424
 
425
425
  See [CHANGELOG.md](CHANGELOG.md) for the full history.
426
426
  <!-- CHANGELOG:END -->
package/README.md CHANGED
@@ -409,10 +409,10 @@ Huge thanks to [gajae-code](https://github.com/Yeachan-Heo/gajae-code) for the i
409
409
 
410
410
  <!-- CHANGELOG:START (auto-generated from CHANGELOG.md — run `bun run changelog:sync`) -->
411
411
  - **[Unreleased]**
412
+ - **[0.12.5]** (2026-10-17) — Antigravity and Kimi provider support in interactive setup, Kimi live model cache rehydration, immediate discovery caching on provider probing.
412
413
  - **[0.12.4]** (2026-10-17) — Refresh Antigravity provider (`antigravity/*`) account catalogs with `antigravity/hub/2.23.1` so entitled Gemini 4 Argon and Gemini 3.8 Flash tiers appear directly in `/model provider antigravity`.
413
414
  - **[0.12.3]** (2026-10-17) — Anthropic static model catalog trimmed to claude-5.x with live API discovery, and `/route off` strictly fixes the active model with no failover.
414
415
  - **[0.12.2]** (2026-10-16) — Select Argon through the official agy full agent, with its own live catalog and session, separately from jeo's Cloud Code Assist backend.
415
- - **[0.12.1]** (2026-10-16) — Logged-in OpenAI subscription models were invisible on proxy-configured machines.
416
416
 
417
417
  See [CHANGELOG.md](CHANGELOG.md) for the full history.
418
418
  <!-- CHANGELOG:END -->
package/README.zh.md CHANGED
@@ -414,10 +414,10 @@ CI 通过 `.github/workflows/npm-publish.yml` 发布 — GitHub 发布 release
414
414
 
415
415
  <!-- CHANGELOG:START (auto-generated from CHANGELOG.md — run `bun run changelog:sync`) -->
416
416
  - **[Unreleased]**
417
+ - **[0.12.5]** (2026-10-17) — Antigravity and Kimi provider support in interactive setup, Kimi live model cache rehydration, immediate discovery caching on provider probing.
417
418
  - **[0.12.4]** (2026-10-17) — Refresh Antigravity provider (`antigravity/*`) account catalogs with `antigravity/hub/2.23.1` so entitled Gemini 4 Argon and Gemini 3.8 Flash tiers appear directly in `/model provider antigravity`.
418
419
  - **[0.12.3]** (2026-10-17) — Anthropic static model catalog trimmed to claude-5.x with live API discovery, and `/route off` strictly fixes the active model with no failover.
419
420
  - **[0.12.2]** (2026-10-16) — Select Argon through the official agy full agent, with its own live catalog and session, separately from jeo's Cloud Code Assist backend.
420
- - **[0.12.1]** (2026-10-16) — Logged-in OpenAI subscription models were invisible on proxy-configured machines.
421
421
 
422
422
  See [CHANGELOG.md](CHANGELOG.md) for the full history.
423
423
  <!-- CHANGELOG:END -->
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jeo-code",
3
- "version": "0.12.4",
3
+ "version": "0.12.5",
4
4
  "description": "Clean, highly optimized AI coding agent using spec-first loop",
5
5
  "type": "module",
6
6
  "main": "src/cli.ts",
@@ -19,7 +19,7 @@ import { mkdir, readFile, writeFile } from "node:fs/promises";
19
19
  import * as os from "node:os";
20
20
  import * as path from "node:path";
21
21
  import { jeoEnv } from "../util/env";
22
- import { recordLiveCodexModels, recordLiveProviderModels, setAntigravityAccountScope, setOpenAIOauthAccountScope } from "./model-catalog";
22
+ import { recordLiveCodexModels, recordLiveKimiCodeModels, recordLiveProviderModels, setAntigravityAccountScope, setOpenAIOauthAccountScope } from "./model-catalog";
23
23
  import type { Credential } from "../auth";
24
24
  import { getStoredOAuth, snapshotProvider } from "../auth/storage";
25
25
  import { getAntigravityUserAgent } from "./providers/antigravity";
@@ -158,7 +158,7 @@ export function mergeCacheEntries(
158
158
  const isScopedOAuth = (provider: ProviderName, source: ModelCacheSource): boolean =>
159
159
  (provider === "openai" || provider === "antigravity") && source === "oauth";
160
160
  const keyOf = (provider: ProviderName, baseUrl?: string, accountId?: string, source?: ModelCacheSource) =>
161
- `${provider}\u0000${baseUrl?.replace(/\/+$/, "") ?? ""}\u0000${isScopedOAuth(provider, source ?? "none") ? accountId ?? "" : ""}\u0000${provider === "openai" || provider === "antigravity" ? source ?? "none" : ""}`;
161
+ `${provider}\u0000${baseUrl?.replace(/\/+$/, "") ?? ""}\u0000${isScopedOAuth(provider, source ?? "none") ? accountId ?? "" : ""}\u0000${provider === "openai" || provider === "antigravity" || provider === "kimi" ? source ?? "none" : ""}`;
162
162
  for (const entry of previous) {
163
163
  const scoped = isScopedOAuth(entry.provider, entry.source);
164
164
  if (entry.provider === "agy") continue;
@@ -240,6 +240,9 @@ export function applyCachedModels(cache: ModelCacheFile | null, openAIOauthAccou
240
240
  if (isOpenAIOAuth && entry.accountId && !entry.baseUrl) {
241
241
  recordLiveCodexModels(entry.models, entry.accountId);
242
242
  }
243
+ if (entry.provider === "kimi" && entry.source === "oauth") {
244
+ recordLiveKimiCodeModels(entry.models);
245
+ }
243
246
  applied += entry.models.length;
244
247
  }
245
248
  return applied;
@@ -501,6 +501,30 @@ export const KIMI_CODE_MODELS: readonly string[] = [
501
501
  "kimi-k2",
502
502
  ];
503
503
 
504
+ const liveKimiCodeModels = new Set<string>();
505
+
506
+ /** Record ids confirmed by the Kimi Code OAuth `/v1/models` endpoint so brand-new
507
+ * subscription models work immediately without waiting for a static catalog release. */
508
+ export function recordLiveKimiCodeModels(ids: readonly string[]): void {
509
+ for (const id of ids) {
510
+ const trimmed = id.trim();
511
+ if (!trimmed) continue;
512
+ const wire = trimmed.startsWith("kimi/") ? trimmed.slice(5) : trimmed;
513
+ if (wire) liveKimiCodeModels.add(wire);
514
+ }
515
+ }
516
+
517
+ /** Whether `model` is served by the Kimi Code OAuth subscription endpoint. */
518
+ export function isKimiCodeModel(model: string): boolean {
519
+ const wire = model.startsWith("kimi/") ? model.slice(5) : model;
520
+ return KIMI_CODE_MODELS.includes(wire) || liveKimiCodeModels.has(wire);
521
+ }
522
+
523
+ /** Test-only reset for live Kimi Code observations. */
524
+ export function resetLiveKimiCodeModels(): void {
525
+ liveKimiCodeModels.clear();
526
+ }
527
+
504
528
  /** Recency compare for `releaseDate` ("YYYY-MM"): `>0` when `a` is newer; a
505
529
  * missing date sorts oldest, so an unconfirmed date never outranks a
506
530
  * verified-newer model. */
@@ -639,6 +663,20 @@ export function inferCatalogMetadata(modelId: string): CatalogModel | undefined
639
663
  company: "xAI",
640
664
  };
641
665
  }
666
+ // Kimi / Moonshot
667
+ const kimi = id.match(/^kimi-(k\d+|latest|for-coding)/);
668
+ if (kimi) {
669
+ return {
670
+ canonical: raw,
671
+ provider: "kimi",
672
+ providerModel: id,
673
+ contextTokens: 256_000,
674
+ maxOutputTokens: 16_384,
675
+ thinking: FULL,
676
+ images: false,
677
+ company: "Moonshot",
678
+ };
679
+ }
642
680
 
643
681
  return undefined;
644
682
  }
@@ -16,6 +16,7 @@ import {
16
16
  catalogByProvider,
17
17
  KIMI_CODE_MODELS,
18
18
  recordLiveCodexModels,
19
+ recordLiveKimiCodeModels,
19
20
  recordLiveProviderModels,
20
21
  setOpenAIOauthAccountScope,
21
22
  setAntigravityAccountScope,
@@ -26,7 +27,7 @@ import { openaiCompatDef } from "./providers/openai-compatible-catalog";
26
27
  import { antigravityAccountScope } from "./model-cache";
27
28
  import { getAntigravityUserAgent, resolveAntigravityProjectId } from "./providers/antigravity";
28
29
  import { discoverGoogleProjectId, ANTIGRAVITY_DISCOVERY_METADATA } from "../auth/flows/google-project";
29
-
30
+ import { getKimiCommonHeaders } from "../auth/flows/kimi";
30
31
  export interface ProviderModelsResult {
31
32
  provider: ProviderName;
32
33
  /** Discovered model ids (provider-qualified where the router expects it). */
@@ -185,6 +186,15 @@ export function discoveryRequest(
185
186
  return { url: "https://api.x.ai/v1/models", headers: token ? { Authorization: `Bearer ${token}` } : {} };
186
187
  }
187
188
  case "kimi": {
189
+ if (cred?.kind === "oauth") {
190
+ return {
191
+ url: "https://api.kimi.com/coding/v1/models",
192
+ headers: {
193
+ ...getKimiCommonHeaders(),
194
+ Authorization: `Bearer ${cred.token}`,
195
+ },
196
+ };
197
+ }
188
198
  const token = cred?.kind === "api_key" ? cred.token : "";
189
199
  return { url: "https://api.moonshot.ai/v1/models", headers: token ? { Authorization: `Bearer ${token}` } : {} };
190
200
  }
@@ -585,6 +595,7 @@ export async function listProviderModels(
585
595
  ...(source === "oauth" && scope.accountId ? { accountId: scope.accountId } : {}),
586
596
  });
587
597
  if (provider === "openai" && source === "oauth" && !baseUrl) recordLiveCodexModels(allModels, oauthAccountId);
598
+ if (provider === "kimi" && source === "oauth") recordLiveKimiCodeModels(allModels);
588
599
  return {
589
600
  provider,
590
601
  models,
@@ -659,6 +670,12 @@ export async function discoverModels(
659
670
  return [primary, await listProviderModels(p, { ...discoveryOpts, baseUrl: undefined, preferOAuth: true, codexCatalog: true })];
660
671
  }
661
672
  }
673
+ if (p === "kimi" && primary.source !== "oauth") {
674
+ const credential = await resolveCredential("kimi");
675
+ if (credential.kind === "oauth") {
676
+ return [primary, await listProviderModels(p, { ...discoveryOpts, preferOAuth: true })];
677
+ }
678
+ }
662
679
  return [primary];
663
680
  }),
664
681
  );
@@ -6,7 +6,7 @@ import "./register-providers"; // side-effect: registers built-in adapters into
6
6
  import type { CallOptions, Message, ProviderAdapter, ProviderName } from "./types";
7
7
  import { expandAlias, resolveModelId, effectiveAliasesFor, BUILTIN_ALIASES } from "./model-registry";
8
8
  import { findCatalogEntry, type ModelCatalogEntry } from "./model-catalog-compat";
9
- import { toProviderModel, CODEX_MODELS, KIMI_CODE_MODELS, findCatalogModel, isCodexModel, findLiveCatalogModel } from "./model-catalog";
9
+ import { toProviderModel, CODEX_MODELS, KIMI_CODE_MODELS, findCatalogModel, isCodexModel, isKimiCodeModel, findLiveCatalogModel } from "./model-catalog";
10
10
  import { xaiCredential } from "./providers/xai";
11
11
  import { allCompatNames, isOpenAICompatProvider } from "./providers/openai-compatible-catalog";
12
12
  import { withRetry, defaultRetryable, withConnectionContext, isConnectionError, ConnectionContextError, type RetryOptions } from "../util/retry";
@@ -329,8 +329,7 @@ export function oauthServesModel(provider: AuthProvider, model: string): boolean
329
329
  return isCodexModel(model);
330
330
  }
331
331
  if (provider === "kimi") {
332
- const wire = model.startsWith("kimi/") ? model.slice(5) : model;
333
- return KIMI_CODE_MODELS.includes(wire);
332
+ return isKimiCodeModel(model);
334
333
  }
335
334
  if (isOAuthProvider(provider) && OAUTH_FLOW_REGISTRY[provider].verifiedEndToEnd === false) return false;
336
335
  return true;
@@ -152,7 +152,7 @@ async function runAuthLogin(rest: string[]): Promise<void> {
152
152
  * already succeeded and is not rolled back by this check. Prints only model
153
153
  * ids/count — no tokens/secrets.
154
154
  */
155
- const LIVE_MODEL_REPORT_PROVIDERS = new Set<AuthProvider>(["openai", "anthropic", "antigravity"]);
155
+ const LIVE_MODEL_REPORT_PROVIDERS = new Set<AuthProvider>(["openai", "anthropic", "antigravity", "kimi"]);
156
156
 
157
157
  async function reportLiveModels(provider: AuthProvider): Promise<void> {
158
158
  try {
@@ -249,6 +249,7 @@ async function runAuthImport(rest: string[]): Promise<void> {
249
249
  }
250
250
  const expiryMsg = expires ? fmtExpiry(expires) : "";
251
251
  console.log(`Expiry status:${expiryMsg || " valid"}`);
252
+ await reportLiveModels("antigravity");
252
253
  } catch (err: any) {
253
254
  console.log(`[FAILED] ${err.message}`);
254
255
  process.exitCode = 1;
@@ -335,8 +336,16 @@ async function selectProvider(
335
336
  console.log(" 1) anthropic (real PKCE OAuth, verified end-to-end)");
336
337
  console.log(" 2) openai (real PKCE OAuth, Codex backend)");
337
338
  console.log(" 3) gemini (real Google OAuth, Cloud Code Assist)");
338
- const ans = (await rl.question("Choose [1-3]: ")).trim();
339
- const map: Record<string, AuthProvider> = { "1": "anthropic", "2": "openai", "3": "gemini" };
339
+ console.log(" 4) antigravity (Google Cloud Code Assist OAuth)");
340
+ console.log(" 5) kimi (Kimi Code OAuth device authorization)");
341
+ const ans = (await rl.question("Choose [1-5]: ")).trim();
342
+ const map: Record<string, AuthProvider> = {
343
+ "1": "anthropic",
344
+ "2": "openai",
345
+ "3": "gemini",
346
+ "4": "antigravity",
347
+ "5": "kimi",
348
+ };
340
349
  const p = map[ans];
341
350
  if (!p) {
342
351
  console.log("Invalid choice.");
@@ -31,6 +31,7 @@ import {
31
31
  normalizeProviderId,
32
32
  } from "../ai/providers/custom-providers";
33
33
  import { listProviderModels } from "../ai/model-discovery";
34
+ import { writeModelCache } from "../ai/model-cache";
34
35
  import { describeProvider } from "../ai/provider-status";
35
36
 
36
37
  const USAGE = [
@@ -186,6 +187,7 @@ async function probe(id: string, opts: { failOnError: boolean }): Promise<void>
186
187
  if (shown.length) console.log(` ${shown.join(", ")}${result.models.length > shown.length ? ", …" : ""}`);
187
188
  const first = result.models[0];
188
189
  console.log(` status : OK — use it with 'jeo launch --model ${first ? qualify(first) : `${id}/<model>`}'`);
190
+ await writeModelCache([result]);
189
191
  return;
190
192
  }
191
193
 
@@ -76,6 +76,7 @@ export function buildEnabledProviders(config: Config): string[] {
76
76
  if (cfg.providers?.anthropic || cfg.oauth?.anthropic) enabled.push("anthropic");
77
77
  if (cfg.providers?.openai || cfg.oauth?.openai) enabled.push("openai");
78
78
  if (cfg.providers?.gemini || cfg.oauth?.gemini || cfg.providers?.antigravity || cfg.oauth?.antigravity) enabled.push("google-oauth");
79
+ if (cfg.providers?.kimi || cfg.oauth?.kimi) enabled.push("kimi");
79
80
  if (cfg.ollamaBaseUrl) enabled.push(`ollama(${cfg.ollamaBaseUrl})`);
80
81
  if (cfg.openaiBaseUrl) enabled.push(`openai-compatible(${cfg.openaiBaseUrl})`);
81
82
  return enabled;
@@ -24,12 +24,14 @@ function reportModelChoice(r: { warning?: string; suggestions: string[] }): void
24
24
  if (r.suggestions.length) console.log(` Did you mean: ${r.suggestions.join(", ")}?`);
25
25
  }
26
26
 
27
- type ProviderChoice = "anthropic" | "openai" | "gemini" | "ollama" | "lmstudio" | "openai-compatible";
27
+ type ProviderChoice = "anthropic" | "openai" | "gemini" | "antigravity" | "kimi" | "ollama" | "lmstudio" | "openai-compatible";
28
28
 
29
29
  const DEFAULT_MODELS: Record<ProviderChoice, string> = {
30
30
  anthropic: "claude-sonnet-4-6",
31
31
  openai: "gpt-4o",
32
32
  gemini: "gemini-2.0-flash",
33
+ antigravity: "antigravity/gemini-3-flash",
34
+ kimi: "kimi-k2.5",
33
35
  ollama: "ollama/llama3.1:8b",
34
36
  lmstudio: "openai/local-model",
35
37
  "openai-compatible": "openai/local-model",
@@ -87,16 +89,19 @@ export async function runSetupCommand(): Promise<void> {
87
89
  console.log(" 1) anthropic — Claude (API key or OAuth bearer)");
88
90
  console.log(" 2) openai — GPT (API key or OAuth bearer)");
89
91
  console.log(" 3) gemini — Google AI Studio (API key or OAuth bearer)");
90
- console.log(" 4) ollama — local Ollama (no auth)");
91
- console.log(" 5) lmstudio — local LM Studio (OpenAI-compatible)");
92
- console.log(" 6) openai-compatible — custom OpenAI-compatible (vLLM, llama-cpp-server, ...)");
93
- console.log(" 7) skip — keep existing values, just change defaults\n");
94
-
95
- const sel = (await rl.question("Configure which provider? [1-7]: ")).trim();
92
+ console.log(" 4) antigravity — Google Cloud Code Assist (OAuth)");
93
+ console.log(" 5) kimi — Kimi / Moonshot (API key or Kimi Code OAuth)");
94
+ console.log(" 6) ollama — local Ollama (no auth)");
95
+ console.log(" 7) lmstudio — local LM Studio (OpenAI-compatible)");
96
+ console.log(" 8) openai-compatible — custom OpenAI-compatible (vLLM, llama-cpp-server, ...)");
97
+ console.log(" 9) skip — keep existing values, just change defaults\n");
98
+
99
+ const sel = (await rl.question("Configure which provider? [1-9]: ")).trim();
96
100
  const map: Record<string, ProviderChoice | "skip"> = {
97
101
  "1": "anthropic", "2": "openai", "3": "gemini",
98
- "4": "ollama", "5": "lmstudio", "6": "openai-compatible",
99
- "7": "skip",
102
+ "4": "antigravity", "5": "kimi",
103
+ "6": "ollama", "7": "lmstudio", "8": "openai-compatible",
104
+ "9": "skip",
100
105
  };
101
106
  const choice = map[sel] ?? "skip";
102
107
 
@@ -108,7 +113,7 @@ export async function runSetupCommand(): Promise<void> {
108
113
  next.providers = next.providers || {};
109
114
  next.oauth = next.oauth || {};
110
115
 
111
- if (choice === "anthropic" || choice === "openai" || choice === "gemini") {
116
+ if (choice === "anthropic" || choice === "openai" || choice === "gemini" || choice === "antigravity" || choice === "kimi") {
112
117
  const authMode = (
113
118
  await rl.question("Auth mode: (b)rowser OAuth login, (t)oken paste, or api (k)ey? [b]: ")
114
119
  ).trim().toLowerCase();
@@ -223,7 +228,7 @@ export async function runSetupCommand(): Promise<void> {
223
228
  rl.close();
224
229
 
225
230
  // Drop empty oauth/providers to keep config tidy.
226
- if (next.oauth && !next.oauth.anthropic && !next.oauth.openai && !next.oauth.gemini) delete next.oauth;
231
+ if (next.oauth && Object.keys(next.oauth).length === 0) delete next.oauth;
227
232
 
228
233
  await saveGlobalConfig(next);
229
234
  console.log("\n[SUCCESS] Configuration saved to ~/.jeo/config.json");