@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.
- package/README.md +14 -9
- package/dist/cli.js +640 -183
- package/dist/index.js +1119 -424
- package/dist/tui.js +640 -183
- 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: "
|
|
2355
|
+
category: "smart",
|
|
2207
2356
|
provider: "opencode-zen",
|
|
2208
2357
|
contextLength: 196608,
|
|
2209
2358
|
free: true
|
|
2210
2359
|
},
|
|
2211
2360
|
{
|
|
2212
|
-
id: "
|
|
2213
|
-
name: "
|
|
2214
|
-
description: "
|
|
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:
|
|
2375
|
+
contextLength: 131072,
|
|
2218
2376
|
free: true
|
|
2219
2377
|
},
|
|
2220
2378
|
{
|
|
2221
|
-
id: "
|
|
2222
|
-
name: "
|
|
2223
|
-
description: "
|
|
2224
|
-
category: "
|
|
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:
|
|
2384
|
+
contextLength: 131072,
|
|
2227
2385
|
free: true
|
|
2228
2386
|
},
|
|
2229
2387
|
{
|
|
2230
|
-
id: "
|
|
2231
|
-
name: "
|
|
2232
|
-
description: "
|
|
2233
|
-
category: "
|
|
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:
|
|
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
|
|
2408
|
+
description: "OpenAI's free lightweight GPT model",
|
|
2241
2409
|
category: "fast",
|
|
2242
2410
|
provider: "opencode-zen",
|
|
2243
|
-
contextLength:
|
|
2411
|
+
contextLength: 400000,
|
|
2244
2412
|
free: true
|
|
2245
2413
|
},
|
|
2246
2414
|
{
|
|
2247
|
-
id: "
|
|
2248
|
-
name: "
|
|
2249
|
-
description: "
|
|
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:
|
|
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.
|
|
2272
|
-
name: "GPT 5.
|
|
2273
|
-
description: "OpenAI's fast
|
|
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:
|
|
2444
|
+
contextLength: 400000
|
|
2277
2445
|
},
|
|
2278
2446
|
{
|
|
2279
|
-
id: "
|
|
2280
|
-
name: "
|
|
2281
|
-
description: "
|
|
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:
|
|
2452
|
+
contextLength: 400000
|
|
2285
2453
|
},
|
|
2286
2454
|
{
|
|
2287
|
-
id: "claude-sonnet-4",
|
|
2288
|
-
name: "Claude Sonnet 4",
|
|
2289
|
-
description: "Anthropic's
|
|
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:
|
|
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.
|
|
2304
|
-
name: "GPT 5.
|
|
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:
|
|
2476
|
+
contextLength: 1050000
|
|
2325
2477
|
},
|
|
2326
2478
|
{
|
|
2327
|
-
id: "gpt-5.
|
|
2328
|
-
name: "GPT 5.
|
|
2329
|
-
description: "OpenAI's
|
|
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:
|
|
2484
|
+
contextLength: 1050000
|
|
2333
2485
|
},
|
|
2334
2486
|
{
|
|
2335
|
-
id: "gpt-5",
|
|
2336
|
-
name: "GPT 5",
|
|
2337
|
-
description: "OpenAI's
|
|
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:
|
|
2492
|
+
contextLength: 400000
|
|
2341
2493
|
},
|
|
2342
2494
|
{
|
|
2343
|
-
id: "gpt-5-codex",
|
|
2344
|
-
name: "GPT 5 Codex",
|
|
2345
|
-
description: "OpenAI's
|
|
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:
|
|
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-
|
|
2392
|
-
name: "Claude
|
|
2393
|
-
description: "Anthropic's
|
|
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:
|
|
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 = [
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
|
3068
|
+
const keychainKey = getKeychainKey(provider);
|
|
2874
3069
|
const stored = await setSecret(keychainKey, key);
|
|
2875
3070
|
if (!stored) {
|
|
2876
|
-
|
|
2877
|
-
|
|
2878
|
-
|
|
2879
|
-
|
|
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: "
|
|
41647
|
+
category: "smart",
|
|
41274
41648
|
provider: "opencode-zen",
|
|
41275
41649
|
contextLength: 196608,
|
|
41276
41650
|
free: true
|
|
41277
41651
|
},
|
|
41278
41652
|
{
|
|
41279
|
-
id: "
|
|
41280
|
-
name: "
|
|
41281
|
-
description: "
|
|
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:
|
|
41667
|
+
contextLength: 131072,
|
|
41285
41668
|
free: true
|
|
41286
41669
|
},
|
|
41287
41670
|
{
|
|
41288
|
-
id: "
|
|
41289
|
-
name: "
|
|
41290
|
-
description: "
|
|
41291
|
-
category: "
|
|
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:
|
|
41676
|
+
contextLength: 131072,
|
|
41294
41677
|
free: true
|
|
41295
41678
|
},
|
|
41296
41679
|
{
|
|
41297
|
-
id: "
|
|
41298
|
-
name: "
|
|
41299
|
-
description: "
|
|
41300
|
-
category: "
|
|
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:
|
|
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
|
|
41700
|
+
description: "OpenAI's free lightweight GPT model",
|
|
41308
41701
|
category: "fast",
|
|
41309
41702
|
provider: "opencode-zen",
|
|
41310
|
-
contextLength:
|
|
41703
|
+
contextLength: 400000,
|
|
41311
41704
|
free: true
|
|
41312
41705
|
},
|
|
41313
41706
|
{
|
|
41314
|
-
id: "
|
|
41315
|
-
name: "
|
|
41316
|
-
description: "
|
|
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:
|
|
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.
|
|
41339
|
-
name: "GPT 5.
|
|
41340
|
-
description: "OpenAI's fast
|
|
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:
|
|
41736
|
+
contextLength: 400000
|
|
41344
41737
|
},
|
|
41345
41738
|
{
|
|
41346
|
-
id: "
|
|
41347
|
-
name: "
|
|
41348
|
-
description: "
|
|
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:
|
|
41744
|
+
contextLength: 400000
|
|
41352
41745
|
},
|
|
41353
41746
|
{
|
|
41354
|
-
id: "claude-sonnet-4",
|
|
41355
|
-
name: "Claude Sonnet 4",
|
|
41356
|
-
description: "Anthropic's
|
|
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:
|
|
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.
|
|
41371
|
-
name: "GPT 5.
|
|
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:
|
|
41768
|
+
contextLength: 1050000
|
|
41376
41769
|
},
|
|
41377
41770
|
{
|
|
41378
|
-
id: "gpt-5.
|
|
41379
|
-
name: "GPT 5.
|
|
41380
|
-
description: "OpenAI's
|
|
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:
|
|
41776
|
+
contextLength: 1050000
|
|
41384
41777
|
},
|
|
41385
41778
|
{
|
|
41386
|
-
id: "gpt-5.
|
|
41387
|
-
name: "GPT 5.
|
|
41388
|
-
description: "OpenAI's
|
|
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:
|
|
41784
|
+
contextLength: 400000
|
|
41392
41785
|
},
|
|
41393
41786
|
{
|
|
41394
|
-
id: "gpt-5.
|
|
41395
|
-
name: "GPT 5.
|
|
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:
|
|
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-
|
|
41459
|
-
name: "Claude
|
|
41460
|
-
description: "Anthropic's
|
|
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:
|
|
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 = [
|
|
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
|
|
41514
|
-
import { homedir as
|
|
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 =
|
|
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 (
|
|
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
|
|
41712
|
-
import { join as
|
|
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 (
|
|
42299
|
+
if (existsSync4(join3(cwd, ".git"))) {
|
|
41719
42300
|
context2.hasGit = true;
|
|
41720
42301
|
detected = true;
|
|
41721
42302
|
}
|
|
41722
|
-
if (
|
|
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 =
|
|
41727
|
-
if (
|
|
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(
|
|
41732
|
-
if (
|
|
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 (
|
|
42315
|
+
} else if (existsSync4(join3(cwd, "pnpm-lock.yaml"))) {
|
|
41735
42316
|
context2.packageManager = "pnpm";
|
|
41736
|
-
} else if (
|
|
42317
|
+
} else if (existsSync4(join3(cwd, "yarn.lock"))) {
|
|
41737
42318
|
context2.packageManager = "yarn";
|
|
41738
|
-
} else if (
|
|
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 =
|
|
41750
|
-
if (
|
|
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 =
|
|
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 (
|
|
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 (
|
|
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 (
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
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:
|
|
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
|
|
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;
|