@austinthesing/magic-shell 0.2.18 → 0.2.20

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (5) hide show
  1. package/README.md +14 -9
  2. package/dist/cli.js +640 -183
  3. package/dist/index.js +1119 -424
  4. package/dist/tui.js +640 -183
  5. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -2116,15 +2116,6 @@ import { cwd as getCwd } from "process";
2116
2116
 
2117
2117
  // src/lib/types.ts
2118
2118
  var OPENROUTER_MODELS = [
2119
- {
2120
- id: "minimax/minimax-m2.5:free",
2121
- name: "MiniMax M2.5 Free",
2122
- description: "Free MiniMax model for trying out open-source generation",
2123
- category: "smart",
2124
- provider: "openrouter",
2125
- contextLength: 196608,
2126
- free: true
2127
- },
2128
2119
  {
2129
2120
  id: "xiaomi/mimo-v2.5",
2130
2121
  name: "MiMo V2.5",
@@ -2157,6 +2148,38 @@ var OPENROUTER_MODELS = [
2157
2148
  provider: "openrouter",
2158
2149
  contextLength: 202752
2159
2150
  },
2151
+ {
2152
+ id: "openai/gpt-latest",
2153
+ name: "OpenAI GPT Latest",
2154
+ description: "OpenRouter alias that redirects to the latest OpenAI GPT model",
2155
+ category: "smart",
2156
+ provider: "openrouter",
2157
+ contextLength: 1050000
2158
+ },
2159
+ {
2160
+ id: "openai/gpt-5.5",
2161
+ name: "GPT 5.5",
2162
+ description: "OpenAI's latest flagship GPT model",
2163
+ category: "smart",
2164
+ provider: "openrouter",
2165
+ contextLength: 1050000
2166
+ },
2167
+ {
2168
+ id: "anthropic/claude-sonnet-latest",
2169
+ name: "Claude Sonnet Latest",
2170
+ description: "OpenRouter alias that redirects to the latest Claude Sonnet model",
2171
+ category: "smart",
2172
+ provider: "openrouter",
2173
+ contextLength: 1e6
2174
+ },
2175
+ {
2176
+ id: "anthropic/claude-sonnet-4.6",
2177
+ name: "Claude Sonnet 4.6",
2178
+ description: "Anthropic's latest Sonnet model",
2179
+ category: "smart",
2180
+ provider: "openrouter",
2181
+ contextLength: 1e6
2182
+ },
2160
2183
  {
2161
2184
  id: "moonshotai/kimi-k2.6",
2162
2185
  name: "Kimi K2.6",
@@ -2189,6 +2212,30 @@ var OPENROUTER_MODELS = [
2189
2212
  provider: "openrouter",
2190
2213
  contextLength: 196608
2191
2214
  },
2215
+ {
2216
+ id: "anthropic/claude-opus-latest",
2217
+ name: "Claude Opus Latest",
2218
+ description: "OpenRouter alias that redirects to the latest Claude Opus model",
2219
+ category: "reasoning",
2220
+ provider: "openrouter",
2221
+ contextLength: 1e6
2222
+ },
2223
+ {
2224
+ id: "anthropic/claude-opus-4.7",
2225
+ name: "Claude Opus 4.7",
2226
+ description: "Anthropic's latest Opus model",
2227
+ category: "reasoning",
2228
+ provider: "openrouter",
2229
+ contextLength: 1e6
2230
+ },
2231
+ {
2232
+ id: "openai/gpt-5.5-pro",
2233
+ name: "GPT 5.5 Pro",
2234
+ description: "OpenAI's latest high-capability reasoning model",
2235
+ category: "reasoning",
2236
+ provider: "openrouter",
2237
+ contextLength: 1050000
2238
+ },
2192
2239
  {
2193
2240
  id: "moonshotai/kimi-k2-thinking",
2194
2241
  name: "Kimi K2 Thinking",
@@ -2198,58 +2245,179 @@ var OPENROUTER_MODELS = [
2198
2245
  contextLength: 262144
2199
2246
  }
2200
2247
  ];
2248
+ var VERCEL_AI_GATEWAY_MODELS = [
2249
+ {
2250
+ id: "openai/gpt-latest",
2251
+ name: "OpenAI GPT Latest",
2252
+ description: "Vercel AI Gateway alias that redirects to the latest OpenAI GPT model",
2253
+ category: "smart",
2254
+ provider: "vercel-ai-gateway",
2255
+ contextLength: 1050000
2256
+ },
2257
+ {
2258
+ id: "openai/gpt-5.5",
2259
+ name: "GPT 5.5",
2260
+ description: "OpenAI's latest flagship GPT model",
2261
+ category: "smart",
2262
+ provider: "vercel-ai-gateway",
2263
+ contextLength: 1050000
2264
+ },
2265
+ {
2266
+ id: "anthropic/claude-sonnet-4.6",
2267
+ name: "Claude Sonnet 4.6",
2268
+ description: "Anthropic's latest Sonnet model",
2269
+ category: "smart",
2270
+ provider: "vercel-ai-gateway",
2271
+ contextLength: 1e6
2272
+ },
2273
+ {
2274
+ id: "anthropic/claude-opus-4.7",
2275
+ name: "Claude Opus 4.7",
2276
+ description: "Anthropic's latest Opus model",
2277
+ category: "reasoning",
2278
+ provider: "vercel-ai-gateway",
2279
+ contextLength: 1e6
2280
+ },
2281
+ {
2282
+ id: "openai/gpt-5.5-pro",
2283
+ name: "GPT 5.5 Pro",
2284
+ description: "OpenAI's latest high-capability reasoning model",
2285
+ category: "reasoning",
2286
+ provider: "vercel-ai-gateway",
2287
+ contextLength: 1050000
2288
+ }
2289
+ ];
2290
+ var CLOUDFLARE_AI_GATEWAY_MODELS = [
2291
+ {
2292
+ id: "openai/gpt-5.5",
2293
+ name: "GPT 5.5",
2294
+ description: "OpenAI's latest flagship GPT model through Cloudflare AI Gateway",
2295
+ category: "smart",
2296
+ provider: "cloudflare-ai-gateway",
2297
+ contextLength: 1050000
2298
+ },
2299
+ {
2300
+ id: "anthropic/claude-sonnet-4-6",
2301
+ name: "Claude Sonnet 4.6",
2302
+ description: "Anthropic's latest Sonnet model through Cloudflare AI Gateway",
2303
+ category: "smart",
2304
+ provider: "cloudflare-ai-gateway",
2305
+ contextLength: 1e6
2306
+ },
2307
+ {
2308
+ id: "anthropic/claude-opus-4-7",
2309
+ name: "Claude Opus 4.7",
2310
+ description: "Anthropic's latest Opus model through Cloudflare AI Gateway",
2311
+ category: "reasoning",
2312
+ provider: "cloudflare-ai-gateway",
2313
+ contextLength: 1e6
2314
+ },
2315
+ {
2316
+ id: "workers-ai/@cf/meta/llama-3.3-70b-instruct-fp8-fast",
2317
+ name: "Workers AI Llama 3.3 70B Fast",
2318
+ description: "Cloudflare Workers AI fast Llama model routed through AI Gateway",
2319
+ category: "smart",
2320
+ provider: "cloudflare-ai-gateway",
2321
+ contextLength: 24000
2322
+ }
2323
+ ];
2324
+ var WORKERS_AI_MODELS = [
2325
+ {
2326
+ id: "@cf/meta/llama-3.3-70b-instruct-fp8-fast",
2327
+ name: "Llama 3.3 70B Fast",
2328
+ description: "Cloudflare Workers AI fast Llama instruct model",
2329
+ category: "smart",
2330
+ provider: "workers-ai",
2331
+ contextLength: 24000
2332
+ },
2333
+ {
2334
+ id: "@cf/meta/llama-3.1-8b-instruct",
2335
+ name: "Llama 3.1 8B Instruct",
2336
+ description: "Cloudflare Workers AI lightweight Llama instruct model",
2337
+ category: "fast",
2338
+ provider: "workers-ai",
2339
+ contextLength: 8000
2340
+ },
2341
+ {
2342
+ id: "@cf/openai/gpt-oss-120b",
2343
+ name: "GPT OSS 120B",
2344
+ description: "OpenAI open-weight model hosted by Cloudflare Workers AI",
2345
+ category: "reasoning",
2346
+ provider: "workers-ai",
2347
+ contextLength: 32000
2348
+ }
2349
+ ];
2201
2350
  var OPENCODE_ZEN_MODELS = [
2202
2351
  {
2203
2352
  id: "minimax-m2.5-free",
2204
2353
  name: "MiniMax M2.5 Free",
2205
2354
  description: "MiniMax's free model (limited time)",
2206
- category: "fast",
2355
+ category: "smart",
2207
2356
  provider: "opencode-zen",
2208
2357
  contextLength: 196608,
2209
2358
  free: true
2210
2359
  },
2211
2360
  {
2212
- id: "kimi-k2.6-free",
2213
- name: "Kimi K2.6 Free",
2214
- description: "Moonshot's latest model (free, limited time)",
2361
+ id: "ling-2.6-flash-free",
2362
+ name: "Ling 2.6 Flash Free",
2363
+ description: "Ling's free flash model (limited time)",
2364
+ category: "fast",
2365
+ provider: "opencode-zen",
2366
+ contextLength: 131072,
2367
+ free: true
2368
+ },
2369
+ {
2370
+ id: "hy3-preview-free",
2371
+ name: "Hy3 Preview Free",
2372
+ description: "Hy3 preview model (free, limited time)",
2215
2373
  category: "smart",
2216
2374
  provider: "opencode-zen",
2217
- contextLength: 262144,
2375
+ contextLength: 131072,
2218
2376
  free: true
2219
2377
  },
2220
2378
  {
2221
- id: "deepseek-v4-flash-free",
2222
- name: "DeepSeek V4 Flash Free",
2223
- description: "DeepSeek's latest fast model (free, limited time)",
2224
- category: "fast",
2379
+ id: "nemotron-3-super-free",
2380
+ name: "Nemotron 3 Super Free",
2381
+ description: "NVIDIA Nemotron free trial model",
2382
+ category: "smart",
2225
2383
  provider: "opencode-zen",
2226
- contextLength: 1048576,
2384
+ contextLength: 131072,
2227
2385
  free: true
2228
2386
  },
2229
2387
  {
2230
- id: "mimo-v2.5",
2231
- name: "MiMo V2.5",
2232
- description: "Xiaomi's latest long-context MiMo model",
2233
- category: "fast",
2388
+ id: "trinity-large-preview-free",
2389
+ name: "Trinity Large Preview Free",
2390
+ description: "Trinity large preview model (free, limited time)",
2391
+ category: "smart",
2234
2392
  provider: "opencode-zen",
2235
- contextLength: 1048576
2393
+ contextLength: 131072,
2394
+ free: true
2395
+ },
2396
+ {
2397
+ id: "big-pickle",
2398
+ name: "Big Pickle",
2399
+ description: "OpenCode stealth model (free, limited time)",
2400
+ category: "smart",
2401
+ provider: "opencode-zen",
2402
+ contextLength: 131072,
2403
+ free: true
2236
2404
  },
2237
2405
  {
2238
2406
  id: "gpt-5-nano",
2239
2407
  name: "GPT 5 Nano",
2240
- description: "OpenAI's fastest GPT model (free)",
2408
+ description: "OpenAI's free lightweight GPT model",
2241
2409
  category: "fast",
2242
2410
  provider: "opencode-zen",
2243
- contextLength: 200000,
2411
+ contextLength: 400000,
2244
2412
  free: true
2245
2413
  },
2246
2414
  {
2247
- id: "claude-3-5-haiku",
2248
- name: "Claude Haiku 3.5",
2249
- description: "Anthropic's fast and efficient model",
2415
+ id: "mimo-v2.5",
2416
+ name: "MiMo V2.5",
2417
+ description: "Xiaomi's latest long-context MiMo model",
2250
2418
  category: "fast",
2251
2419
  provider: "opencode-zen",
2252
- contextLength: 200000
2420
+ contextLength: 1048576
2253
2421
  },
2254
2422
  {
2255
2423
  id: "claude-haiku-4-5",
@@ -2268,84 +2436,68 @@ var OPENCODE_ZEN_MODELS = [
2268
2436
  contextLength: 200000
2269
2437
  },
2270
2438
  {
2271
- id: "gpt-5.1-codex-mini",
2272
- name: "GPT 5.1 Codex Mini",
2273
- description: "OpenAI's fast codex model",
2439
+ id: "gpt-5.4-mini",
2440
+ name: "GPT 5.4 Mini",
2441
+ description: "OpenAI's latest fast GPT mini model",
2274
2442
  category: "fast",
2275
2443
  provider: "opencode-zen",
2276
- contextLength: 200000
2444
+ contextLength: 400000
2277
2445
  },
2278
2446
  {
2279
- id: "deepseek-v4-flash",
2280
- name: "DeepSeek V4 Flash",
2281
- description: "DeepSeek's latest fast open-source model",
2447
+ id: "gpt-5.4-nano",
2448
+ name: "GPT 5.4 Nano",
2449
+ description: "OpenAI's latest lightweight GPT model",
2282
2450
  category: "fast",
2283
2451
  provider: "opencode-zen",
2284
- contextLength: 1048576
2452
+ contextLength: 400000
2285
2453
  },
2286
2454
  {
2287
- id: "claude-sonnet-4",
2288
- name: "Claude Sonnet 4",
2289
- description: "Anthropic's balanced model for complex tasks",
2455
+ id: "claude-sonnet-4-6",
2456
+ name: "Claude Sonnet 4.6",
2457
+ description: "Anthropic's latest Sonnet model",
2290
2458
  category: "smart",
2291
2459
  provider: "opencode-zen",
2292
- contextLength: 200000
2460
+ contextLength: 1e6
2293
2461
  },
2294
2462
  {
2295
- id: "gemini-3-pro",
2296
- name: "Gemini 3 Pro",
2463
+ id: "gemini-3.1-pro",
2464
+ name: "Gemini 3.1 Pro",
2297
2465
  description: "Google's high-end Gemini model",
2298
2466
  category: "smart",
2299
2467
  provider: "opencode-zen",
2300
2468
  contextLength: 200000
2301
2469
  },
2302
2470
  {
2303
- id: "gpt-5.2",
2304
- name: "GPT 5.2",
2305
- description: "OpenAI's flagship GPT model",
2306
- category: "smart",
2307
- provider: "opencode-zen",
2308
- contextLength: 200000
2309
- },
2310
- {
2311
- id: "gpt-5.2-codex",
2312
- name: "GPT 5.2 Codex",
2313
- description: "OpenAI's coding-focused GPT model",
2314
- category: "smart",
2315
- provider: "opencode-zen",
2316
- contextLength: 200000
2317
- },
2318
- {
2319
- id: "gpt-5.1",
2320
- name: "GPT 5.1",
2321
- description: "OpenAI's balanced GPT model",
2471
+ id: "gpt-5.5",
2472
+ name: "GPT 5.5",
2473
+ description: "OpenAI's latest flagship GPT model",
2322
2474
  category: "smart",
2323
2475
  provider: "opencode-zen",
2324
- contextLength: 200000
2476
+ contextLength: 1050000
2325
2477
  },
2326
2478
  {
2327
- id: "gpt-5.1-codex",
2328
- name: "GPT 5.1 Codex",
2329
- description: "OpenAI's coding model",
2479
+ id: "gpt-5.5-pro",
2480
+ name: "GPT 5.5 Pro",
2481
+ description: "OpenAI's latest high-capability reasoning model",
2330
2482
  category: "smart",
2331
2483
  provider: "opencode-zen",
2332
- contextLength: 200000
2484
+ contextLength: 1050000
2333
2485
  },
2334
2486
  {
2335
- id: "gpt-5",
2336
- name: "GPT 5",
2337
- description: "OpenAI's prior generation GPT model",
2487
+ id: "gpt-5.3-codex",
2488
+ name: "GPT 5.3 Codex",
2489
+ description: "OpenAI's latest coding-focused GPT model",
2338
2490
  category: "smart",
2339
2491
  provider: "opencode-zen",
2340
- contextLength: 200000
2492
+ contextLength: 400000
2341
2493
  },
2342
2494
  {
2343
- id: "gpt-5-codex",
2344
- name: "GPT 5 Codex",
2345
- description: "OpenAI's prior generation codex model",
2495
+ id: "gpt-5.3-codex-spark",
2496
+ name: "GPT 5.3 Codex Spark",
2497
+ description: "OpenAI's latest fast coding-focused GPT model",
2346
2498
  category: "smart",
2347
2499
  provider: "opencode-zen",
2348
- contextLength: 200000
2500
+ contextLength: 400000
2349
2501
  },
2350
2502
  {
2351
2503
  id: "minimax-m2.7",
@@ -2388,44 +2540,12 @@ var OPENCODE_ZEN_MODELS = [
2388
2540
  contextLength: 202752
2389
2541
  },
2390
2542
  {
2391
- id: "claude-sonnet-4-5",
2392
- name: "Claude Sonnet 4.5",
2393
- description: "Anthropic's hybrid reasoning model",
2543
+ id: "claude-opus-4-7",
2544
+ name: "Claude Opus 4.7",
2545
+ description: "Anthropic's latest Opus model",
2394
2546
  category: "reasoning",
2395
2547
  provider: "opencode-zen",
2396
- contextLength: 200000
2397
- },
2398
- {
2399
- id: "claude-opus-4-6",
2400
- name: "Claude Opus 4.6",
2401
- description: "Anthropic's newest Opus model",
2402
- category: "reasoning",
2403
- provider: "opencode-zen",
2404
- contextLength: 200000
2405
- },
2406
- {
2407
- id: "claude-opus-4-5",
2408
- name: "Claude Opus 4.5",
2409
- description: "Anthropic's most capable model",
2410
- category: "reasoning",
2411
- provider: "opencode-zen",
2412
- contextLength: 200000
2413
- },
2414
- {
2415
- id: "claude-opus-4-1",
2416
- name: "Claude Opus 4.1",
2417
- description: "Anthropic's powerful reasoning model",
2418
- category: "reasoning",
2419
- provider: "opencode-zen",
2420
- contextLength: 200000
2421
- },
2422
- {
2423
- id: "gpt-5.1-codex-max",
2424
- name: "GPT 5.1 Codex Max",
2425
- description: "OpenAI's largest coding model",
2426
- category: "reasoning",
2427
- provider: "opencode-zen",
2428
- contextLength: 200000
2548
+ contextLength: 1e6
2429
2549
  },
2430
2550
  {
2431
2551
  id: "kimi-k2-thinking",
@@ -2436,7 +2556,45 @@ var OPENCODE_ZEN_MODELS = [
2436
2556
  contextLength: 262144
2437
2557
  }
2438
2558
  ];
2439
- var ALL_MODELS = [...OPENCODE_ZEN_MODELS, ...OPENROUTER_MODELS];
2559
+ var ALL_MODELS = [
2560
+ ...OPENCODE_ZEN_MODELS,
2561
+ ...OPENROUTER_MODELS,
2562
+ ...VERCEL_AI_GATEWAY_MODELS,
2563
+ ...CLOUDFLARE_AI_GATEWAY_MODELS,
2564
+ ...WORKERS_AI_MODELS
2565
+ ];
2566
+ function getProviderModels(provider) {
2567
+ switch (provider) {
2568
+ case "opencode-zen":
2569
+ return OPENCODE_ZEN_MODELS;
2570
+ case "openrouter":
2571
+ return OPENROUTER_MODELS;
2572
+ case "vercel-ai-gateway":
2573
+ return VERCEL_AI_GATEWAY_MODELS;
2574
+ case "cloudflare-ai-gateway":
2575
+ return CLOUDFLARE_AI_GATEWAY_MODELS;
2576
+ case "workers-ai":
2577
+ return WORKERS_AI_MODELS;
2578
+ case "custom":
2579
+ return [];
2580
+ }
2581
+ }
2582
+ function getProviderDisplayName(provider) {
2583
+ switch (provider) {
2584
+ case "opencode-zen":
2585
+ return "OpenCode Zen";
2586
+ case "openrouter":
2587
+ return "OpenRouter";
2588
+ case "vercel-ai-gateway":
2589
+ return "Vercel AI Gateway";
2590
+ case "cloudflare-ai-gateway":
2591
+ return "Cloudflare AI Gateway";
2592
+ case "workers-ai":
2593
+ return "Cloudflare Workers AI";
2594
+ case "custom":
2595
+ return "Custom";
2596
+ }
2597
+ }
2440
2598
 
2441
2599
  // src/lib/config.ts
2442
2600
  import { homedir } from "os";
@@ -2804,11 +2962,20 @@ var CONFIG_FILE = join(CONFIG_DIR, "config.json");
2804
2962
  var HISTORY_FILE = join(CONFIG_DIR, "history.json");
2805
2963
  var KEYCHAIN_OPENROUTER = "openrouter-api-key";
2806
2964
  var KEYCHAIN_OPENCODE_ZEN = "opencode-zen-api-key";
2965
+ var KEYCHAIN_VERCEL_AI_GATEWAY = "vercel-ai-gateway-api-key";
2966
+ var KEYCHAIN_CLOUDFLARE_AI_GATEWAY = "cloudflare-ai-gateway-api-key";
2967
+ var KEYCHAIN_WORKERS_AI = "workers-ai-api-key";
2807
2968
  var DEFAULT_CONFIG = {
2808
2969
  provider: "opencode-zen",
2809
2970
  openrouterApiKey: "",
2810
2971
  opencodeZenApiKey: "",
2811
- defaultModel: "kimi-k2.6-free",
2972
+ vercelAiGatewayApiKey: "",
2973
+ cloudflareAiGatewayApiKey: "",
2974
+ workersAiApiKey: "",
2975
+ cloudflareAccountId: "",
2976
+ cloudflareAiGatewayId: "default",
2977
+ defaultModel: "minimax-m2.5-free",
2978
+ thinkingLevel: "low",
2812
2979
  safetyLevel: "moderate",
2813
2980
  dryRunByDefault: false,
2814
2981
  blockedCommands: [
@@ -2847,6 +3014,9 @@ function saveConfig(config) {
2847
3014
  if (isSecureStorageAvailable()) {
2848
3015
  configToSave.openrouterApiKey = "";
2849
3016
  configToSave.opencodeZenApiKey = "";
3017
+ configToSave.vercelAiGatewayApiKey = "";
3018
+ configToSave.cloudflareAiGatewayApiKey = "";
3019
+ configToSave.workersAiApiKey = "";
2850
3020
  }
2851
3021
  writeFileSync(CONFIG_FILE, JSON.stringify(configToSave, null, 2));
2852
3022
  }
@@ -2859,28 +3029,83 @@ async function getApiKey(provider) {
2859
3029
  const envKey = process.env.OPENCODE_ZEN_API_KEY;
2860
3030
  if (envKey)
2861
3031
  return envKey;
3032
+ } else if (provider === "vercel-ai-gateway") {
3033
+ const envKey = process.env.AI_GATEWAY_API_KEY || process.env.VERCEL_AI_GATEWAY_API_KEY;
3034
+ if (envKey)
3035
+ return envKey;
3036
+ } else if (provider === "cloudflare-ai-gateway") {
3037
+ const envKey = process.env.CLOUDFLARE_AI_GATEWAY_API_KEY || process.env.CF_AIG_TOKEN;
3038
+ if (envKey)
3039
+ return envKey;
3040
+ } else if (provider === "workers-ai") {
3041
+ const envKey = process.env.CLOUDFLARE_API_TOKEN || process.env.CLOUDFLARE_API_KEY;
3042
+ if (envKey)
3043
+ return envKey;
2862
3044
  }
2863
- const keychainKey = provider === "openrouter" ? KEYCHAIN_OPENROUTER : KEYCHAIN_OPENCODE_ZEN;
3045
+ const keychainKey = getKeychainKey(provider);
2864
3046
  const secureKey = await getSecret(keychainKey);
2865
3047
  if (secureKey)
2866
3048
  return secureKey;
2867
3049
  const config = loadConfig();
2868
- return provider === "openrouter" ? config.openrouterApiKey : config.opencodeZenApiKey;
3050
+ switch (provider) {
3051
+ case "openrouter":
3052
+ return config.openrouterApiKey;
3053
+ case "opencode-zen":
3054
+ return config.opencodeZenApiKey;
3055
+ case "vercel-ai-gateway":
3056
+ return config.vercelAiGatewayApiKey || "";
3057
+ case "cloudflare-ai-gateway":
3058
+ return config.cloudflareAiGatewayApiKey || "";
3059
+ case "workers-ai":
3060
+ return config.workersAiApiKey || "";
3061
+ case "custom":
3062
+ return "";
3063
+ }
2869
3064
  }
2870
3065
  async function setApiKey(provider, key) {
2871
3066
  const config = loadConfig();
2872
3067
  config.provider = provider;
2873
- const keychainKey = provider === "openrouter" ? KEYCHAIN_OPENROUTER : KEYCHAIN_OPENCODE_ZEN;
3068
+ const keychainKey = getKeychainKey(provider);
2874
3069
  const stored = await setSecret(keychainKey, key);
2875
3070
  if (!stored) {
2876
- if (provider === "openrouter") {
2877
- config.openrouterApiKey = key;
2878
- } else {
2879
- config.opencodeZenApiKey = key;
3071
+ switch (provider) {
3072
+ case "openrouter":
3073
+ config.openrouterApiKey = key;
3074
+ break;
3075
+ case "opencode-zen":
3076
+ config.opencodeZenApiKey = key;
3077
+ break;
3078
+ case "vercel-ai-gateway":
3079
+ config.vercelAiGatewayApiKey = key;
3080
+ break;
3081
+ case "cloudflare-ai-gateway":
3082
+ config.cloudflareAiGatewayApiKey = key;
3083
+ break;
3084
+ case "workers-ai":
3085
+ config.workersAiApiKey = key;
3086
+ break;
3087
+ case "custom":
3088
+ break;
2880
3089
  }
2881
3090
  }
2882
3091
  saveConfig(config);
2883
3092
  }
3093
+ function getKeychainKey(provider) {
3094
+ switch (provider) {
3095
+ case "openrouter":
3096
+ return KEYCHAIN_OPENROUTER;
3097
+ case "opencode-zen":
3098
+ return KEYCHAIN_OPENCODE_ZEN;
3099
+ case "vercel-ai-gateway":
3100
+ return KEYCHAIN_VERCEL_AI_GATEWAY;
3101
+ case "cloudflare-ai-gateway":
3102
+ return KEYCHAIN_CLOUDFLARE_AI_GATEWAY;
3103
+ case "workers-ai":
3104
+ return KEYCHAIN_WORKERS_AI;
3105
+ case "custom":
3106
+ return "custom-api-key";
3107
+ }
3108
+ }
2884
3109
  function loadHistory() {
2885
3110
  ensureConfigDir();
2886
3111
  if (!existsSync(HISTORY_FILE)) {
@@ -41183,15 +41408,6 @@ var defaultDownload2 = createDownload();
41183
41408
 
41184
41409
  // src/lib/types.ts
41185
41410
  var OPENROUTER_MODELS2 = [
41186
- {
41187
- id: "minimax/minimax-m2.5:free",
41188
- name: "MiniMax M2.5 Free",
41189
- description: "Free MiniMax model for trying out open-source generation",
41190
- category: "smart",
41191
- provider: "openrouter",
41192
- contextLength: 196608,
41193
- free: true
41194
- },
41195
41411
  {
41196
41412
  id: "xiaomi/mimo-v2.5",
41197
41413
  name: "MiMo V2.5",
@@ -41224,6 +41440,38 @@ var OPENROUTER_MODELS2 = [
41224
41440
  provider: "openrouter",
41225
41441
  contextLength: 202752
41226
41442
  },
41443
+ {
41444
+ id: "openai/gpt-latest",
41445
+ name: "OpenAI GPT Latest",
41446
+ description: "OpenRouter alias that redirects to the latest OpenAI GPT model",
41447
+ category: "smart",
41448
+ provider: "openrouter",
41449
+ contextLength: 1050000
41450
+ },
41451
+ {
41452
+ id: "openai/gpt-5.5",
41453
+ name: "GPT 5.5",
41454
+ description: "OpenAI's latest flagship GPT model",
41455
+ category: "smart",
41456
+ provider: "openrouter",
41457
+ contextLength: 1050000
41458
+ },
41459
+ {
41460
+ id: "anthropic/claude-sonnet-latest",
41461
+ name: "Claude Sonnet Latest",
41462
+ description: "OpenRouter alias that redirects to the latest Claude Sonnet model",
41463
+ category: "smart",
41464
+ provider: "openrouter",
41465
+ contextLength: 1e6
41466
+ },
41467
+ {
41468
+ id: "anthropic/claude-sonnet-4.6",
41469
+ name: "Claude Sonnet 4.6",
41470
+ description: "Anthropic's latest Sonnet model",
41471
+ category: "smart",
41472
+ provider: "openrouter",
41473
+ contextLength: 1e6
41474
+ },
41227
41475
  {
41228
41476
  id: "moonshotai/kimi-k2.6",
41229
41477
  name: "Kimi K2.6",
@@ -41256,6 +41504,30 @@ var OPENROUTER_MODELS2 = [
41256
41504
  provider: "openrouter",
41257
41505
  contextLength: 196608
41258
41506
  },
41507
+ {
41508
+ id: "anthropic/claude-opus-latest",
41509
+ name: "Claude Opus Latest",
41510
+ description: "OpenRouter alias that redirects to the latest Claude Opus model",
41511
+ category: "reasoning",
41512
+ provider: "openrouter",
41513
+ contextLength: 1e6
41514
+ },
41515
+ {
41516
+ id: "anthropic/claude-opus-4.7",
41517
+ name: "Claude Opus 4.7",
41518
+ description: "Anthropic's latest Opus model",
41519
+ category: "reasoning",
41520
+ provider: "openrouter",
41521
+ contextLength: 1e6
41522
+ },
41523
+ {
41524
+ id: "openai/gpt-5.5-pro",
41525
+ name: "GPT 5.5 Pro",
41526
+ description: "OpenAI's latest high-capability reasoning model",
41527
+ category: "reasoning",
41528
+ provider: "openrouter",
41529
+ contextLength: 1050000
41530
+ },
41259
41531
  {
41260
41532
  id: "moonshotai/kimi-k2-thinking",
41261
41533
  name: "Kimi K2 Thinking",
@@ -41265,58 +41537,179 @@ var OPENROUTER_MODELS2 = [
41265
41537
  contextLength: 262144
41266
41538
  }
41267
41539
  ];
41540
+ var VERCEL_AI_GATEWAY_MODELS2 = [
41541
+ {
41542
+ id: "openai/gpt-latest",
41543
+ name: "OpenAI GPT Latest",
41544
+ description: "Vercel AI Gateway alias that redirects to the latest OpenAI GPT model",
41545
+ category: "smart",
41546
+ provider: "vercel-ai-gateway",
41547
+ contextLength: 1050000
41548
+ },
41549
+ {
41550
+ id: "openai/gpt-5.5",
41551
+ name: "GPT 5.5",
41552
+ description: "OpenAI's latest flagship GPT model",
41553
+ category: "smart",
41554
+ provider: "vercel-ai-gateway",
41555
+ contextLength: 1050000
41556
+ },
41557
+ {
41558
+ id: "anthropic/claude-sonnet-4.6",
41559
+ name: "Claude Sonnet 4.6",
41560
+ description: "Anthropic's latest Sonnet model",
41561
+ category: "smart",
41562
+ provider: "vercel-ai-gateway",
41563
+ contextLength: 1e6
41564
+ },
41565
+ {
41566
+ id: "anthropic/claude-opus-4.7",
41567
+ name: "Claude Opus 4.7",
41568
+ description: "Anthropic's latest Opus model",
41569
+ category: "reasoning",
41570
+ provider: "vercel-ai-gateway",
41571
+ contextLength: 1e6
41572
+ },
41573
+ {
41574
+ id: "openai/gpt-5.5-pro",
41575
+ name: "GPT 5.5 Pro",
41576
+ description: "OpenAI's latest high-capability reasoning model",
41577
+ category: "reasoning",
41578
+ provider: "vercel-ai-gateway",
41579
+ contextLength: 1050000
41580
+ }
41581
+ ];
41582
+ var CLOUDFLARE_AI_GATEWAY_MODELS2 = [
41583
+ {
41584
+ id: "openai/gpt-5.5",
41585
+ name: "GPT 5.5",
41586
+ description: "OpenAI's latest flagship GPT model through Cloudflare AI Gateway",
41587
+ category: "smart",
41588
+ provider: "cloudflare-ai-gateway",
41589
+ contextLength: 1050000
41590
+ },
41591
+ {
41592
+ id: "anthropic/claude-sonnet-4-6",
41593
+ name: "Claude Sonnet 4.6",
41594
+ description: "Anthropic's latest Sonnet model through Cloudflare AI Gateway",
41595
+ category: "smart",
41596
+ provider: "cloudflare-ai-gateway",
41597
+ contextLength: 1e6
41598
+ },
41599
+ {
41600
+ id: "anthropic/claude-opus-4-7",
41601
+ name: "Claude Opus 4.7",
41602
+ description: "Anthropic's latest Opus model through Cloudflare AI Gateway",
41603
+ category: "reasoning",
41604
+ provider: "cloudflare-ai-gateway",
41605
+ contextLength: 1e6
41606
+ },
41607
+ {
41608
+ id: "workers-ai/@cf/meta/llama-3.3-70b-instruct-fp8-fast",
41609
+ name: "Workers AI Llama 3.3 70B Fast",
41610
+ description: "Cloudflare Workers AI fast Llama model routed through AI Gateway",
41611
+ category: "smart",
41612
+ provider: "cloudflare-ai-gateway",
41613
+ contextLength: 24000
41614
+ }
41615
+ ];
41616
+ var WORKERS_AI_MODELS2 = [
41617
+ {
41618
+ id: "@cf/meta/llama-3.3-70b-instruct-fp8-fast",
41619
+ name: "Llama 3.3 70B Fast",
41620
+ description: "Cloudflare Workers AI fast Llama instruct model",
41621
+ category: "smart",
41622
+ provider: "workers-ai",
41623
+ contextLength: 24000
41624
+ },
41625
+ {
41626
+ id: "@cf/meta/llama-3.1-8b-instruct",
41627
+ name: "Llama 3.1 8B Instruct",
41628
+ description: "Cloudflare Workers AI lightweight Llama instruct model",
41629
+ category: "fast",
41630
+ provider: "workers-ai",
41631
+ contextLength: 8000
41632
+ },
41633
+ {
41634
+ id: "@cf/openai/gpt-oss-120b",
41635
+ name: "GPT OSS 120B",
41636
+ description: "OpenAI open-weight model hosted by Cloudflare Workers AI",
41637
+ category: "reasoning",
41638
+ provider: "workers-ai",
41639
+ contextLength: 32000
41640
+ }
41641
+ ];
41268
41642
  var OPENCODE_ZEN_MODELS2 = [
41269
41643
  {
41270
41644
  id: "minimax-m2.5-free",
41271
41645
  name: "MiniMax M2.5 Free",
41272
41646
  description: "MiniMax's free model (limited time)",
41273
- category: "fast",
41647
+ category: "smart",
41274
41648
  provider: "opencode-zen",
41275
41649
  contextLength: 196608,
41276
41650
  free: true
41277
41651
  },
41278
41652
  {
41279
- id: "kimi-k2.6-free",
41280
- name: "Kimi K2.6 Free",
41281
- description: "Moonshot's latest model (free, limited time)",
41653
+ id: "ling-2.6-flash-free",
41654
+ name: "Ling 2.6 Flash Free",
41655
+ description: "Ling's free flash model (limited time)",
41656
+ category: "fast",
41657
+ provider: "opencode-zen",
41658
+ contextLength: 131072,
41659
+ free: true
41660
+ },
41661
+ {
41662
+ id: "hy3-preview-free",
41663
+ name: "Hy3 Preview Free",
41664
+ description: "Hy3 preview model (free, limited time)",
41282
41665
  category: "smart",
41283
41666
  provider: "opencode-zen",
41284
- contextLength: 262144,
41667
+ contextLength: 131072,
41285
41668
  free: true
41286
41669
  },
41287
41670
  {
41288
- id: "deepseek-v4-flash-free",
41289
- name: "DeepSeek V4 Flash Free",
41290
- description: "DeepSeek's latest fast model (free, limited time)",
41291
- category: "fast",
41671
+ id: "nemotron-3-super-free",
41672
+ name: "Nemotron 3 Super Free",
41673
+ description: "NVIDIA Nemotron free trial model",
41674
+ category: "smart",
41292
41675
  provider: "opencode-zen",
41293
- contextLength: 1048576,
41676
+ contextLength: 131072,
41294
41677
  free: true
41295
41678
  },
41296
41679
  {
41297
- id: "mimo-v2.5",
41298
- name: "MiMo V2.5",
41299
- description: "Xiaomi's latest long-context MiMo model",
41300
- category: "fast",
41680
+ id: "trinity-large-preview-free",
41681
+ name: "Trinity Large Preview Free",
41682
+ description: "Trinity large preview model (free, limited time)",
41683
+ category: "smart",
41301
41684
  provider: "opencode-zen",
41302
- contextLength: 1048576
41685
+ contextLength: 131072,
41686
+ free: true
41687
+ },
41688
+ {
41689
+ id: "big-pickle",
41690
+ name: "Big Pickle",
41691
+ description: "OpenCode stealth model (free, limited time)",
41692
+ category: "smart",
41693
+ provider: "opencode-zen",
41694
+ contextLength: 131072,
41695
+ free: true
41303
41696
  },
41304
41697
  {
41305
41698
  id: "gpt-5-nano",
41306
41699
  name: "GPT 5 Nano",
41307
- description: "OpenAI's fastest GPT model (free)",
41700
+ description: "OpenAI's free lightweight GPT model",
41308
41701
  category: "fast",
41309
41702
  provider: "opencode-zen",
41310
- contextLength: 200000,
41703
+ contextLength: 400000,
41311
41704
  free: true
41312
41705
  },
41313
41706
  {
41314
- id: "claude-3-5-haiku",
41315
- name: "Claude Haiku 3.5",
41316
- description: "Anthropic's fast and efficient model",
41707
+ id: "mimo-v2.5",
41708
+ name: "MiMo V2.5",
41709
+ description: "Xiaomi's latest long-context MiMo model",
41317
41710
  category: "fast",
41318
41711
  provider: "opencode-zen",
41319
- contextLength: 200000
41712
+ contextLength: 1048576
41320
41713
  },
41321
41714
  {
41322
41715
  id: "claude-haiku-4-5",
@@ -41335,84 +41728,68 @@ var OPENCODE_ZEN_MODELS2 = [
41335
41728
  contextLength: 200000
41336
41729
  },
41337
41730
  {
41338
- id: "gpt-5.1-codex-mini",
41339
- name: "GPT 5.1 Codex Mini",
41340
- description: "OpenAI's fast codex model",
41731
+ id: "gpt-5.4-mini",
41732
+ name: "GPT 5.4 Mini",
41733
+ description: "OpenAI's latest fast GPT mini model",
41341
41734
  category: "fast",
41342
41735
  provider: "opencode-zen",
41343
- contextLength: 200000
41736
+ contextLength: 400000
41344
41737
  },
41345
41738
  {
41346
- id: "deepseek-v4-flash",
41347
- name: "DeepSeek V4 Flash",
41348
- description: "DeepSeek's latest fast open-source model",
41739
+ id: "gpt-5.4-nano",
41740
+ name: "GPT 5.4 Nano",
41741
+ description: "OpenAI's latest lightweight GPT model",
41349
41742
  category: "fast",
41350
41743
  provider: "opencode-zen",
41351
- contextLength: 1048576
41744
+ contextLength: 400000
41352
41745
  },
41353
41746
  {
41354
- id: "claude-sonnet-4",
41355
- name: "Claude Sonnet 4",
41356
- description: "Anthropic's balanced model for complex tasks",
41747
+ id: "claude-sonnet-4-6",
41748
+ name: "Claude Sonnet 4.6",
41749
+ description: "Anthropic's latest Sonnet model",
41357
41750
  category: "smart",
41358
41751
  provider: "opencode-zen",
41359
- contextLength: 200000
41752
+ contextLength: 1e6
41360
41753
  },
41361
41754
  {
41362
- id: "gemini-3-pro",
41363
- name: "Gemini 3 Pro",
41755
+ id: "gemini-3.1-pro",
41756
+ name: "Gemini 3.1 Pro",
41364
41757
  description: "Google's high-end Gemini model",
41365
41758
  category: "smart",
41366
41759
  provider: "opencode-zen",
41367
41760
  contextLength: 200000
41368
41761
  },
41369
41762
  {
41370
- id: "gpt-5.2",
41371
- name: "GPT 5.2",
41372
- description: "OpenAI's flagship GPT model",
41763
+ id: "gpt-5.5",
41764
+ name: "GPT 5.5",
41765
+ description: "OpenAI's latest flagship GPT model",
41373
41766
  category: "smart",
41374
41767
  provider: "opencode-zen",
41375
- contextLength: 200000
41768
+ contextLength: 1050000
41376
41769
  },
41377
41770
  {
41378
- id: "gpt-5.2-codex",
41379
- name: "GPT 5.2 Codex",
41380
- description: "OpenAI's coding-focused GPT model",
41771
+ id: "gpt-5.5-pro",
41772
+ name: "GPT 5.5 Pro",
41773
+ description: "OpenAI's latest high-capability reasoning model",
41381
41774
  category: "smart",
41382
41775
  provider: "opencode-zen",
41383
- contextLength: 200000
41776
+ contextLength: 1050000
41384
41777
  },
41385
41778
  {
41386
- id: "gpt-5.1",
41387
- name: "GPT 5.1",
41388
- description: "OpenAI's balanced GPT model",
41779
+ id: "gpt-5.3-codex",
41780
+ name: "GPT 5.3 Codex",
41781
+ description: "OpenAI's latest coding-focused GPT model",
41389
41782
  category: "smart",
41390
41783
  provider: "opencode-zen",
41391
- contextLength: 200000
41784
+ contextLength: 400000
41392
41785
  },
41393
41786
  {
41394
- id: "gpt-5.1-codex",
41395
- name: "GPT 5.1 Codex",
41396
- description: "OpenAI's coding model",
41787
+ id: "gpt-5.3-codex-spark",
41788
+ name: "GPT 5.3 Codex Spark",
41789
+ description: "OpenAI's latest fast coding-focused GPT model",
41397
41790
  category: "smart",
41398
41791
  provider: "opencode-zen",
41399
- contextLength: 200000
41400
- },
41401
- {
41402
- id: "gpt-5",
41403
- name: "GPT 5",
41404
- description: "OpenAI's prior generation GPT model",
41405
- category: "smart",
41406
- provider: "opencode-zen",
41407
- contextLength: 200000
41408
- },
41409
- {
41410
- id: "gpt-5-codex",
41411
- name: "GPT 5 Codex",
41412
- description: "OpenAI's prior generation codex model",
41413
- category: "smart",
41414
- provider: "opencode-zen",
41415
- contextLength: 200000
41792
+ contextLength: 400000
41416
41793
  },
41417
41794
  {
41418
41795
  id: "minimax-m2.7",
@@ -41455,44 +41832,12 @@ var OPENCODE_ZEN_MODELS2 = [
41455
41832
  contextLength: 202752
41456
41833
  },
41457
41834
  {
41458
- id: "claude-sonnet-4-5",
41459
- name: "Claude Sonnet 4.5",
41460
- description: "Anthropic's hybrid reasoning model",
41835
+ id: "claude-opus-4-7",
41836
+ name: "Claude Opus 4.7",
41837
+ description: "Anthropic's latest Opus model",
41461
41838
  category: "reasoning",
41462
41839
  provider: "opencode-zen",
41463
- contextLength: 200000
41464
- },
41465
- {
41466
- id: "claude-opus-4-6",
41467
- name: "Claude Opus 4.6",
41468
- description: "Anthropic's newest Opus model",
41469
- category: "reasoning",
41470
- provider: "opencode-zen",
41471
- contextLength: 200000
41472
- },
41473
- {
41474
- id: "claude-opus-4-5",
41475
- name: "Claude Opus 4.5",
41476
- description: "Anthropic's most capable model",
41477
- category: "reasoning",
41478
- provider: "opencode-zen",
41479
- contextLength: 200000
41480
- },
41481
- {
41482
- id: "claude-opus-4-1",
41483
- name: "Claude Opus 4.1",
41484
- description: "Anthropic's powerful reasoning model",
41485
- category: "reasoning",
41486
- provider: "opencode-zen",
41487
- contextLength: 200000
41488
- },
41489
- {
41490
- id: "gpt-5.1-codex-max",
41491
- name: "GPT 5.1 Codex Max",
41492
- description: "OpenAI's largest coding model",
41493
- category: "reasoning",
41494
- provider: "opencode-zen",
41495
- contextLength: 200000
41840
+ contextLength: 1e6
41496
41841
  },
41497
41842
  {
41498
41843
  id: "kimi-k2-thinking",
@@ -41503,22 +41848,258 @@ var OPENCODE_ZEN_MODELS2 = [
41503
41848
  contextLength: 262144
41504
41849
  }
41505
41850
  ];
41506
- var ALL_MODELS2 = [...OPENCODE_ZEN_MODELS2, ...OPENROUTER_MODELS2];
41851
+ var ALL_MODELS2 = [
41852
+ ...OPENCODE_ZEN_MODELS2,
41853
+ ...OPENROUTER_MODELS2,
41854
+ ...VERCEL_AI_GATEWAY_MODELS2,
41855
+ ...CLOUDFLARE_AI_GATEWAY_MODELS2,
41856
+ ...WORKERS_AI_MODELS2
41857
+ ];
41858
+ function getProviderModels2(provider) {
41859
+ switch (provider) {
41860
+ case "opencode-zen":
41861
+ return OPENCODE_ZEN_MODELS2;
41862
+ case "openrouter":
41863
+ return OPENROUTER_MODELS2;
41864
+ case "vercel-ai-gateway":
41865
+ return VERCEL_AI_GATEWAY_MODELS2;
41866
+ case "cloudflare-ai-gateway":
41867
+ return CLOUDFLARE_AI_GATEWAY_MODELS2;
41868
+ case "workers-ai":
41869
+ return WORKERS_AI_MODELS2;
41870
+ case "custom":
41871
+ return [];
41872
+ }
41873
+ }
41874
+ function getProviderDisplayName2(provider) {
41875
+ switch (provider) {
41876
+ case "opencode-zen":
41877
+ return "OpenCode Zen";
41878
+ case "openrouter":
41879
+ return "OpenRouter";
41880
+ case "vercel-ai-gateway":
41881
+ return "Vercel AI Gateway";
41882
+ case "cloudflare-ai-gateway":
41883
+ return "Cloudflare AI Gateway";
41884
+ case "workers-ai":
41885
+ return "Cloudflare Workers AI";
41886
+ case "custom":
41887
+ return "Custom";
41888
+ }
41889
+ }
41507
41890
  function isCustomModel(model) {
41508
41891
  return "baseUrl" in model;
41509
41892
  }
41510
41893
 
41894
+ // src/lib/config.ts
41895
+ import { homedir as homedir2 } from "os";
41896
+ import { join as join2 } from "path";
41897
+ import { existsSync as existsSync2, readFileSync as readFileSync2, writeFileSync as writeFileSync2, mkdirSync as mkdirSync2 } from "fs";
41898
+ var CONFIG_DIR2 = join2(homedir2(), ".magic-shell");
41899
+ var CONFIG_FILE2 = join2(CONFIG_DIR2, "config.json");
41900
+ var HISTORY_FILE2 = join2(CONFIG_DIR2, "history.json");
41901
+ var KEYCHAIN_OPENROUTER2 = "openrouter-api-key";
41902
+ var KEYCHAIN_OPENCODE_ZEN2 = "opencode-zen-api-key";
41903
+ var KEYCHAIN_VERCEL_AI_GATEWAY2 = "vercel-ai-gateway-api-key";
41904
+ var KEYCHAIN_CLOUDFLARE_AI_GATEWAY2 = "cloudflare-ai-gateway-api-key";
41905
+ var KEYCHAIN_WORKERS_AI2 = "workers-ai-api-key";
41906
+ var DEFAULT_CONFIG2 = {
41907
+ provider: "opencode-zen",
41908
+ openrouterApiKey: "",
41909
+ opencodeZenApiKey: "",
41910
+ vercelAiGatewayApiKey: "",
41911
+ cloudflareAiGatewayApiKey: "",
41912
+ workersAiApiKey: "",
41913
+ cloudflareAccountId: "",
41914
+ cloudflareAiGatewayId: "default",
41915
+ defaultModel: "minimax-m2.5-free",
41916
+ thinkingLevel: "low",
41917
+ safetyLevel: "moderate",
41918
+ dryRunByDefault: false,
41919
+ blockedCommands: [
41920
+ ":(){ :|:& };:",
41921
+ "> /dev/sda",
41922
+ "mkfs",
41923
+ "dd if=/dev/zero",
41924
+ "chmod -R 777 /",
41925
+ "chown -R"
41926
+ ],
41927
+ confirmedDangerousPatterns: [],
41928
+ repoContext: false,
41929
+ customModels: []
41930
+ };
41931
+ function ensureConfigDir2() {
41932
+ if (!existsSync2(CONFIG_DIR2)) {
41933
+ mkdirSync2(CONFIG_DIR2, { recursive: true });
41934
+ }
41935
+ }
41936
+ function loadConfig2() {
41937
+ ensureConfigDir2();
41938
+ if (!existsSync2(CONFIG_FILE2)) {
41939
+ return { ...DEFAULT_CONFIG2 };
41940
+ }
41941
+ try {
41942
+ const data = readFileSync2(CONFIG_FILE2, "utf-8");
41943
+ const loaded = JSON.parse(data);
41944
+ return { ...DEFAULT_CONFIG2, ...loaded };
41945
+ } catch {
41946
+ return { ...DEFAULT_CONFIG2 };
41947
+ }
41948
+ }
41949
+ function saveConfig2(config2) {
41950
+ ensureConfigDir2();
41951
+ const configToSave = { ...config2 };
41952
+ if (isSecureStorageAvailable()) {
41953
+ configToSave.openrouterApiKey = "";
41954
+ configToSave.opencodeZenApiKey = "";
41955
+ configToSave.vercelAiGatewayApiKey = "";
41956
+ configToSave.cloudflareAiGatewayApiKey = "";
41957
+ configToSave.workersAiApiKey = "";
41958
+ }
41959
+ writeFileSync2(CONFIG_FILE2, JSON.stringify(configToSave, null, 2));
41960
+ }
41961
+ async function getApiKey2(provider) {
41962
+ if (provider === "openrouter") {
41963
+ const envKey = process.env.OPENROUTER_API_KEY;
41964
+ if (envKey)
41965
+ return envKey;
41966
+ } else if (provider === "opencode-zen") {
41967
+ const envKey = process.env.OPENCODE_ZEN_API_KEY;
41968
+ if (envKey)
41969
+ return envKey;
41970
+ } else if (provider === "vercel-ai-gateway") {
41971
+ const envKey = process.env.AI_GATEWAY_API_KEY || process.env.VERCEL_AI_GATEWAY_API_KEY;
41972
+ if (envKey)
41973
+ return envKey;
41974
+ } else if (provider === "cloudflare-ai-gateway") {
41975
+ const envKey = process.env.CLOUDFLARE_AI_GATEWAY_API_KEY || process.env.CF_AIG_TOKEN;
41976
+ if (envKey)
41977
+ return envKey;
41978
+ } else if (provider === "workers-ai") {
41979
+ const envKey = process.env.CLOUDFLARE_API_TOKEN || process.env.CLOUDFLARE_API_KEY;
41980
+ if (envKey)
41981
+ return envKey;
41982
+ }
41983
+ const keychainKey = getKeychainKey2(provider);
41984
+ const secureKey = await getSecret(keychainKey);
41985
+ if (secureKey)
41986
+ return secureKey;
41987
+ const config2 = loadConfig2();
41988
+ switch (provider) {
41989
+ case "openrouter":
41990
+ return config2.openrouterApiKey;
41991
+ case "opencode-zen":
41992
+ return config2.opencodeZenApiKey;
41993
+ case "vercel-ai-gateway":
41994
+ return config2.vercelAiGatewayApiKey || "";
41995
+ case "cloudflare-ai-gateway":
41996
+ return config2.cloudflareAiGatewayApiKey || "";
41997
+ case "workers-ai":
41998
+ return config2.workersAiApiKey || "";
41999
+ case "custom":
42000
+ return "";
42001
+ }
42002
+ }
42003
+ async function setApiKey2(provider, key) {
42004
+ const config2 = loadConfig2();
42005
+ config2.provider = provider;
42006
+ const keychainKey = getKeychainKey2(provider);
42007
+ const stored = await setSecret(keychainKey, key);
42008
+ if (!stored) {
42009
+ switch (provider) {
42010
+ case "openrouter":
42011
+ config2.openrouterApiKey = key;
42012
+ break;
42013
+ case "opencode-zen":
42014
+ config2.opencodeZenApiKey = key;
42015
+ break;
42016
+ case "vercel-ai-gateway":
42017
+ config2.vercelAiGatewayApiKey = key;
42018
+ break;
42019
+ case "cloudflare-ai-gateway":
42020
+ config2.cloudflareAiGatewayApiKey = key;
42021
+ break;
42022
+ case "workers-ai":
42023
+ config2.workersAiApiKey = key;
42024
+ break;
42025
+ case "custom":
42026
+ break;
42027
+ }
42028
+ }
42029
+ saveConfig2(config2);
42030
+ }
42031
+ function getKeychainKey2(provider) {
42032
+ switch (provider) {
42033
+ case "openrouter":
42034
+ return KEYCHAIN_OPENROUTER2;
42035
+ case "opencode-zen":
42036
+ return KEYCHAIN_OPENCODE_ZEN2;
42037
+ case "vercel-ai-gateway":
42038
+ return KEYCHAIN_VERCEL_AI_GATEWAY2;
42039
+ case "cloudflare-ai-gateway":
42040
+ return KEYCHAIN_CLOUDFLARE_AI_GATEWAY2;
42041
+ case "workers-ai":
42042
+ return KEYCHAIN_WORKERS_AI2;
42043
+ case "custom":
42044
+ return "custom-api-key";
42045
+ }
42046
+ }
42047
+ function loadHistory2() {
42048
+ ensureConfigDir2();
42049
+ if (!existsSync2(HISTORY_FILE2)) {
42050
+ return [];
42051
+ }
42052
+ try {
42053
+ const data = readFileSync2(HISTORY_FILE2, "utf-8");
42054
+ return JSON.parse(data);
42055
+ } catch {
42056
+ return [];
42057
+ }
42058
+ }
42059
+ function saveHistory(history) {
42060
+ ensureConfigDir2();
42061
+ const trimmed = history.slice(-100);
42062
+ writeFileSync2(HISTORY_FILE2, JSON.stringify(trimmed, null, 2));
42063
+ }
42064
+ function addToHistory(entry) {
42065
+ const history = loadHistory2();
42066
+ history.push(entry);
42067
+ saveHistory(history);
42068
+ }
42069
+ function getCustomModels2() {
42070
+ const config2 = loadConfig2();
42071
+ return config2.customModels || [];
42072
+ }
42073
+ async function getCustomModel2(id) {
42074
+ const customModels = getCustomModels2();
42075
+ const model = customModels.find((m) => m.id === id);
42076
+ if (!model) {
42077
+ return;
42078
+ }
42079
+ const keychainKey = `customModel:${model.id}:apiKey`;
42080
+ try {
42081
+ const apiKey = await getSecret(keychainKey);
42082
+ return apiKey ? { ...model, apiKey } : model;
42083
+ } catch (error40) {
42084
+ if (process.env.DEBUG_API === "1") {
42085
+ const message = error40 instanceof Error ? error40.message : String(error40);
42086
+ console.error(`[DEBUG] Custom model keychain get error: ${message}`);
42087
+ }
42088
+ return model;
42089
+ }
42090
+ }
42091
+
41511
42092
  // src/lib/shell.ts
41512
42093
  import { execSync } from "child_process";
41513
- import { existsSync as existsSync2 } from "fs";
41514
- import { homedir as homedir2 } from "os";
42094
+ import { existsSync as existsSync3 } from "fs";
42095
+ import { homedir as homedir3 } from "os";
41515
42096
  function detectShell() {
41516
42097
  const platform = detectPlatform();
41517
42098
  const isWSL = detectWSL();
41518
42099
  const shellPath = getShellPath();
41519
42100
  const shell2 = parseShellType(shellPath);
41520
42101
  const terminalEmulator = detectTerminalEmulator();
41521
- const homeDir = homedir2();
42102
+ const homeDir = homedir3();
41522
42103
  return {
41523
42104
  shell: shell2,
41524
42105
  shellPath,
@@ -41548,7 +42129,7 @@ function detectWSL() {
41548
42129
  if (release.includes("microsoft") || release.includes("wsl")) {
41549
42130
  return true;
41550
42131
  }
41551
- if (existsSync2("/proc/sys/fs/binfmt_misc/WSLInterop")) {
42132
+ if (existsSync3("/proc/sys/fs/binfmt_misc/WSLInterop")) {
41552
42133
  return true;
41553
42134
  }
41554
42135
  return false;
@@ -41708,34 +42289,34 @@ function getPlatformPaths(platform) {
41708
42289
  }
41709
42290
 
41710
42291
  // src/lib/repo-context.ts
41711
- import { existsSync as existsSync3, readFileSync as readFileSync2 } from "fs";
41712
- import { join as join2 } from "path";
42292
+ import { existsSync as existsSync4, readFileSync as readFileSync3 } from "fs";
42293
+ import { join as join3 } from "path";
41713
42294
  function detectRepoContext(cwd) {
41714
42295
  const context2 = {
41715
42296
  type: "unknown"
41716
42297
  };
41717
42298
  let detected = false;
41718
- if (existsSync3(join2(cwd, ".git"))) {
42299
+ if (existsSync4(join3(cwd, ".git"))) {
41719
42300
  context2.hasGit = true;
41720
42301
  detected = true;
41721
42302
  }
41722
- if (existsSync3(join2(cwd, "Dockerfile")) || existsSync3(join2(cwd, "docker-compose.yml")) || existsSync3(join2(cwd, "docker-compose.yaml"))) {
42303
+ if (existsSync4(join3(cwd, "Dockerfile")) || existsSync4(join3(cwd, "docker-compose.yml")) || existsSync4(join3(cwd, "docker-compose.yaml"))) {
41723
42304
  context2.hasDocker = true;
41724
42305
  detected = true;
41725
42306
  }
41726
- const packageJsonPath = join2(cwd, "package.json");
41727
- if (existsSync3(packageJsonPath)) {
42307
+ const packageJsonPath = join3(cwd, "package.json");
42308
+ if (existsSync4(packageJsonPath)) {
41728
42309
  detected = true;
41729
42310
  context2.type = "node";
41730
42311
  try {
41731
- const packageJson = JSON.parse(readFileSync2(packageJsonPath, "utf-8"));
41732
- if (existsSync3(join2(cwd, "bun.lockb")) || existsSync3(join2(cwd, "bun.lock"))) {
42312
+ const packageJson = JSON.parse(readFileSync3(packageJsonPath, "utf-8"));
42313
+ if (existsSync4(join3(cwd, "bun.lockb")) || existsSync4(join3(cwd, "bun.lock"))) {
41733
42314
  context2.packageManager = "bun";
41734
- } else if (existsSync3(join2(cwd, "pnpm-lock.yaml"))) {
42315
+ } else if (existsSync4(join3(cwd, "pnpm-lock.yaml"))) {
41735
42316
  context2.packageManager = "pnpm";
41736
- } else if (existsSync3(join2(cwd, "yarn.lock"))) {
42317
+ } else if (existsSync4(join3(cwd, "yarn.lock"))) {
41737
42318
  context2.packageManager = "yarn";
41738
- } else if (existsSync3(join2(cwd, "package-lock.json"))) {
42319
+ } else if (existsSync4(join3(cwd, "package-lock.json"))) {
41739
42320
  context2.packageManager = "npm";
41740
42321
  } else if (packageJson.packageManager) {
41741
42322
  const pm = packageJson.packageManager.split("@")[0];
@@ -41746,13 +42327,13 @@ function detectRepoContext(cwd) {
41746
42327
  }
41747
42328
  } catch {}
41748
42329
  }
41749
- const makefilePath = join2(cwd, "Makefile");
41750
- if (existsSync3(makefilePath)) {
42330
+ const makefilePath = join3(cwd, "Makefile");
42331
+ if (existsSync4(makefilePath)) {
41751
42332
  detected = true;
41752
42333
  if (context2.type === "unknown")
41753
42334
  context2.type = "make";
41754
42335
  try {
41755
- const makefile = readFileSync2(makefilePath, "utf-8");
42336
+ const makefile = readFileSync3(makefilePath, "utf-8");
41756
42337
  const targetRegex = /^([a-zA-Z_][a-zA-Z0-9_-]*)\s*:/gm;
41757
42338
  const targets = [];
41758
42339
  let match;
@@ -41766,17 +42347,17 @@ function detectRepoContext(cwd) {
41766
42347
  }
41767
42348
  } catch {}
41768
42349
  }
41769
- if (existsSync3(join2(cwd, "Cargo.toml"))) {
42350
+ if (existsSync4(join3(cwd, "Cargo.toml"))) {
41770
42351
  detected = true;
41771
42352
  context2.type = "rust";
41772
42353
  context2.cargoCommands = ["build", "run", "test", "check", "clippy", "fmt", "doc"];
41773
42354
  }
41774
- if (existsSync3(join2(cwd, "pyproject.toml")) || existsSync3(join2(cwd, "setup.py")) || existsSync3(join2(cwd, "requirements.txt"))) {
42355
+ if (existsSync4(join3(cwd, "pyproject.toml")) || existsSync4(join3(cwd, "setup.py")) || existsSync4(join3(cwd, "requirements.txt"))) {
41775
42356
  detected = true;
41776
42357
  if (context2.type === "unknown")
41777
42358
  context2.type = "python";
41778
42359
  }
41779
- if (existsSync3(join2(cwd, "go.mod"))) {
42360
+ if (existsSync4(join3(cwd, "go.mod"))) {
41780
42361
  detected = true;
41781
42362
  if (context2.type === "unknown")
41782
42363
  context2.type = "go";
@@ -41814,9 +42395,6 @@ function formatRepoContext(context2) {
41814
42395
 
41815
42396
  // src/lib/api.ts
41816
42397
  function getZenApiType(modelId) {
41817
- if (modelId === "minimax-m2.5-free") {
41818
- return "anthropic";
41819
- }
41820
42398
  if (modelId.startsWith("gpt-")) {
41821
42399
  return "openai-responses";
41822
42400
  }
@@ -41910,7 +42488,94 @@ function cleanCommand(command) {
41910
42488
  }
41911
42489
  return cleaned.trim();
41912
42490
  }
41913
- async function callOpenRouter(apiKey, modelId, systemPrompt, userInput) {
42491
+ function getThinkingLevel(config2) {
42492
+ return config2?.thinkingLevel || "low";
42493
+ }
42494
+ function supportsThinkingControl(modelId) {
42495
+ return modelId.includes("thinking") || modelId.includes("gpt-5") || modelId.includes("claude-") || modelId.includes("gemini-");
42496
+ }
42497
+ function buildOpenRouterThinkingOptions(modelId, thinkingLevel) {
42498
+ if (thinkingLevel === "off" || !supportsThinkingControl(modelId)) {
42499
+ return {};
42500
+ }
42501
+ return {
42502
+ reasoning: {
42503
+ effort: thinkingLevel
42504
+ }
42505
+ };
42506
+ }
42507
+ function buildOpenAICompatibleThinkingOptions(modelId, thinkingLevel) {
42508
+ if (thinkingLevel === "off" || !supportsThinkingControl(modelId)) {
42509
+ return {};
42510
+ }
42511
+ return {
42512
+ reasoning_effort: thinkingLevel
42513
+ };
42514
+ }
42515
+ function buildAiSdkProviderOptions(modelId, thinkingLevel, providerOptionsName) {
42516
+ if (thinkingLevel === "off" || !supportsThinkingControl(modelId)) {
42517
+ return;
42518
+ }
42519
+ if (modelId.startsWith("gpt-")) {
42520
+ const compatibleOptions = providerOptionsName && providerOptionsName !== "openai" ? {
42521
+ [providerOptionsName]: {
42522
+ reasoningEffort: thinkingLevel
42523
+ }
42524
+ } : {};
42525
+ return {
42526
+ openai: {
42527
+ reasoningEffort: thinkingLevel
42528
+ },
42529
+ openaiCompatible: {
42530
+ reasoningEffort: thinkingLevel
42531
+ },
42532
+ ...compatibleOptions
42533
+ };
42534
+ }
42535
+ if (modelId.startsWith("gemini-")) {
42536
+ return {
42537
+ google: {
42538
+ thinkingConfig: {
42539
+ thinkingLevel
42540
+ }
42541
+ }
42542
+ };
42543
+ }
42544
+ if (modelId.startsWith("claude-")) {
42545
+ const budgetByLevel = {
42546
+ low: 1024,
42547
+ medium: 4096,
42548
+ high: 8192
42549
+ };
42550
+ return {
42551
+ anthropic: {
42552
+ thinking: {
42553
+ type: "enabled",
42554
+ budgetTokens: budgetByLevel[thinkingLevel]
42555
+ }
42556
+ }
42557
+ };
42558
+ }
42559
+ if (modelId.includes("thinking")) {
42560
+ return {
42561
+ openaiCompatible: {
42562
+ reasoningEffort: thinkingLevel
42563
+ },
42564
+ ...providerOptionsName ? {
42565
+ [providerOptionsName]: {
42566
+ reasoningEffort: thinkingLevel
42567
+ }
42568
+ } : {}
42569
+ };
42570
+ }
42571
+ return;
42572
+ }
42573
+ function shouldOmitTemperature(modelId, thinkingLevel) {
42574
+ return thinkingLevel !== "off" && (modelId.startsWith("claude-") || modelId.includes("gpt-5"));
42575
+ }
42576
+ async function callOpenRouter(apiKey, modelId, systemPrompt, userInput, thinkingLevel) {
42577
+ const thinkingOptions = buildOpenRouterThinkingOptions(modelId, thinkingLevel);
42578
+ const temperatureOptions = shouldOmitTemperature(modelId, thinkingLevel) ? {} : { temperature: 0.1 };
41914
42579
  const response = await fetch("https://openrouter.ai/api/v1/chat/completions", {
41915
42580
  method: "POST",
41916
42581
  headers: {
@@ -41926,7 +42591,8 @@ async function callOpenRouter(apiKey, modelId, systemPrompt, userInput) {
41926
42591
  { role: "user", content: userInput }
41927
42592
  ],
41928
42593
  max_tokens: 500,
41929
- temperature: 0.1
42594
+ ...temperatureOptions,
42595
+ ...thinkingOptions
41930
42596
  })
41931
42597
  });
41932
42598
  if (!response.ok) {
@@ -41946,18 +42612,99 @@ async function callOpenRouter(apiKey, modelId, systemPrompt, userInput) {
41946
42612
  }
41947
42613
  return data.choices[0]?.message?.content?.trim() || "";
41948
42614
  }
42615
+ async function callOpenAICompatibleFetch(baseURL, apiKey, modelId, systemPrompt, userInput, thinkingLevel, headers = {}, includeAuthorization = true) {
42616
+ const thinkingOptions = buildOpenAICompatibleThinkingOptions(modelId, thinkingLevel);
42617
+ const temperatureOptions = shouldOmitTemperature(modelId, thinkingLevel) ? {} : { temperature: 0.1 };
42618
+ const requestHeaders = {
42619
+ "Content-Type": "application/json",
42620
+ ...headers
42621
+ };
42622
+ if (includeAuthorization) {
42623
+ requestHeaders.Authorization = `Bearer ${apiKey}`;
42624
+ }
42625
+ const response = await fetch(`${baseURL.replace(/\/$/, "")}/chat/completions`, {
42626
+ method: "POST",
42627
+ headers: requestHeaders,
42628
+ body: JSON.stringify({
42629
+ model: modelId,
42630
+ messages: [
42631
+ { role: "system", content: systemPrompt },
42632
+ { role: "user", content: userInput }
42633
+ ],
42634
+ max_tokens: 500,
42635
+ stream: false,
42636
+ ...temperatureOptions,
42637
+ ...thinkingOptions
42638
+ })
42639
+ });
42640
+ if (!response.ok) {
42641
+ const errorText = await response.text();
42642
+ let errorMessage = `API request failed: ${response.status}`;
42643
+ try {
42644
+ const errorData = JSON.parse(errorText);
42645
+ if (errorData.error?.message) {
42646
+ errorMessage = errorData.error.message;
42647
+ } else if (errorData.errors?.[0]?.message) {
42648
+ errorMessage = errorData.errors[0].message;
42649
+ }
42650
+ } catch {}
42651
+ throw new Error(errorMessage);
42652
+ }
42653
+ const data = await response.json();
42654
+ if (data.error) {
42655
+ throw new Error(data.error.message);
42656
+ }
42657
+ if (data.errors?.[0]?.message) {
42658
+ throw new Error(data.errors[0].message);
42659
+ }
42660
+ const choices = data.choices || data.result?.choices;
42661
+ return choices?.[0]?.message?.content?.trim() || "";
42662
+ }
42663
+ function getCloudflareAccountId(config2) {
42664
+ return config2.cloudflareAccountId || process.env.CLOUDFLARE_ACCOUNT_ID || process.env.CF_ACCOUNT_ID || "";
42665
+ }
42666
+ function getCloudflareGatewayId(config2) {
42667
+ return config2.cloudflareAiGatewayId || process.env.CLOUDFLARE_AI_GATEWAY_ID || process.env.CF_AIG_GATEWAY_ID || "default";
42668
+ }
42669
+ async function callGatewayProvider(provider, apiKey, modelId, systemPrompt, userInput, thinkingLevel) {
42670
+ const config2 = loadConfig2();
42671
+ switch (provider) {
42672
+ case "vercel-ai-gateway":
42673
+ return await callOpenAICompatibleFetch("https://ai-gateway.vercel.sh/v1", apiKey, modelId, systemPrompt, userInput, thinkingLevel);
42674
+ case "cloudflare-ai-gateway": {
42675
+ const accountId = getCloudflareAccountId(config2);
42676
+ if (!accountId) {
42677
+ throw new Error("Cloudflare account ID is required. Set cloudflareAccountId in config or CLOUDFLARE_ACCOUNT_ID.");
42678
+ }
42679
+ const gatewayId = getCloudflareGatewayId(config2);
42680
+ return await callOpenAICompatibleFetch(`https://gateway.ai.cloudflare.com/v1/${accountId}/${gatewayId}/compat`, apiKey, modelId, systemPrompt, userInput, thinkingLevel, { "cf-aig-authorization": `Bearer ${apiKey}` }, false);
42681
+ }
42682
+ case "workers-ai": {
42683
+ const accountId = getCloudflareAccountId(config2);
42684
+ if (!accountId) {
42685
+ throw new Error("Cloudflare account ID is required. Set cloudflareAccountId in config or CLOUDFLARE_ACCOUNT_ID.");
42686
+ }
42687
+ return await callOpenAICompatibleFetch(`https://api.cloudflare.com/client/v4/accounts/${accountId}/ai/v1`, apiKey, modelId, systemPrompt, userInput, thinkingLevel);
42688
+ }
42689
+ default:
42690
+ throw new Error(`Unsupported gateway provider: ${provider}`);
42691
+ }
42692
+ }
41949
42693
  var DEBUG_API = process.env.DEBUG_API === "1";
41950
- async function generateZenText(model, systemPrompt, userInput) {
42694
+ async function generateZenText(model, modelId, systemPrompt, userInput, thinkingLevel, providerOptionsName) {
42695
+ const providerOptions = buildAiSdkProviderOptions(modelId, thinkingLevel, providerOptionsName);
42696
+ const temperatureOptions = shouldOmitTemperature(modelId, thinkingLevel) ? {} : { temperature: 0.1 };
41951
42697
  const { text: text2 } = await generateText({
41952
42698
  model,
41953
42699
  system: systemPrompt,
41954
42700
  prompt: userInput,
41955
42701
  maxOutputTokens: 500,
41956
- temperature: 0.1
42702
+ ...temperatureOptions,
42703
+ ...providerOptions ? { providerOptions } : {}
41957
42704
  });
41958
42705
  return text2.trim();
41959
42706
  }
41960
- async function callZenOpenAIResponses(apiKey, modelId, systemPrompt, userInput) {
42707
+ async function callZenOpenAIResponses(apiKey, modelId, systemPrompt, userInput, thinkingLevel) {
41961
42708
  if (DEBUG_API) {
41962
42709
  console.error(`[DEBUG] Calling OpenAI Responses API`);
41963
42710
  console.error(`[DEBUG] Model: ${modelId}`);
@@ -41968,7 +42715,7 @@ async function callZenOpenAIResponses(apiKey, modelId, systemPrompt, userInput)
41968
42715
  baseURL: ZEN_BASE_URL
41969
42716
  });
41970
42717
  try {
41971
- return await generateZenText(openai2(modelId), systemPrompt, userInput);
42718
+ return await generateZenText(openai2(modelId), modelId, systemPrompt, userInput, thinkingLevel);
41972
42719
  } catch (error40) {
41973
42720
  const message = error40 instanceof Error ? error40.message : String(error40);
41974
42721
  if (DEBUG_API) {
@@ -41977,7 +42724,7 @@ async function callZenOpenAIResponses(apiKey, modelId, systemPrompt, userInput)
41977
42724
  throw new Error(message);
41978
42725
  }
41979
42726
  }
41980
- async function callZenAnthropic(apiKey, modelId, systemPrompt, userInput) {
42727
+ async function callZenAnthropic(apiKey, modelId, systemPrompt, userInput, thinkingLevel) {
41981
42728
  if (DEBUG_API) {
41982
42729
  console.error(`[DEBUG] Calling Anthropic Messages API`);
41983
42730
  console.error(`[DEBUG] Model: ${modelId}`);
@@ -41988,7 +42735,7 @@ async function callZenAnthropic(apiKey, modelId, systemPrompt, userInput) {
41988
42735
  baseURL: ZEN_BASE_URL
41989
42736
  });
41990
42737
  try {
41991
- return await generateZenText(anthropic2(modelId), systemPrompt, userInput);
42738
+ return await generateZenText(anthropic2(modelId), modelId, systemPrompt, userInput, thinkingLevel);
41992
42739
  } catch (error40) {
41993
42740
  const message = error40 instanceof Error ? error40.message : String(error40);
41994
42741
  if (DEBUG_API) {
@@ -41997,7 +42744,7 @@ async function callZenAnthropic(apiKey, modelId, systemPrompt, userInput) {
41997
42744
  throw new Error(message);
41998
42745
  }
41999
42746
  }
42000
- async function callZenOpenAICompatible(apiKey, modelId, systemPrompt, userInput) {
42747
+ async function callZenOpenAICompatible(apiKey, modelId, systemPrompt, userInput, thinkingLevel) {
42001
42748
  if (DEBUG_API) {
42002
42749
  console.error(`[DEBUG] Calling OpenAI-compatible Chat Completions API`);
42003
42750
  console.error(`[DEBUG] Model: ${modelId}`);
@@ -42008,7 +42755,7 @@ async function callZenOpenAICompatible(apiKey, modelId, systemPrompt, userInput)
42008
42755
  baseURL: ZEN_BASE_URL
42009
42756
  });
42010
42757
  try {
42011
- return await generateZenText(openaiCompatible(modelId), systemPrompt, userInput);
42758
+ return await generateZenText(openaiCompatible(modelId), modelId, systemPrompt, userInput, thinkingLevel, "opencodeZen");
42012
42759
  } catch (error40) {
42013
42760
  const message = error40 instanceof Error ? error40.message : String(error40);
42014
42761
  if (DEBUG_API) {
@@ -42017,7 +42764,7 @@ async function callZenOpenAICompatible(apiKey, modelId, systemPrompt, userInput)
42017
42764
  throw new Error(message);
42018
42765
  }
42019
42766
  }
42020
- async function callCustomModel(model, systemPrompt, userInput) {
42767
+ async function callCustomModel(model, systemPrompt, userInput, thinkingLevel) {
42021
42768
  if (DEBUG_API) {
42022
42769
  console.error(`[DEBUG] Calling Custom Model`);
42023
42770
  console.error(`[DEBUG] Model: ${model.modelId}`);
@@ -42029,7 +42776,7 @@ async function callCustomModel(model, systemPrompt, userInput) {
42029
42776
  baseURL: model.baseUrl
42030
42777
  });
42031
42778
  try {
42032
- return await generateZenText(openaiCompatible(model.modelId), systemPrompt, userInput);
42779
+ return await generateZenText(openaiCompatible(model.modelId), model.modelId, systemPrompt, userInput, thinkingLevel, "custom");
42033
42780
  } catch (error40) {
42034
42781
  const message = error40 instanceof Error ? error40.message : String(error40);
42035
42782
  if (DEBUG_API) {
@@ -42038,7 +42785,7 @@ async function callCustomModel(model, systemPrompt, userInput) {
42038
42785
  throw new Error(message);
42039
42786
  }
42040
42787
  }
42041
- async function callZenGoogle(apiKey, modelId, systemPrompt, userInput) {
42788
+ async function callZenGoogle(apiKey, modelId, systemPrompt, userInput, thinkingLevel) {
42042
42789
  if (DEBUG_API) {
42043
42790
  console.error(`[DEBUG] Calling Google Gemini API`);
42044
42791
  console.error(`[DEBUG] Model: ${modelId}`);
@@ -42048,7 +42795,7 @@ async function callZenGoogle(apiKey, modelId, systemPrompt, userInput) {
42048
42795
  baseURL: `https://opencode.ai/zen/v1/models/${modelId}`
42049
42796
  });
42050
42797
  try {
42051
- return await generateZenText(google2(modelId), systemPrompt, userInput);
42798
+ return await generateZenText(google2(modelId), modelId, systemPrompt, userInput, thinkingLevel);
42052
42799
  } catch (error40) {
42053
42800
  const message = error40 instanceof Error ? error40.message : String(error40);
42054
42801
  if (DEBUG_API) {
@@ -42064,28 +42811,31 @@ function getShellInfo() {
42064
42811
  }
42065
42812
  return cachedShellInfo;
42066
42813
  }
42067
- async function translateToCommand(apiKey, model, userInput, cwd, history = [], repoContextEnabled) {
42814
+ async function translateToCommand(apiKey, model, userInput, cwd, history = [], repoContextEnabled, config2) {
42068
42815
  const shellInfo = getShellInfo();
42069
42816
  const systemPrompt = buildSystemPrompt(cwd, history, shellInfo, repoContextEnabled);
42817
+ const thinkingLevel = getThinkingLevel(config2);
42070
42818
  let rawCommand;
42071
42819
  if (isCustomModel(model)) {
42072
- rawCommand = await callCustomModel(model, systemPrompt, userInput);
42820
+ rawCommand = await callCustomModel(model, systemPrompt, userInput, "off");
42073
42821
  } else if (model.provider === "openrouter") {
42074
- rawCommand = await callOpenRouter(apiKey, model.id, systemPrompt, userInput);
42822
+ rawCommand = await callOpenRouter(apiKey, model.id, systemPrompt, userInput, thinkingLevel);
42823
+ } else if (model.provider === "vercel-ai-gateway" || model.provider === "cloudflare-ai-gateway" || model.provider === "workers-ai") {
42824
+ rawCommand = await callGatewayProvider(model.provider, apiKey, model.id, systemPrompt, userInput, thinkingLevel);
42075
42825
  } else {
42076
42826
  const apiType = getZenApiType(model.id);
42077
42827
  switch (apiType) {
42078
42828
  case "openai-responses":
42079
- rawCommand = await callZenOpenAIResponses(apiKey, model.id, systemPrompt, userInput);
42829
+ rawCommand = await callZenOpenAIResponses(apiKey, model.id, systemPrompt, userInput, thinkingLevel);
42080
42830
  break;
42081
42831
  case "anthropic":
42082
- rawCommand = await callZenAnthropic(apiKey, model.id, systemPrompt, userInput);
42832
+ rawCommand = await callZenAnthropic(apiKey, model.id, systemPrompt, userInput, thinkingLevel);
42083
42833
  break;
42084
42834
  case "google":
42085
- rawCommand = await callZenGoogle(apiKey, model.id, systemPrompt, userInput);
42835
+ rawCommand = await callZenGoogle(apiKey, model.id, systemPrompt, userInput, thinkingLevel);
42086
42836
  break;
42087
42837
  case "openai-compatible":
42088
- rawCommand = await callZenOpenAICompatible(apiKey, model.id, systemPrompt, userInput);
42838
+ rawCommand = await callZenOpenAICompatible(apiKey, model.id, systemPrompt, userInput, thinkingLevel);
42089
42839
  break;
42090
42840
  }
42091
42841
  }
@@ -42096,137 +42846,6 @@ async function translateToCommand(apiKey, model, userInput, cwd, history = [], r
42096
42846
  return cleaned;
42097
42847
  }
42098
42848
 
42099
- // src/lib/config.ts
42100
- import { homedir as homedir3 } from "os";
42101
- import { join as join3 } from "path";
42102
- import { existsSync as existsSync4, readFileSync as readFileSync3, writeFileSync as writeFileSync2, mkdirSync as mkdirSync2 } from "fs";
42103
- var CONFIG_DIR2 = join3(homedir3(), ".magic-shell");
42104
- var CONFIG_FILE2 = join3(CONFIG_DIR2, "config.json");
42105
- var HISTORY_FILE2 = join3(CONFIG_DIR2, "history.json");
42106
- var KEYCHAIN_OPENROUTER2 = "openrouter-api-key";
42107
- var KEYCHAIN_OPENCODE_ZEN2 = "opencode-zen-api-key";
42108
- var DEFAULT_CONFIG2 = {
42109
- provider: "opencode-zen",
42110
- openrouterApiKey: "",
42111
- opencodeZenApiKey: "",
42112
- defaultModel: "kimi-k2.6-free",
42113
- safetyLevel: "moderate",
42114
- dryRunByDefault: false,
42115
- blockedCommands: [
42116
- ":(){ :|:& };:",
42117
- "> /dev/sda",
42118
- "mkfs",
42119
- "dd if=/dev/zero",
42120
- "chmod -R 777 /",
42121
- "chown -R"
42122
- ],
42123
- confirmedDangerousPatterns: [],
42124
- repoContext: false,
42125
- customModels: []
42126
- };
42127
- function ensureConfigDir2() {
42128
- if (!existsSync4(CONFIG_DIR2)) {
42129
- mkdirSync2(CONFIG_DIR2, { recursive: true });
42130
- }
42131
- }
42132
- function loadConfig2() {
42133
- ensureConfigDir2();
42134
- if (!existsSync4(CONFIG_FILE2)) {
42135
- return { ...DEFAULT_CONFIG2 };
42136
- }
42137
- try {
42138
- const data = readFileSync3(CONFIG_FILE2, "utf-8");
42139
- const loaded = JSON.parse(data);
42140
- return { ...DEFAULT_CONFIG2, ...loaded };
42141
- } catch {
42142
- return { ...DEFAULT_CONFIG2 };
42143
- }
42144
- }
42145
- function saveConfig2(config2) {
42146
- ensureConfigDir2();
42147
- const configToSave = { ...config2 };
42148
- if (isSecureStorageAvailable()) {
42149
- configToSave.openrouterApiKey = "";
42150
- configToSave.opencodeZenApiKey = "";
42151
- }
42152
- writeFileSync2(CONFIG_FILE2, JSON.stringify(configToSave, null, 2));
42153
- }
42154
- async function getApiKey2(provider) {
42155
- if (provider === "openrouter") {
42156
- const envKey = process.env.OPENROUTER_API_KEY;
42157
- if (envKey)
42158
- return envKey;
42159
- } else if (provider === "opencode-zen") {
42160
- const envKey = process.env.OPENCODE_ZEN_API_KEY;
42161
- if (envKey)
42162
- return envKey;
42163
- }
42164
- const keychainKey = provider === "openrouter" ? KEYCHAIN_OPENROUTER2 : KEYCHAIN_OPENCODE_ZEN2;
42165
- const secureKey = await getSecret(keychainKey);
42166
- if (secureKey)
42167
- return secureKey;
42168
- const config2 = loadConfig2();
42169
- return provider === "openrouter" ? config2.openrouterApiKey : config2.opencodeZenApiKey;
42170
- }
42171
- async function setApiKey2(provider, key) {
42172
- const config2 = loadConfig2();
42173
- config2.provider = provider;
42174
- const keychainKey = provider === "openrouter" ? KEYCHAIN_OPENROUTER2 : KEYCHAIN_OPENCODE_ZEN2;
42175
- const stored = await setSecret(keychainKey, key);
42176
- if (!stored) {
42177
- if (provider === "openrouter") {
42178
- config2.openrouterApiKey = key;
42179
- } else {
42180
- config2.opencodeZenApiKey = key;
42181
- }
42182
- }
42183
- saveConfig2(config2);
42184
- }
42185
- function loadHistory2() {
42186
- ensureConfigDir2();
42187
- if (!existsSync4(HISTORY_FILE2)) {
42188
- return [];
42189
- }
42190
- try {
42191
- const data = readFileSync3(HISTORY_FILE2, "utf-8");
42192
- return JSON.parse(data);
42193
- } catch {
42194
- return [];
42195
- }
42196
- }
42197
- function saveHistory(history) {
42198
- ensureConfigDir2();
42199
- const trimmed = history.slice(-100);
42200
- writeFileSync2(HISTORY_FILE2, JSON.stringify(trimmed, null, 2));
42201
- }
42202
- function addToHistory(entry) {
42203
- const history = loadHistory2();
42204
- history.push(entry);
42205
- saveHistory(history);
42206
- }
42207
- function getCustomModels2() {
42208
- const config2 = loadConfig2();
42209
- return config2.customModels || [];
42210
- }
42211
- async function getCustomModel2(id) {
42212
- const customModels = getCustomModels2();
42213
- const model = customModels.find((m) => m.id === id);
42214
- if (!model) {
42215
- return;
42216
- }
42217
- const keychainKey = `customModel:${model.id}:apiKey`;
42218
- try {
42219
- const apiKey = await getSecret(keychainKey);
42220
- return apiKey ? { ...model, apiKey } : model;
42221
- } catch (error40) {
42222
- if (process.env.DEBUG_API === "1") {
42223
- const message = error40 instanceof Error ? error40.message : String(error40);
42224
- console.error(`[DEBUG] Custom model keychain get error: ${message}`);
42225
- }
42226
- return model;
42227
- }
42228
- }
42229
-
42230
42849
  // src/lib/theme.ts
42231
42850
  var opencode = {
42232
42851
  name: "opencode",
@@ -42595,7 +43214,8 @@ ${colors.bold}USAGE${colors.reset}
42595
43214
  msh --add-model Add custom model (LM Studio, Ollama, etc.)
42596
43215
  msh --list-custom List custom models
42597
43216
  msh --remove-model <id> Remove custom model
42598
- msh --provider <name> Set provider (opencode-zen or openrouter)
43217
+ msh --provider <name> Set provider
43218
+ msh --thinking <level> Set thinking level (off, low, medium, high)
42599
43219
  msh --themes List available themes
42600
43220
  msh --theme <name> Set color theme
42601
43221
  msh --repo-context Enable project context detection
@@ -42630,6 +43250,10 @@ ${colors.bold}THEMES${colors.reset}
42630
43250
  ${colors.bold}ENVIRONMENT${colors.reset}
42631
43251
  OPENCODE_ZEN_API_KEY API key for OpenCode Zen
42632
43252
  OPENROUTER_API_KEY API key for OpenRouter
43253
+ AI_GATEWAY_API_KEY API key for Vercel AI Gateway
43254
+ CLOUDFLARE_API_TOKEN API token for Cloudflare Workers AI
43255
+ CLOUDFLARE_ACCOUNT_ID Account ID for Cloudflare providers
43256
+ CLOUDFLARE_AI_GATEWAY_API_KEY API key/token for Cloudflare AI Gateway
42633
43257
 
42634
43258
  ${colors.bold}CONFIG${colors.reset}
42635
43259
  ~/.magic-shell/config.json
@@ -42675,6 +43299,24 @@ ${colors.bold}OpenRouter Models${colors.reset}
42675
43299
  console.log(` ${colors.dim}${model.description}${colors.reset}`);
42676
43300
  }
42677
43301
  }
43302
+ const providerSections = [
43303
+ ["Vercel AI Gateway Models", VERCEL_AI_GATEWAY_MODELS, "vercel-ai-gateway"],
43304
+ ["Cloudflare AI Gateway Models", CLOUDFLARE_AI_GATEWAY_MODELS, "cloudflare-ai-gateway"],
43305
+ ["Cloudflare Workers AI Models", WORKERS_AI_MODELS, "workers-ai"]
43306
+ ];
43307
+ for (const [title, models, provider] of providerSections) {
43308
+ console.log(`
43309
+ ${colors.bold}${title}${colors.reset}
43310
+ `);
43311
+ const sortedModels = [...models].sort((a, b) => a.name.localeCompare(b.name));
43312
+ for (const model of sortedModels) {
43313
+ const isCurrent = config2.provider === provider && config2.defaultModel === model.id;
43314
+ const marker21 = isCurrent ? colors.success + "\u2192 " : " ";
43315
+ const category = colors.dim + `[${model.category}]` + colors.reset;
43316
+ console.log(`${marker21}${model.id} ${category}`);
43317
+ console.log(` ${colors.dim}${model.description}${colors.reset}`);
43318
+ }
43319
+ }
42678
43320
  if (customModels.length > 0) {
42679
43321
  console.log(`
42680
43322
  ${colors.bold}Custom Models${colors.reset} ${colors.info}(custom)${colors.reset}
@@ -42698,8 +43340,8 @@ function validateApiKey(key, provider) {
42698
43340
  if (trimmed.length < 20) {
42699
43341
  return "API key seems too short (expected at least 20 characters)";
42700
43342
  }
42701
- if (!trimmed.startsWith("sk-")) {
42702
- const providerName = provider === "opencode-zen" ? "OpenCode Zen" : "OpenRouter";
43343
+ if ((provider === "opencode-zen" || provider === "openrouter") && !trimmed.startsWith("sk-")) {
43344
+ const providerName = getProviderDisplayName(provider);
42703
43345
  return `${providerName} API keys typically start with 'sk-'`;
42704
43346
  }
42705
43347
  if (trimmed.includes(" ")) {
@@ -42711,6 +43353,22 @@ function validateApiKey(key, provider) {
42711
43353
  }
42712
43354
  return null;
42713
43355
  }
43356
+ function getApiKeyUrl(provider) {
43357
+ switch (provider) {
43358
+ case "opencode-zen":
43359
+ return "https://opencode.ai/auth";
43360
+ case "openrouter":
43361
+ return "https://openrouter.ai/keys";
43362
+ case "vercel-ai-gateway":
43363
+ return "https://vercel.com/docs/ai-gateway";
43364
+ case "cloudflare-ai-gateway":
43365
+ return "https://developers.cloudflare.com/ai-gateway/";
43366
+ case "workers-ai":
43367
+ return "https://dash.cloudflare.com/profile/api-tokens";
43368
+ case "custom":
43369
+ return "";
43370
+ }
43371
+ }
42714
43372
  async function setup() {
42715
43373
  const readline = await import("readline");
42716
43374
  const rl = readline.createInterface({
@@ -42728,9 +43386,18 @@ ${colors.bold}${colors.cyan}Magic Shell Setup${colors.reset}
42728
43386
  console.log("Select provider:");
42729
43387
  console.log(" 1. OpenCode Zen (recommended, has free models)");
42730
43388
  console.log(" 2. OpenRouter");
43389
+ console.log(" 3. Vercel AI Gateway");
43390
+ console.log(" 4. Cloudflare AI Gateway");
43391
+ console.log(" 5. Cloudflare Workers AI");
42731
43392
  const providerChoice = await question(`
42732
43393
  Choice [1]: `);
42733
- const provider = providerChoice === "2" ? "openrouter" : "opencode-zen";
43394
+ const providerChoices = {
43395
+ "2": "openrouter",
43396
+ "3": "vercel-ai-gateway",
43397
+ "4": "cloudflare-ai-gateway",
43398
+ "5": "workers-ai"
43399
+ };
43400
+ const provider = providerChoices[providerChoice] || "opencode-zen";
42734
43401
  const existingKey = await getApiKey(provider);
42735
43402
  if (existingKey) {
42736
43403
  const useExisting = await question(`
@@ -42738,7 +43405,7 @@ API key already configured. Keep it? [Y/n]: `);
42738
43405
  if (useExisting.toLowerCase() !== "n") {
42739
43406
  console.log(`${colors.green}\u2713 Using existing API key${colors.reset}`);
42740
43407
  } else {
42741
- const url2 = provider === "opencode-zen" ? "https://opencode.ai/auth" : "https://openrouter.ai/keys";
43408
+ const url2 = getApiKeyUrl(provider);
42742
43409
  console.log(`
42743
43410
  Get your API key from: ${colors.cyan}${url2}${colors.reset}`);
42744
43411
  let validKey = false;
@@ -42762,7 +43429,7 @@ Get your API key from: ${colors.cyan}${url2}${colors.reset}`);
42762
43429
  }
42763
43430
  }
42764
43431
  } else {
42765
- const url2 = provider === "opencode-zen" ? "https://opencode.ai/auth" : "https://openrouter.ai/keys";
43432
+ const url2 = getApiKeyUrl(provider);
42766
43433
  console.log(`
42767
43434
  Get your API key from: ${colors.cyan}${url2}${colors.reset}`);
42768
43435
  let validKey = false;
@@ -42786,7 +43453,20 @@ Get your API key from: ${colors.cyan}${url2}${colors.reset}`);
42786
43453
  validKey = true;
42787
43454
  }
42788
43455
  }
42789
- const models = provider === "opencode-zen" ? OPENCODE_ZEN_MODELS : OPENROUTER_MODELS;
43456
+ const config2 = loadConfig();
43457
+ if (provider === "cloudflare-ai-gateway" || provider === "workers-ai") {
43458
+ const existingAccountId = config2.cloudflareAccountId || process.env.CLOUDFLARE_ACCOUNT_ID || "";
43459
+ if (!existingAccountId) {
43460
+ const accountId = await question(`
43461
+ Cloudflare account ID: `);
43462
+ config2.cloudflareAccountId = accountId.trim();
43463
+ }
43464
+ }
43465
+ if (provider === "cloudflare-ai-gateway") {
43466
+ const gatewayId = await question(`Cloudflare AI Gateway ID [${config2.cloudflareAiGatewayId || "default"}]: `);
43467
+ config2.cloudflareAiGatewayId = gatewayId.trim() || config2.cloudflareAiGatewayId || "default";
43468
+ }
43469
+ const models = getProviderModels(provider);
42790
43470
  const freeModels = models.filter((m) => m.free);
42791
43471
  console.log(`
42792
43472
  Recommended models:`);
@@ -42799,13 +43479,12 @@ Recommended models:`);
42799
43479
  Choice [1]: `);
42800
43480
  const modelIndex = parseInt(modelChoice || "1") - 1;
42801
43481
  const selectedModel = displayModels[modelIndex] || displayModels[0];
42802
- const config2 = loadConfig();
42803
43482
  config2.provider = provider;
42804
43483
  config2.defaultModel = selectedModel.id;
42805
43484
  saveConfig(config2);
42806
43485
  console.log(`
42807
43486
  ${colors.green}\u2713 Setup complete!${colors.reset}`);
42808
- console.log(` Provider: ${provider === "opencode-zen" ? "OpenCode Zen" : "OpenRouter"}`);
43487
+ console.log(` Provider: ${getProviderDisplayName(provider)}`);
42809
43488
  console.log(` Model: ${selectedModel.name}`);
42810
43489
  console.log(`
42811
43490
  Try: ${colors.cyan}msh "list all files"${colors.reset}
@@ -42949,7 +43628,8 @@ async function translate(query, options) {
42949
43628
  const apiKey = await getApiKey(config2.provider);
42950
43629
  const customModel = await getCustomModel(config2.defaultModel);
42951
43630
  const builtInModel = ALL_MODELS.find((m) => m.id === config2.defaultModel);
42952
- const model = customModel || builtInModel || (config2.provider === "opencode-zen" ? OPENCODE_ZEN_MODELS[0] : OPENROUTER_MODELS[0]);
43631
+ const fallbackModels = getProviderModels(config2.provider);
43632
+ const model = customModel || builtInModel || fallbackModels[0] || OPENCODE_ZEN_MODELS[0];
42953
43633
  if (!customModel && !apiKey) {
42954
43634
  console.error(`${colors.red}Error: No API key configured.${colors.reset}`);
42955
43635
  console.error(`Run: ${colors.cyan}msh --setup${colors.reset}`);
@@ -42960,12 +43640,13 @@ async function translate(query, options) {
42960
43640
  const useRepoContext = options.repoContext ?? config2.repoContext ?? false;
42961
43641
  const spinner = createSpinner(`Translating with ${customModel ? customModel.name : model.name}`);
42962
43642
  try {
42963
- const command = await translateToCommand(apiKey, model, query, cwd, history, useRepoContext);
43643
+ const command = await translateToCommand(apiKey, model, query, cwd, history, useRepoContext, config2);
42964
43644
  spinner.stop();
42965
43645
  if (options.dryRun) {
42966
43646
  const safety = analyzeCommand(command, config2);
42967
43647
  console.log(`${colors.dim}Query:${colors.reset} ${query}`);
42968
43648
  console.log(`${colors.dim}Model:${colors.reset} ${model.name}`);
43649
+ console.log(`${colors.dim}Thinking:${colors.reset} ${config2.thinkingLevel}`);
42969
43650
  if (useRepoContext) {
42970
43651
  console.log(`${colors.dim}Project context:${colors.reset} enabled`);
42971
43652
  }
@@ -43128,14 +43809,15 @@ ${colors.bold}Custom Models${colors.reset}
43128
43809
  }
43129
43810
  if (args[0] === "--provider" && args[1]) {
43130
43811
  const provider = args[1];
43131
- if (provider !== "opencode-zen" && provider !== "openrouter") {
43812
+ const validProviders = ["opencode-zen", "openrouter", "vercel-ai-gateway", "cloudflare-ai-gateway", "workers-ai"];
43813
+ if (!validProviders.includes(provider)) {
43132
43814
  console.error(`${colors.error}Unknown provider: ${provider}${colors.reset}`);
43133
- console.error(`Valid providers: opencode-zen, openrouter`);
43815
+ console.error(`Valid providers: ${validProviders.join(", ")}`);
43134
43816
  process.exit(1);
43135
43817
  }
43136
43818
  const config2 = loadConfig();
43137
43819
  config2.provider = provider;
43138
- const models = provider === "opencode-zen" ? OPENCODE_ZEN_MODELS : OPENROUTER_MODELS;
43820
+ const models = getProviderModels(provider);
43139
43821
  const firstAvailable = models.find((m) => !m.disabled) || models[0];
43140
43822
  config2.defaultModel = firstAvailable.id;
43141
43823
  saveConfig(config2);
@@ -43199,6 +43881,19 @@ ${colors.bold}Available Themes${colors.reset}
43199
43881
  console.log(`${colors.success}\u2713 Safety level set to ${level}${colors.reset}`);
43200
43882
  return;
43201
43883
  }
43884
+ if (args[0] === "--thinking" && args[1]) {
43885
+ const level = args[1].toLowerCase();
43886
+ if (level !== "off" && level !== "low" && level !== "medium" && level !== "high") {
43887
+ console.error(`${colors.error}Unknown thinking level: ${level}${colors.reset}`);
43888
+ console.error(`Valid levels: off, low, medium, high`);
43889
+ process.exit(1);
43890
+ }
43891
+ const config2 = loadConfig();
43892
+ config2.thinkingLevel = level;
43893
+ saveConfig(config2);
43894
+ console.log(`${colors.success}\u2713 Thinking level set to ${level}${colors.reset}`);
43895
+ return;
43896
+ }
43202
43897
  let execute = false;
43203
43898
  let dryRun = false;
43204
43899
  let repoContext = undefined;