@kamel-ahmed/proxy-claude 1.0.4 → 1.0.6

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 CHANGED
@@ -4,12 +4,9 @@
4
4
  [![npm downloads](https://img.shields.io/npm/dm/@kamel-ahmed/proxy-claude.svg)](https://www.npmjs.com/package/@kamel-ahmed/proxy-claude)
5
5
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
6
6
 
7
- <a href="https://buymeacoffee.com/badrinarayanans" target="_blank"><img src="https://cdn.buymeacoffee.com/buttons/v2/default-yellow.png" alt="Buy Me A Coffee" height="50"></a>
8
7
 
9
8
  A proxy server that exposes an **Anthropic-compatible API** backed by **Antigravity's Cloud Code**, letting you use Claude and Gemini models with **Claude Code CLI**.
10
9
 
11
- ![Antigravity Claude Proxy Banner](images/banner.png)
12
-
13
10
  ## How It Works
14
11
 
15
12
  ```
@@ -28,65 +25,234 @@ A proxy server that exposes an **Anthropic-compatible API** backed by **Antigrav
28
25
 
29
26
  ## Prerequisites
30
27
 
31
- - **Node.js** 18 or later
32
- - **Antigravity** installed (for single-account mode) OR Google account(s) for multi-account mode
28
+ - **Node.js** 18 or later (download from [nodejs.org](https://nodejs.org))
29
+ - **Claude Code CLI** (installed automatically by setup wizard)
30
+ - Google account(s) for authentication
33
31
 
34
32
  ---
35
33
 
36
34
  ## Installation
37
35
 
38
- ### Automated Setup (Recommended)
36
+ ### Windows Installation
37
+
38
+ **Step 1: Install Node.js**
39
+
40
+ 1. Download Node.js 18+ from [nodejs.org](https://nodejs.org)
41
+ 2. Run the installer and follow the setup wizard
42
+ 3. Restart your computer (or just close & reopen PowerShell)
43
+ 4. Verify installation in PowerShell:
44
+ ```powershell
45
+ node --version
46
+ npm --version
47
+ ```
48
+
49
+ **Step 2: Install proxy-claude**
50
+
51
+ Open PowerShell or Command Prompt and run:
52
+
53
+ ```powershell
54
+ npm install -g @kamel-ahmed/proxy-claude
55
+ proxy-claude init
56
+ ```
57
+
58
+ **Step 3: Complete Setup Wizard**
59
+
60
+ The wizard will:
61
+ - ✅ Check Node.js and Claude Code CLI
62
+ - ✅ Add your Google account(s)
63
+ - ✅ Pick models for each tier
64
+ - ✅ Auto-configure settings
39
65
 
40
- Run the setup command to automatically install Claude Code CLI and create a global `proxy-claude` command:
66
+ **Step 4: Start Using**
67
+
68
+ ```powershell
69
+ proxy-claude
70
+ ```
71
+
72
+ That's it! Claude Code will launch connected to the proxy.
73
+
74
+ ---
75
+
76
+ ### macOS/Linux Installation
77
+
78
+ **Step 1: Install Node.js** (if not already installed)
79
+
80
+ ```bash
81
+ # macOS with Homebrew
82
+ brew install node
83
+
84
+ # Or download from https://nodejs.org
85
+ ```
86
+
87
+ **Step 2: Install proxy-claude**
41
88
 
42
89
  ```bash
43
- # Install globally (recommended)
44
90
  npm install -g @kamel-ahmed/proxy-claude
45
- proxy-claude setup
91
+ proxy-claude init
92
+ ```
46
93
 
47
- # Or run via npx
48
- npx @kamel-ahmed/proxy-claude setup
94
+ **Step 3: Start Using**
49
95
 
50
- # If cloned locally
51
- npm run setup
96
+ ```bash
97
+ proxy-claude
98
+ ```
99
+
100
+ ---
101
+
102
+ ### Quick Install (Recommended)
103
+
104
+ ```bash
105
+ # Install globally
106
+ npm install -g @kamel-ahmed/proxy-claude
107
+
108
+ # Run setup wizard
109
+ proxy-claude init
110
+ ```
111
+
112
+ The setup wizard will:
113
+ 1. ✅ Check prerequisites (Node.js, Claude Code CLI)
114
+ 2. ✅ Help you add Google account(s)
115
+ 3. ✅ Let you pick models for each tier (Opus, Sonnet, Haiku)
116
+ 4. ✅ Auto-configure `~/.claude/settings.json`
117
+
118
+ After setup, just run:
119
+
120
+ ```bash
121
+ proxy-claude
52
122
  ```
53
123
 
54
- After setup completes, you can run Claude with the proxy from anywhere:
124
+ This will:
125
+ 1. Start the proxy server in the background
126
+ 2. Wait for the server to be ready
127
+ 3. Launch Claude Code CLI connected to the proxy
128
+ 4. Automatically shut down the proxy when you exit
129
+
130
+ ---
131
+
132
+ ### Quick Install (All Platforms)
133
+
134
+ ```bash
135
+ # Install globally
136
+ npm install -g @kamel-ahmed/proxy-claude
137
+
138
+ # Run setup wizard
139
+ proxy-claude init
140
+ ```
141
+
142
+ The setup wizard will:
143
+ 1. ✅ Check prerequisites (Node.js, Claude Code CLI)
144
+ 2. ✅ Help you add Google account(s)
145
+ 3. ✅ Let you pick models for each tier (Opus, Sonnet, Haiku)
146
+ 4. ✅ Auto-configure `~/.claude/settings.json`
147
+
148
+ After setup, just run:
55
149
 
56
150
  ```bash
57
151
  proxy-claude
58
152
  ```
59
153
 
60
- The `proxy-claude` command will:
61
- 1. Start the proxy server in the background.
62
- 2. Wait for the server to be ready.
63
- 3. Launch `claude` (Claude Code CLI) connected to the proxy.
64
- 4. Automatically shut down the proxy when you exit Claude.
154
+ This will:
155
+ 1. Start the proxy server in the background
156
+ 2. Wait for the server to be ready
157
+ 3. Launch Claude Code CLI connected to the proxy
158
+ 4. Automatically shut down the proxy when you exit
159
+
160
+ ---
161
+
162
+ ## Troubleshooting
163
+
164
+ ### Windows: "npm: The term 'npm' is not recognized"
165
+
166
+ **Solution:** Node.js wasn't installed correctly or PowerShell needs to be restarted.
167
+
168
+ 1. Download and reinstall Node.js from [nodejs.org](https://nodejs.org)
169
+ 2. Close PowerShell/Command Prompt completely
170
+ 3. Reopen PowerShell as Administrator
171
+ 4. Try again: `npm --version`
172
+
173
+ ### Windows: "proxy-claude: The term 'proxy-claude' is not recognized"
174
+
175
+ **Solution:** npm install path isn't in your PATH environment variable.
176
+
177
+ ```powershell
178
+ # Find where npm installed it
179
+ npm config get prefix
180
+
181
+ # Add to PATH (replace C:\Users\YourUsername\AppData\Roaming\npm if different):
182
+ $env:Path += ";C:\Users\$env:USERNAME\AppData\Roaming\npm"
183
+ ```
184
+
185
+ Then close and reopen PowerShell.
186
+
187
+ ### Port Already in Use
65
188
 
66
- You can also customize the port and pass arguments to Claude:
189
+ If port 8080 is already in use, specify a different port:
67
190
 
68
191
  ```bash
69
- # Use a custom port
70
192
  PORT=3000 proxy-claude
193
+ # or
194
+ proxy-claude --port 3000
195
+ ```
196
+
197
+ ### "Claude Code CLI not found" Error
71
198
 
72
- # Pass arguments to Claude
73
- proxy-claude --model sonnet
199
+ The setup wizard will automatically install Claude Code CLI for you. If it fails:
200
+
201
+ ```bash
202
+ npm install -g @anthropic-ai/claude-code
74
203
  ```
75
204
 
76
- > **Note:** The setup requires write access to `/usr/local/bin`. If prompted, enter your password to allow installation.
205
+ ### Settings Not Persisting
77
206
 
78
- ### Option 1: npm (Manual)
207
+ The wizard auto-configures `~/.claude/settings.json`. You can verify it was created:
208
+
209
+ **Windows:**
210
+ ```powershell
211
+ notepad "$env:USERPROFILE\.claude\settings.json"
212
+ ```
79
213
 
214
+ **macOS/Linux:**
80
215
  ```bash
81
- # Run directly with npx (no install needed)
82
- npx @kamel-ahmed/proxy-claude start
216
+ cat ~/.claude/settings.json
217
+ ```
83
218
 
84
- # Or install globally
85
- npm install -g @kamel-ahmed/proxy-claude
86
- proxy-claude start
219
+ ---
220
+
221
+ ### CLI Commands
222
+
223
+ ```bash
224
+ proxy-claude # Start proxy + Claude Code (default)
225
+ proxy-claude init # Run setup wizard
226
+ proxy-claude start # Start proxy server only
227
+ proxy-claude stop # Stop proxy server
228
+ proxy-claude status # Check if proxy is running
229
+ proxy-claude accounts # Manage Google accounts
230
+ proxy-claude refresh # Refresh account tokens
231
+ proxy-claude --help # Show all commands
232
+ ```
233
+
234
+ Custom port:
235
+
236
+ ```bash
237
+ PORT=3000 proxy-claude
238
+ proxy-claude --port 3000
239
+ ```
240
+
241
+ ### Cross-Platform Support
242
+
243
+ Works on **Windows**, **macOS**, and **Linux** with full feature parity.
244
+
245
+ ### Alternative: npx (No Install)
246
+
247
+ ```bash
248
+ # Run directly without installing
249
+ npx @kamel-ahmed/proxy-claude
250
+
251
+ # Or just start the server
252
+ npx @kamel-ahmed/proxy-claude start
87
253
  ```
88
254
 
89
- ### Option 2: Clone Repository
255
+ ### Development: Clone Repository
90
256
 
91
257
  ```bash
92
258
  git clone https://github.com/badri-s2001/antigravity-claude-proxy.git
@@ -99,22 +265,23 @@ npm start
99
265
 
100
266
  ## Quick Start
101
267
 
102
- ### 1. Start the Proxy Server
268
+ If you used `proxy-claude init`, you're already set up! Just run:
103
269
 
104
270
  ```bash
105
- # If installed via npm
106
- proxy-claude start
271
+ proxy-claude
272
+ ```
107
273
 
108
- # If using npx
109
- npx @kamel-ahmed/proxy-claude start
274
+ ### Manual Setup (Alternative)
110
275
 
111
- # If cloned locally
112
- npm start
276
+ #### 1. Start the Proxy Server
277
+
278
+ ```bash
279
+ proxy-claude start
113
280
  ```
114
281
 
115
282
  The server runs on `http://localhost:8080` by default.
116
283
 
117
- ### 2. Link Account(s)
284
+ #### 2. Link Account(s)
118
285
 
119
286
  Choose one of the following methods to authorize the proxy:
120
287
 
@@ -616,8 +783,4 @@ This project is based on insights and code from:
616
783
 
617
784
  MIT
618
785
 
619
- ---
620
-
621
- ## Star History
622
-
623
- [![Star History Chart](https://api.star-history.com/svg?repos=badrisnarayanan/antigravity-claude-proxy&type=date&legend=top-left&cache-control=no-cache)](https://www.star-history.com/#badrisnarayanan/antigravity-claude-proxy&type=date&legend=top-left)
786
+ ---
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@kamel-ahmed/proxy-claude",
3
- "version": "1.0.4",
4
- "description": "Proxy server to use Antigravity's Claude models with Claude Code CLI - run 'proxy-claude' to start",
3
+ "version": "1.0.6",
4
+ "description": "Cross-platform CLI proxy for Antigravity Cloud Code. Use Claude & Gemini models with Claude Code CLI on Windows, macOS, and Linux.",
5
5
  "main": "src/index.js",
6
6
  "type": "module",
7
7
  "bin": {
@@ -45,17 +45,22 @@
45
45
  "anthropic",
46
46
  "antigravity",
47
47
  "proxy",
48
- "vertex-ai"
48
+ "gemini",
49
+ "claude-code",
50
+ "cross-platform",
51
+ "windows",
52
+ "macos",
53
+ "linux"
49
54
  ],
50
- "author": "Kamel Ahmed",
55
+ "author": "Kamel Ahmed <kamel.ahmed.mostafa.kamel@gmail.com>",
51
56
  "license": "MIT",
52
57
  "repository": {
53
58
  "type": "git",
54
- "url": "git+https://github.com/kamel-ahmed/proxy-claude.git"
59
+ "url": "git+https://github.com/KamelAhmed01/antigravity-claude-proxy.git"
55
60
  },
56
- "homepage": "https://github.com/kamel-ahmed/proxy-claude#readme",
61
+ "homepage": "https://github.com/KamelAhmed01/antigravity-claude-proxy#readme",
57
62
  "bugs": {
58
- "url": "https://github.com/kamel-ahmed/proxy-claude/issues"
63
+ "url": "https://github.com/KamelAhmed01/antigravity-claude-proxy/issues"
59
64
  },
60
65
  "publishConfig": {
61
66
  "access": "public"
@@ -95,7 +95,7 @@ function openBrowser(url) {
95
95
  args = [url];
96
96
  } else if (platform === 'win32') {
97
97
  command = 'cmd';
98
- args = ['/c', 'start', '', url];
98
+ args = ['/c', 'start', '', url.replace(/&/g, '^&')];
99
99
  } else {
100
100
  command = 'xdg-open';
101
101
  args = [url];
@@ -50,41 +50,36 @@ const ACCOUNTS_FILE = path.join(CONFIG_DIR, 'accounts.json');
50
50
  const CLAUDE_CONFIG_DIR = path.join(PLATFORM.homeDir, '.claude');
51
51
  const CLAUDE_SETTINGS_FILE = path.join(CLAUDE_CONFIG_DIR, 'settings.json');
52
52
 
53
- // Default model configurations
54
- const MODEL_PRESETS = {
55
- claude: {
56
- name: 'Claude Models (Recommended)',
57
- description: 'Best for coding tasks with extended thinking',
58
- models: {
59
- ANTHROPIC_MODEL: 'claude-sonnet-4-5-thinking',
60
- ANTHROPIC_DEFAULT_OPUS_MODEL: 'claude-opus-4-5-thinking',
61
- ANTHROPIC_DEFAULT_SONNET_MODEL: 'claude-sonnet-4-5-thinking',
62
- ANTHROPIC_DEFAULT_HAIKU_MODEL: 'gemini-2.5-flash-lite',
63
- CLAUDE_CODE_SUBAGENT_MODEL: 'claude-sonnet-4-5-thinking',
64
- }
53
+ // All available models in Antigravity (fetched dynamically, but this is a fallback)
54
+ const ALL_MODELS = [
55
+ // Claude models
56
+ { id: 'claude-opus-4-5-thinking', family: 'claude', tier: 'opus', description: 'Claude Opus 4.5 with thinking' },
57
+ { id: 'claude-sonnet-4-5-thinking', family: 'claude', tier: 'sonnet', description: 'Claude Sonnet 4.5 with thinking' },
58
+ { id: 'claude-sonnet-4-5', family: 'claude', tier: 'sonnet', description: 'Claude Sonnet 4.5' },
59
+ // Gemini models
60
+ { id: 'gemini-3-pro-high', family: 'gemini', tier: 'opus', description: 'Gemini 3 Pro High (best quality)' },
61
+ { id: 'gemini-3-pro-low', family: 'gemini', tier: 'sonnet', description: 'Gemini 3 Pro Low' },
62
+ { id: 'gemini-3-flash', family: 'gemini', tier: 'sonnet', description: 'Gemini 3 Flash (fast)' },
63
+ { id: 'gemini-2.5-flash-lite', family: 'gemini', tier: 'haiku', description: 'Gemini 2.5 Flash Lite (fastest)' },
64
+ ];
65
+
66
+ // Model tier descriptions
67
+ const TIER_INFO = {
68
+ opus: {
69
+ name: 'Opus (Primary)',
70
+ description: 'Main model for complex tasks',
71
+ envKey: 'ANTHROPIC_DEFAULT_OPUS_MODEL',
65
72
  },
66
- gemini: {
67
- name: 'Gemini Models',
68
- description: 'Google\'s Gemini models with thinking support',
69
- models: {
70
- ANTHROPIC_MODEL: 'gemini-3-pro-high',
71
- ANTHROPIC_DEFAULT_OPUS_MODEL: 'gemini-3-pro-high',
72
- ANTHROPIC_DEFAULT_SONNET_MODEL: 'gemini-3-flash',
73
- ANTHROPIC_DEFAULT_HAIKU_MODEL: 'gemini-2.5-flash-lite',
74
- CLAUDE_CODE_SUBAGENT_MODEL: 'gemini-3-flash',
75
- }
73
+ sonnet: {
74
+ name: 'Sonnet (Default)',
75
+ description: 'Balanced model for most tasks',
76
+ envKey: 'ANTHROPIC_DEFAULT_SONNET_MODEL',
77
+ },
78
+ haiku: {
79
+ name: 'Haiku (Fast)',
80
+ description: 'Quick model for simple tasks & background',
81
+ envKey: 'ANTHROPIC_DEFAULT_HAIKU_MODEL',
76
82
  },
77
- balanced: {
78
- name: 'Balanced (Claude + Gemini)',
79
- description: 'Claude for main tasks, Gemini for background',
80
- models: {
81
- ANTHROPIC_MODEL: 'claude-sonnet-4-5-thinking',
82
- ANTHROPIC_DEFAULT_OPUS_MODEL: 'claude-opus-4-5-thinking',
83
- ANTHROPIC_DEFAULT_SONNET_MODEL: 'claude-sonnet-4-5-thinking',
84
- ANTHROPIC_DEFAULT_HAIKU_MODEL: 'gemini-2.5-flash-lite',
85
- CLAUDE_CODE_SUBAGENT_MODEL: 'gemini-3-flash',
86
- }
87
- }
88
83
  };
89
84
 
90
85
  /**
@@ -215,6 +210,65 @@ function getExistingAccounts() {
215
210
  return [];
216
211
  }
217
212
 
213
+ /**
214
+ * Fetch available models from the API using account token
215
+ */
216
+ async function fetchAvailableModels(accounts) {
217
+ if (!accounts || accounts.length === 0) {
218
+ return ALL_MODELS;
219
+ }
220
+
221
+ try {
222
+ // Get token from first account
223
+ const account = accounts[0];
224
+ const token = account.accessToken;
225
+
226
+ if (!token) {
227
+ return ALL_MODELS;
228
+ }
229
+
230
+ // Import the model API
231
+ const { fetchAvailableModels: fetchModels } = await import('../cloudcode/model-api.js');
232
+ const data = await fetchModels(token);
233
+
234
+ if (data && data.models) {
235
+ const models = [];
236
+ for (const [modelId, modelData] of Object.entries(data.models)) {
237
+ // Only include Claude and Gemini models
238
+ if (!modelId.includes('claude') && !modelId.includes('gemini')) continue;
239
+
240
+ // Determine family
241
+ const family = modelId.includes('claude') ? 'claude' : 'gemini';
242
+
243
+ // Determine tier based on model name
244
+ let tier = 'sonnet';
245
+ if (modelId.includes('opus') || modelId.includes('pro-high')) tier = 'opus';
246
+ else if (modelId.includes('haiku') || modelId.includes('flash-lite')) tier = 'haiku';
247
+
248
+ // Check if model has quota (remaining > 0)
249
+ const hasQuota = modelData.remainingFraction === undefined || modelData.remainingFraction > 0;
250
+
251
+ models.push({
252
+ id: modelId,
253
+ family,
254
+ tier,
255
+ description: modelData.displayName || modelId,
256
+ hasQuota,
257
+ remainingFraction: modelData.remainingFraction,
258
+ });
259
+ }
260
+
261
+ if (models.length > 0) {
262
+ return models;
263
+ }
264
+ }
265
+ } catch (error) {
266
+ print(`Could not fetch models from API: ${error.message}`, 'warn');
267
+ }
268
+
269
+ return ALL_MODELS;
270
+ }
271
+
218
272
  /**
219
273
  * Add Google account via OAuth
220
274
  */
@@ -260,9 +314,69 @@ function saveClaudeSettings(settings) {
260
314
  }
261
315
 
262
316
  /**
263
- * Configure Claude Code settings
317
+ * Select a model for a specific tier
318
+ */
319
+ async function selectModelForTier(rl, tier, availableModels) {
320
+ const tierInfo = TIER_INFO[tier];
321
+ console.log('');
322
+ console.log(`${COLORS.bold}${tierInfo.name}${COLORS.reset} - ${COLORS.dim}${tierInfo.description}${COLORS.reset}`);
323
+ console.log('');
324
+
325
+ // Filter models that are suitable for this tier or higher
326
+ // opus can use any model, sonnet can use sonnet/haiku, haiku uses haiku
327
+ const tierPriority = { opus: 3, sonnet: 2, haiku: 1 };
328
+ const minTier = tierPriority[tier];
329
+
330
+ const suitableModels = availableModels.filter(m => {
331
+ const modelTier = tierPriority[m.tier] || 2;
332
+ return modelTier >= minTier - 1; // Allow one tier lower
333
+ });
334
+
335
+ // Sort: models with quota first, then by family (claude first), then by tier
336
+ suitableModels.sort((a, b) => {
337
+ // Quota status
338
+ if (a.hasQuota !== b.hasQuota) return a.hasQuota ? -1 : 1;
339
+ // Family (claude first for opus/sonnet, gemini first for haiku)
340
+ if (tier === 'haiku') {
341
+ if (a.family !== b.family) return a.family === 'gemini' ? -1 : 1;
342
+ } else {
343
+ if (a.family !== b.family) return a.family === 'claude' ? -1 : 1;
344
+ }
345
+ // Tier priority
346
+ return (tierPriority[b.tier] || 0) - (tierPriority[a.tier] || 0);
347
+ });
348
+
349
+ // Display models
350
+ console.log(`${COLORS.dim}Available models:${COLORS.reset}`);
351
+ suitableModels.forEach((model, index) => {
352
+ const quotaStatus = model.hasQuota === false
353
+ ? `${COLORS.red}(no quota)${COLORS.reset}`
354
+ : model.remainingFraction !== undefined
355
+ ? `${COLORS.green}(${Math.round(model.remainingFraction * 100)}% quota)${COLORS.reset}`
356
+ : '';
357
+ const familyBadge = model.family === 'claude'
358
+ ? `${COLORS.magenta}[Claude]${COLORS.reset}`
359
+ : `${COLORS.blue}[Gemini]${COLORS.reset}`;
360
+ console.log(` ${COLORS.cyan}${index + 1}.${COLORS.reset} ${model.id} ${familyBadge} ${quotaStatus}`);
361
+ });
362
+ console.log('');
363
+
364
+ // Default to first model with quota
365
+ const defaultIndex = suitableModels.findIndex(m => m.hasQuota !== false) + 1 || 1;
366
+
367
+ const choice = await prompt(rl, `Select model for ${tier} (1-${suitableModels.length})`, String(defaultIndex));
368
+ const index = parseInt(choice, 10) - 1;
369
+
370
+ if (index >= 0 && index < suitableModels.length) {
371
+ return suitableModels[index].id;
372
+ }
373
+ return suitableModels[0]?.id || ALL_MODELS.find(m => m.tier === tier)?.id;
374
+ }
375
+
376
+ /**
377
+ * Configure Claude Code settings with selected models
264
378
  */
265
- function configureClaudeSettings(modelPreset, port = 8080) {
379
+ function configureClaudeSettingsWithModels(modelConfig, port = 8080) {
266
380
  const existing = loadClaudeSettings();
267
381
 
268
382
  const newSettings = {
@@ -271,7 +385,11 @@ function configureClaudeSettings(modelPreset, port = 8080) {
271
385
  ...(existing.env || {}),
272
386
  ANTHROPIC_AUTH_TOKEN: 'proxy-claude',
273
387
  ANTHROPIC_BASE_URL: `http://localhost:${port}`,
274
- ...modelPreset.models,
388
+ ANTHROPIC_MODEL: modelConfig.sonnet, // Default model is sonnet
389
+ ANTHROPIC_DEFAULT_OPUS_MODEL: modelConfig.opus,
390
+ ANTHROPIC_DEFAULT_SONNET_MODEL: modelConfig.sonnet,
391
+ ANTHROPIC_DEFAULT_HAIKU_MODEL: modelConfig.haiku,
392
+ CLAUDE_CODE_SUBAGENT_MODEL: modelConfig.haiku, // Subagent uses haiku for efficiency
275
393
  ENABLE_EXPERIMENTAL_MCP_CLI: 'true',
276
394
  }
277
395
  };
@@ -286,33 +404,9 @@ function configureClaudeSettings(modelPreset, port = 8080) {
286
404
  }
287
405
 
288
406
  /**
289
- * Display model selection menu
407
+ * Print summary with selected models
290
408
  */
291
- async function selectModelPreset(rl) {
292
- console.log('');
293
- console.log(`${COLORS.bold}Available model configurations:${COLORS.reset}`);
294
- console.log('');
295
-
296
- const presets = Object.entries(MODEL_PRESETS);
297
- presets.forEach(([key, preset], index) => {
298
- console.log(` ${COLORS.cyan}${index + 1}.${COLORS.reset} ${COLORS.bold}${preset.name}${COLORS.reset}`);
299
- console.log(` ${COLORS.dim}${preset.description}${COLORS.reset}`);
300
- });
301
- console.log('');
302
-
303
- const choice = await prompt(rl, 'Select configuration (1-3)', '1');
304
- const index = parseInt(choice, 10) - 1;
305
-
306
- if (index >= 0 && index < presets.length) {
307
- return presets[index];
308
- }
309
- return presets[0]; // Default to first option
310
- }
311
-
312
- /**
313
- * Print summary
314
- */
315
- function printSummary(accounts, modelPreset, port) {
409
+ function printSummary(accounts, modelConfig, port) {
316
410
  console.log('');
317
411
  console.log(`${COLORS.green}╔══════════════════════════════════════════════════════════╗${COLORS.reset}`);
318
412
  console.log(`${COLORS.green}║${COLORS.reset} ${COLORS.bold}${COLORS.green}Setup Complete!${COLORS.reset} ${COLORS.green}║${COLORS.reset}`);
@@ -321,7 +415,9 @@ function printSummary(accounts, modelPreset, port) {
321
415
 
322
416
  console.log(`${COLORS.bold}Configuration Summary:${COLORS.reset}`);
323
417
  console.log(` ${COLORS.dim}•${COLORS.reset} Accounts: ${accounts.length} configured`);
324
- console.log(` ${COLORS.dim}•${COLORS.reset} Model preset: ${modelPreset[1].name}`);
418
+ console.log(` ${COLORS.dim}•${COLORS.reset} Opus model: ${COLORS.cyan}${modelConfig.opus}${COLORS.reset}`);
419
+ console.log(` ${COLORS.dim}•${COLORS.reset} Sonnet model: ${COLORS.cyan}${modelConfig.sonnet}${COLORS.reset}`);
420
+ console.log(` ${COLORS.dim}•${COLORS.reset} Haiku model: ${COLORS.cyan}${modelConfig.haiku}${COLORS.reset}`);
325
421
  console.log(` ${COLORS.dim}•${COLORS.reset} Proxy port: ${port}`);
326
422
  console.log(` ${COLORS.dim}•${COLORS.reset} Settings saved to: ${CLAUDE_SETTINGS_FILE}`);
327
423
  console.log('');
@@ -422,11 +518,26 @@ export async function runOnboarding(options = {}) {
422
518
  // Step 3: Model Configuration
423
519
  printStep(++currentStep, totalSteps, 'Model Configuration');
424
520
 
425
- print('Select which AI models to use with Claude Code.', 'info');
426
- print(`${COLORS.dim}(Haiku model uses Gemini to preserve Claude quota)${COLORS.reset}`, 'info');
521
+ print('Fetching available models from your account...', 'step');
522
+ const availableModels = await fetchAvailableModels(accounts);
523
+ print(`Found ${availableModels.length} models available`, 'success');
524
+
525
+ console.log('');
526
+ print('Now select a model for each tier. Models with quota are shown first.', 'info');
527
+ print(`${COLORS.dim}Tip: Use Gemini for Haiku to save your Claude quota!${COLORS.reset}`, 'info');
528
+
529
+ // Select model for each tier
530
+ const modelConfig = {
531
+ opus: await selectModelForTier(rl, 'opus', availableModels),
532
+ sonnet: await selectModelForTier(rl, 'sonnet', availableModels),
533
+ haiku: await selectModelForTier(rl, 'haiku', availableModels),
534
+ };
427
535
 
428
- const modelPreset = await selectModelPreset(rl);
429
- print(`Selected: ${modelPreset[1].name}`, 'success');
536
+ console.log('');
537
+ print('Model configuration:', 'success');
538
+ console.log(` ${COLORS.dim}Opus:${COLORS.reset} ${COLORS.cyan}${modelConfig.opus}${COLORS.reset}`);
539
+ console.log(` ${COLORS.dim}Sonnet:${COLORS.reset} ${COLORS.cyan}${modelConfig.sonnet}${COLORS.reset}`);
540
+ console.log(` ${COLORS.dim}Haiku:${COLORS.reset} ${COLORS.cyan}${modelConfig.haiku}${COLORS.reset}`);
430
541
 
431
542
  // Step 4: Apply Configuration
432
543
  printStep(++currentStep, totalSteps, 'Applying Configuration');
@@ -435,11 +546,11 @@ export async function runOnboarding(options = {}) {
435
546
 
436
547
  // Configure Claude Code settings
437
548
  print('Configuring Claude Code settings...', 'step');
438
- configureClaudeSettings(modelPreset[1], port);
549
+ configureClaudeSettingsWithModels(modelConfig, port);
439
550
  print(`Settings saved to ${CLAUDE_SETTINGS_FILE}`, 'success');
440
551
 
441
552
  // Print summary
442
- printSummary(accounts, modelPreset, port);
553
+ printSummary(accounts, modelConfig, port);
443
554
 
444
555
  rl.close();
445
556
  return true;