jbai-cli 1.4.0 → 1.5.0

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.
@@ -80,21 +80,6 @@ config.MODELS.openai.available.forEach(model => {
80
80
  };
81
81
  });
82
82
 
83
- // Add other provider models (DeepSeek, Mistral, Qwen, XAI, Meta) via OpenAI endpoint
84
- const otherModels = [
85
- ...config.MODELS.other.deepseek,
86
- ...config.MODELS.other.mistral,
87
- ...config.MODELS.other.qwen,
88
- ...config.MODELS.other.xai,
89
- ...config.MODELS.other.meta
90
- ];
91
- otherModels.forEach(model => {
92
- opencodeConfig.provider[providerName].models[model] = {
93
- name: model,
94
- limit: { context: 128000, output: 8192 }
95
- };
96
- });
97
-
98
83
  // Add JetBrains Anthropic provider for Claude models
99
84
  opencodeConfig.provider[anthropicProviderName] = {
100
85
  npm: '@ai-sdk/anthropic',
package/bin/jbai.js CHANGED
@@ -18,12 +18,6 @@ const TOOLS = {
18
18
  install: 'npm install -g @openai/codex',
19
19
  check: 'codex --version'
20
20
  },
21
- aider: {
22
- name: 'Aider',
23
- command: 'aider',
24
- install: 'pipx install aider-chat',
25
- check: 'aider --version'
26
- },
27
21
  gemini: {
28
22
  name: 'Gemini CLI',
29
23
  command: 'gemini',
@@ -50,7 +44,7 @@ COMMANDS:
50
44
  jbai test Test all API endpoints
51
45
  jbai env [staging|production] Switch environment
52
46
  jbai models List available models
53
- jbai install Install all AI tools (claude, codex, aider)
47
+ jbai install Install all AI tools (claude, codex, gemini, opencode)
54
48
  jbai install claude Install specific tool
55
49
  jbai doctor Check which tools are installed
56
50
  jbai help Show this help
@@ -58,7 +52,6 @@ COMMANDS:
58
52
  TOOL WRAPPERS:
59
53
  jbai-claude Launch Claude Code with JetBrains AI
60
54
  jbai-codex Launch Codex CLI with JetBrains AI
61
- jbai-aider Launch Aider with JetBrains AI
62
55
  jbai-gemini Launch Gemini CLI with JetBrains AI
63
56
  jbai-opencode Launch OpenCode with JetBrains AI
64
57
 
@@ -66,13 +59,13 @@ SUPER MODE:
66
59
  Add --super (or --yolo or -s) to skip confirmations:
67
60
  jbai-claude --super # Skip permission prompts
68
61
  jbai-codex --super # Full auto mode
69
- jbai-aider --super # Auto-confirm changes
62
+ jbai-gemini --super # Auto-confirm changes
70
63
 
71
64
  EXAMPLES:
72
65
  jbai token set # Set your token
73
66
  jbai-claude # Start Claude Code
74
67
  jbai-codex exec "explain code" # Run Codex task
75
- jbai-aider # Start Aider
68
+ jbai-gemini # Start Gemini CLI
76
69
 
77
70
  TOKEN:
78
71
  Get token: ${config.getEndpoints().tokenUrl}
@@ -227,7 +220,7 @@ function showModels() {
227
220
  console.log(` - ${m}${def}`);
228
221
  });
229
222
 
230
- console.log('\nGPT (OpenAI) - jbai-codex, jbai-aider:');
223
+ console.log('\nGPT (OpenAI) - jbai-codex, jbai-opencode:');
231
224
  config.MODELS.openai.available.forEach((m) => {
232
225
  const def = m === config.MODELS.openai.default ? ' (default)' : '';
233
226
  console.log(` - ${m}${def}`);
@@ -239,31 +232,13 @@ function showModels() {
239
232
  console.log(` - ${m}${def}`);
240
233
  });
241
234
 
242
- console.log('\nDeepSeek - jbai-aider, jbai-opencode:');
243
- config.MODELS.other.deepseek.forEach((m) => console.log(` - ${m}`));
244
-
245
- console.log('\nMistral - jbai-aider, jbai-opencode:');
246
- config.MODELS.other.mistral.forEach((m) => console.log(` - ${m}`));
247
-
248
- console.log('\nQwen - jbai-aider, jbai-opencode:');
249
- config.MODELS.other.qwen.forEach((m) => console.log(` - ${m}`));
250
-
251
- console.log('\nXAI (Grok) - jbai-aider, jbai-opencode:');
252
- config.MODELS.other.xai.forEach((m) => console.log(` - ${m}`));
253
-
254
- console.log('\nMeta (Llama) - jbai-aider, jbai-opencode:');
255
- config.MODELS.other.meta.forEach((m) => console.log(` - ${m}`));
256
-
257
235
  // Count total
258
236
  const total = config.MODELS.claude.available.length +
259
237
  config.MODELS.openai.available.length +
260
- config.MODELS.gemini.available.length +
261
- config.MODELS.other.deepseek.length +
262
- config.MODELS.other.mistral.length +
263
- config.MODELS.other.qwen.length +
264
- config.MODELS.other.xai.length +
265
- config.MODELS.other.meta.length;
238
+ config.MODELS.gemini.available.length;
266
239
  console.log(`\nTotal: ${total} models`);
240
+ console.log('\nNote: Other providers (DeepSeek, Mistral, Qwen, XAI, Meta) are available');
241
+ console.log('via Grazie native API but not via OpenAI-compatible CLI tools.');
267
242
  }
268
243
 
269
244
  function setEnvironment(env) {
@@ -0,0 +1,261 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * E2E Model Compatibility Testing Script
5
+ * Tests all configured Grazie models against the API endpoints
6
+ * to identify which models are valid and which return 404 or errors.
7
+ */
8
+
9
+ const https = require('https');
10
+ const config = require('../lib/config');
11
+
12
+ const token = config.getToken();
13
+ if (!token) {
14
+ console.error('❌ No token found. Run: jbai token set');
15
+ process.exit(1);
16
+ }
17
+
18
+ const endpoints = config.getEndpoints();
19
+
20
+ // Colors for terminal output
21
+ const colors = {
22
+ reset: '\x1b[0m',
23
+ green: '\x1b[32m',
24
+ red: '\x1b[31m',
25
+ yellow: '\x1b[33m',
26
+ cyan: '\x1b[36m',
27
+ dim: '\x1b[2m'
28
+ };
29
+
30
+ function httpPost(url, body, headers) {
31
+ return new Promise((resolve, reject) => {
32
+ const urlObj = new URL(url);
33
+ const data = JSON.stringify(body);
34
+
35
+ const req = https.request({
36
+ hostname: urlObj.hostname,
37
+ port: 443,
38
+ path: urlObj.pathname + urlObj.search,
39
+ method: 'POST',
40
+ headers: {
41
+ 'Content-Type': 'application/json',
42
+ 'Content-Length': Buffer.byteLength(data),
43
+ ...headers
44
+ },
45
+ timeout: 30000
46
+ }, (res) => {
47
+ let body = '';
48
+ res.on('data', chunk => body += chunk);
49
+ res.on('end', () => {
50
+ try {
51
+ const parsed = JSON.parse(body);
52
+ resolve({ status: res.statusCode, data: parsed });
53
+ } catch {
54
+ resolve({ status: res.statusCode, data: body, raw: true });
55
+ }
56
+ });
57
+ });
58
+
59
+ req.on('error', (e) => reject(e));
60
+ req.on('timeout', () => {
61
+ req.destroy();
62
+ reject(new Error('Timeout'));
63
+ });
64
+ req.write(data);
65
+ req.end();
66
+ });
67
+ }
68
+
69
+ async function testOpenAIModel(model) {
70
+ try {
71
+ // GPT-5.x and O-series models require max_completion_tokens instead of max_tokens
72
+ const needsCompletionTokens = model.startsWith('gpt-5') || model.startsWith('o1') ||
73
+ model.startsWith('o3') || model.startsWith('o4');
74
+
75
+ const bodyParams = needsCompletionTokens
76
+ ? { max_completion_tokens: 500 } // O-series needs more tokens for reasoning
77
+ : { max_tokens: 5 };
78
+
79
+ const result = await httpPost(
80
+ `${endpoints.openai}/chat/completions`,
81
+ {
82
+ model: model,
83
+ messages: [{ role: 'user', content: 'Say OK' }],
84
+ ...bodyParams
85
+ },
86
+ { 'Grazie-Authenticate-JWT': token }
87
+ );
88
+
89
+ if (result.status === 200 && result.data.choices) {
90
+ return { success: true, message: 'OK' };
91
+ } else if (result.status === 404) {
92
+ return { success: false, message: `404 Not Found`, error: result.data.error?.message || 'Model not found' };
93
+ } else if (result.status === 400) {
94
+ return { success: false, message: `400 Bad Request`, error: result.data.error?.message || 'Invalid request' };
95
+ } else {
96
+ return { success: false, message: `Status ${result.status}`, error: result.data.error?.message || JSON.stringify(result.data).substring(0, 100) };
97
+ }
98
+ } catch (e) {
99
+ return { success: false, message: 'Error', error: e.message };
100
+ }
101
+ }
102
+
103
+ async function testAnthropicModel(model) {
104
+ try {
105
+ const result = await httpPost(
106
+ `${endpoints.anthropic}/messages`,
107
+ {
108
+ model: model,
109
+ messages: [{ role: 'user', content: 'Say OK' }],
110
+ max_tokens: 10
111
+ },
112
+ {
113
+ 'Grazie-Authenticate-JWT': token,
114
+ 'anthropic-version': '2023-06-01'
115
+ }
116
+ );
117
+
118
+ if (result.status === 200 && result.data.content) {
119
+ return { success: true, message: 'OK' };
120
+ } else if (result.status === 404) {
121
+ return { success: false, message: `404 Not Found`, error: result.data.error?.message || 'Model not found' };
122
+ } else if (result.status === 400) {
123
+ return { success: false, message: `400 Bad Request`, error: result.data.error?.message || 'Invalid request' };
124
+ } else {
125
+ return { success: false, message: `Status ${result.status}`, error: result.data.error?.message || JSON.stringify(result.data).substring(0, 100) };
126
+ }
127
+ } catch (e) {
128
+ return { success: false, message: 'Error', error: e.message };
129
+ }
130
+ }
131
+
132
+ async function testGeminiModel(model) {
133
+ try {
134
+ // Gemini API format via Vertex AI proxy
135
+ const result = await httpPost(
136
+ `${endpoints.google}/v1/projects/default/locations/default/publishers/google/models/${model}:generateContent`,
137
+ {
138
+ contents: [{ role: 'user', parts: [{ text: 'Say OK' }] }]
139
+ },
140
+ { 'Grazie-Authenticate-JWT': token }
141
+ );
142
+
143
+ if (result.status === 200 && result.data.candidates) {
144
+ return { success: true, message: 'OK' };
145
+ } else if (result.status === 404) {
146
+ return { success: false, message: `404 Not Found`, error: result.data.error?.message || 'Model not found' };
147
+ } else if (result.status === 400) {
148
+ return { success: false, message: `400 Bad Request`, error: result.data.error?.message || 'Invalid request' };
149
+ } else {
150
+ return { success: false, message: `Status ${result.status}`, error: result.data.error?.message || JSON.stringify(result.data).substring(0, 100) };
151
+ }
152
+ } catch (e) {
153
+ return { success: false, message: 'Error', error: e.message };
154
+ }
155
+ }
156
+
157
+ async function runTests() {
158
+ console.log(`\n${'='.repeat(70)}`);
159
+ console.log(`${colors.cyan}JBAI-CLI E2E MODEL COMPATIBILITY TESTING${colors.reset}`);
160
+ console.log(`Environment: ${config.getEnvironment()}`);
161
+ console.log(`${'='.repeat(70)}\n`);
162
+
163
+ const results = {
164
+ openai: { working: [], failing: [] },
165
+ anthropic: { working: [], failing: [] },
166
+ gemini: { working: [], failing: [] }
167
+ };
168
+
169
+ // Test Claude models (Anthropic)
170
+ console.log(`${colors.cyan}Testing Claude models (jbai-claude)...${colors.reset}`);
171
+ console.log('-'.repeat(50));
172
+ for (const model of config.MODELS.claude.available) {
173
+ process.stdout.write(` ${model.padEnd(35)} `);
174
+ const result = await testAnthropicModel(model);
175
+ if (result.success) {
176
+ console.log(`${colors.green}✓ ${result.message}${colors.reset}`);
177
+ results.anthropic.working.push(model);
178
+ } else {
179
+ console.log(`${colors.red}✗ ${result.message}${colors.reset}`);
180
+ console.log(` ${colors.dim}${result.error}${colors.reset}`);
181
+ results.anthropic.failing.push({ model, error: result.error });
182
+ }
183
+ }
184
+
185
+ // Test OpenAI models (Codex, OpenCode)
186
+ console.log(`\n${colors.cyan}Testing OpenAI/GPT models (jbai-codex, jbai-opencode)...${colors.reset}`);
187
+ console.log('-'.repeat(50));
188
+ for (const model of config.MODELS.openai.available) {
189
+ process.stdout.write(` ${model.padEnd(35)} `);
190
+ const result = await testOpenAIModel(model);
191
+ if (result.success) {
192
+ console.log(`${colors.green}✓ ${result.message}${colors.reset}`);
193
+ results.openai.working.push(model);
194
+ } else {
195
+ console.log(`${colors.red}✗ ${result.message}${colors.reset}`);
196
+ console.log(` ${colors.dim}${result.error}${colors.reset}`);
197
+ results.openai.failing.push({ model, error: result.error });
198
+ }
199
+ }
200
+
201
+ // Test Gemini models
202
+ console.log(`\n${colors.cyan}Testing Gemini models (jbai-gemini)...${colors.reset}`);
203
+ console.log('-'.repeat(50));
204
+ for (const model of config.MODELS.gemini.available) {
205
+ process.stdout.write(` ${model.padEnd(35)} `);
206
+ const result = await testGeminiModel(model);
207
+ if (result.success) {
208
+ console.log(`${colors.green}✓ ${result.message}${colors.reset}`);
209
+ results.gemini.working.push(model);
210
+ } else {
211
+ console.log(`${colors.red}✗ ${result.message}${colors.reset}`);
212
+ console.log(` ${colors.dim}${result.error}${colors.reset}`);
213
+ results.gemini.failing.push({ model, error: result.error });
214
+ }
215
+ }
216
+
217
+ // Summary
218
+ console.log(`\n${'='.repeat(70)}`);
219
+ console.log(`${colors.cyan}SUMMARY${colors.reset}`);
220
+ console.log(`${'='.repeat(70)}`);
221
+
222
+ const totalWorking = results.anthropic.working.length + results.openai.working.length +
223
+ results.gemini.working.length;
224
+ const totalFailing = results.anthropic.failing.length + results.openai.failing.length +
225
+ results.gemini.failing.length;
226
+
227
+ console.log(`\n${colors.green}Working Models: ${totalWorking}${colors.reset}`);
228
+ console.log(`${colors.red}Failing Models: ${totalFailing}${colors.reset}`);
229
+
230
+ console.log(`\n${colors.cyan}By Provider:${colors.reset}`);
231
+ console.log(` Claude (Anthropic): ${colors.green}${results.anthropic.working.length}${colors.reset} working, ${colors.red}${results.anthropic.failing.length}${colors.reset} failing`);
232
+ console.log(` OpenAI/GPT: ${colors.green}${results.openai.working.length}${colors.reset} working, ${colors.red}${results.openai.failing.length}${colors.reset} failing`);
233
+ console.log(` Gemini (Google): ${colors.green}${results.gemini.working.length}${colors.reset} working, ${colors.red}${results.gemini.failing.length}${colors.reset} failing`);
234
+
235
+ if (totalFailing > 0) {
236
+ console.log(`\n${colors.red}FAILING MODELS TO REMOVE:${colors.reset}`);
237
+
238
+ if (results.anthropic.failing.length > 0) {
239
+ console.log(`\n Claude models:`);
240
+ results.anthropic.failing.forEach(f => console.log(` - ${f.model}`));
241
+ }
242
+ if (results.openai.failing.length > 0) {
243
+ console.log(`\n OpenAI models:`);
244
+ results.openai.failing.forEach(f => console.log(` - ${f.model}`));
245
+ }
246
+ if (results.gemini.failing.length > 0) {
247
+ console.log(`\n Gemini models:`);
248
+ results.gemini.failing.forEach(f => console.log(` - ${f.model}`));
249
+ }
250
+ } else {
251
+ console.log(`\n${colors.green}All models are working correctly!${colors.reset}`);
252
+ }
253
+
254
+ console.log(`\n${'='.repeat(70)}\n`);
255
+
256
+ // Return results for programmatic use
257
+ return results;
258
+ }
259
+
260
+ // Run tests
261
+ runTests().catch(console.error);
package/lib/config.js CHANGED
@@ -26,91 +26,76 @@ const ENDPOINTS = {
26
26
  };
27
27
 
28
28
  // All models available from JetBrains AI Platform (Grazie)
29
- // Model names are mapped to SDK-compatible format
29
+ // Model names must match EXACTLY what the Grazie API accepts
30
+ // Run 'node bin/test-models.js' to verify model availability
30
31
  const MODELS = {
31
32
  claude: {
32
33
  default: 'claude-sonnet-4-5-20250929',
33
34
  available: [
34
- // Claude 4.x series (latest)
35
- 'claude-opus-4-5-20250929',
35
+ // Claude 4.5 series (latest)
36
+ 'claude-opus-4-5-20251101',
36
37
  'claude-sonnet-4-5-20250929',
37
- 'claude-haiku-4-5-20250929',
38
+ 'claude-haiku-4-5-20251001',
39
+ // Claude 4.x series
38
40
  'claude-opus-4-1-20250805',
39
41
  'claude-opus-4-20250514',
40
42
  'claude-sonnet-4-20250514',
41
43
  // Claude 3.x series
42
44
  'claude-3-7-sonnet-20250219',
43
- 'claude-3-5-sonnet-20241022',
44
- 'claude-3-5-haiku-20241022',
45
- 'claude-3-haiku-20240307'
45
+ 'claude-3-5-haiku-20241022'
46
46
  ]
47
47
  },
48
48
  openai: {
49
- default: 'gpt-4o',
49
+ default: 'gpt-4o-2024-11-20',
50
50
  available: [
51
- // GPT-5.x series (latest)
52
- 'gpt-5',
53
- 'gpt-5.1',
51
+ // GPT-5.x series (latest) - require date-versioned names
52
+ 'gpt-5.2-2025-12-11',
54
53
  'gpt-5.2',
55
- 'gpt-5-mini',
56
- 'gpt-5-nano',
57
- 'gpt-5-codex',
58
- 'gpt-5.1-codex',
59
- 'gpt-5.1-codex-max',
60
- 'gpt-5.1-codex-mini',
61
- 'gpt-5.2-codex',
62
- 'gpt-5.2-pro',
54
+ 'gpt-5.1-2025-11-13',
55
+ 'gpt-5-2025-08-07',
56
+ 'gpt-5-mini-2025-08-07',
57
+ 'gpt-5-nano-2025-08-07',
63
58
  // GPT-4.x series
64
- 'gpt-4.1',
65
- 'gpt-4.1-mini',
66
- 'gpt-4.1-nano',
67
- 'gpt-4o',
68
- 'gpt-4o-mini',
69
- 'gpt-4-turbo',
70
- 'gpt-4',
71
- // O-series (reasoning)
72
- 'o1',
73
- 'o3',
74
- 'o3-mini',
75
- 'o4-mini'
59
+ 'gpt-4.1-2025-04-14',
60
+ 'gpt-4.1-mini-2025-04-14',
61
+ 'gpt-4.1-nano-2025-04-14',
62
+ 'gpt-4o-2024-11-20',
63
+ 'gpt-4o-mini-2024-07-18',
64
+ 'gpt-4-turbo-2024-04-09',
65
+ 'gpt-4-0613',
66
+ 'gpt-3.5-turbo-0125',
67
+ // O-series (reasoning) - use max_completion_tokens instead of max_tokens
68
+ 'o4-mini-2025-04-16',
69
+ 'o3-2025-04-16',
70
+ 'o3-mini-2025-01-31',
71
+ 'o1-2024-12-17'
76
72
  ]
77
73
  },
78
74
  gemini: {
79
75
  default: 'gemini-2.5-flash',
80
76
  available: [
81
- // Gemini 3.x (latest)
82
- 'gemini-3.0-pro',
83
- 'gemini-3.0-flash',
84
- // Gemini 2.x
77
+ // Gemini 3.x (preview)
78
+ 'gemini-3-pro-preview',
79
+ 'gemini-3-flash-preview',
80
+ // Gemini 2.5
85
81
  'gemini-2.5-pro',
86
82
  'gemini-2.5-flash',
87
83
  'gemini-2.5-flash-lite',
88
- 'gemini-2.0-flash',
89
- 'gemini-2.0-flash-lite'
84
+ // Gemini 2.0
85
+ 'gemini-2.0-flash-001',
86
+ 'gemini-2.0-flash-lite-001'
90
87
  ]
91
- },
92
- // Other providers available via Grazie
93
- other: {
94
- deepseek: ['deepseek-r1'],
95
- mistral: ['mistral-large', 'mistral-small', 'mistral-codestral', 'mistral-open-7b', 'mixtral-open-8x7b', 'mixtral-open-8x22b'],
96
- qwen: ['qwen-max', 'qwen-max-longcontext', 'qwen-plus', 'qwen-turbo'],
97
- xai: ['xai-grok-4', 'xai-grok-4-fast', 'xai-grok-4-1-fast', 'xai-grok-code-fast-1'],
98
- meta: ['grazie-chat-llama-v3-8b-instruct']
99
88
  }
89
+ // NOTE: Other providers (DeepSeek, Mistral, Qwen, XAI, Meta) are available
90
+ // via Grazie native Chat API but NOT via the OpenAI-compatible proxy.
91
+ // They are not supported by CLI tools that use OpenAI API format.
100
92
  };
101
93
 
102
- // All models for tools that support multiple providers (like Aider, OpenCode)
94
+ // All models for tools that support multiple providers (OpenCode, Codex)
103
95
  const ALL_MODELS = {
104
96
  openai: MODELS.openai.available,
105
97
  anthropic: MODELS.claude.available,
106
- gemini: MODELS.gemini.available,
107
- other: [
108
- ...MODELS.other.deepseek,
109
- ...MODELS.other.mistral,
110
- ...MODELS.other.qwen,
111
- ...MODELS.other.xai,
112
- ...MODELS.other.meta
113
- ]
98
+ gemini: MODELS.gemini.available
114
99
  };
115
100
 
116
101
  function ensureConfigDir() {
@@ -190,11 +175,6 @@ const TOOLS = {
190
175
  command: 'codex',
191
176
  install: 'npm install -g @openai/codex'
192
177
  },
193
- aider: {
194
- name: 'Aider',
195
- command: 'aider',
196
- install: 'brew install aider'
197
- },
198
178
  gemini: {
199
179
  name: 'Gemini CLI',
200
180
  command: 'gemini',
package/package.json CHANGED
@@ -1,13 +1,12 @@
1
1
  {
2
2
  "name": "jbai-cli",
3
- "version": "1.4.0",
4
- "description": "CLI wrappers to use AI coding tools (Claude Code, Codex, Aider, Gemini CLI, OpenCode) with JetBrains AI Platform",
3
+ "version": "1.5.0",
4
+ "description": "CLI wrappers to use AI coding tools (Claude Code, Codex, Gemini CLI, OpenCode) with JetBrains AI Platform",
5
5
  "keywords": [
6
6
  "jetbrains",
7
7
  "ai",
8
8
  "claude",
9
9
  "codex",
10
- "aider",
11
10
  "gemini",
12
11
  "opencode",
13
12
  "cli",
@@ -29,7 +28,6 @@
29
28
  "jbai": "./bin/jbai.js",
30
29
  "jbai-claude": "./bin/jbai-claude.js",
31
30
  "jbai-codex": "./bin/jbai-codex.js",
32
- "jbai-aider": "./bin/jbai-aider.js",
33
31
  "jbai-gemini": "./bin/jbai-gemini.js",
34
32
  "jbai-opencode": "./bin/jbai-opencode.js"
35
33
  },
@@ -41,9 +39,7 @@
41
39
  "engines": {
42
40
  "node": ">=18.0.0"
43
41
  },
44
- "dependencies": {
45
- "yaml": "^2.7.1"
46
- },
42
+ "dependencies": {},
47
43
  "scripts": {
48
44
  "postinstall": "node lib/postinstall.js",
49
45
  "test": "node bin/jbai.js test"
package/bin/jbai-aider.js DELETED
@@ -1,94 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- const { spawn } = require('child_process');
4
- const fs = require('fs');
5
- const path = require('path');
6
- const os = require('os');
7
- const yaml = require('yaml');
8
- const config = require('../lib/config');
9
-
10
- const token = config.getToken();
11
- if (!token) {
12
- console.error('❌ No token found. Run: jbai token set');
13
- process.exit(1);
14
- }
15
-
16
- if (config.isTokenExpired(token)) {
17
- console.error('⚠️ Token expired. Run: jbai token refresh');
18
- process.exit(1);
19
- }
20
-
21
- const endpoints = config.getEndpoints();
22
- const environment = config.getEnvironment();
23
- let args = process.argv.slice(2);
24
-
25
- // Check for super mode (--super, --yolo, -s)
26
- const superFlags = ['--super', '--yolo', '-s'];
27
- const superMode = args.some(a => superFlags.includes(a));
28
- args = args.filter(a => !superFlags.includes(a));
29
-
30
- // Create model settings file with extra headers for JetBrains authentication
31
- const configDir = path.join(os.homedir(), '.jbai');
32
- const modelSettingsFile = path.join(configDir, 'aider-model-settings.yml');
33
-
34
- // Ensure config directory exists
35
- if (!fs.existsSync(configDir)) {
36
- fs.mkdirSync(configDir, { recursive: true, mode: 0o700 });
37
- }
38
-
39
- // Create model settings with extra_headers for authentication
40
- // Use aider/extra_params for global settings that apply to all models
41
- const modelSettings = [
42
- {
43
- name: 'aider/extra_params',
44
- extra_params: {
45
- extra_headers: {
46
- 'Grazie-Authenticate-JWT': token
47
- }
48
- }
49
- }
50
- ];
51
-
52
- // Write model settings file
53
- fs.writeFileSync(modelSettingsFile, yaml.stringify(modelSettings), { mode: 0o600 });
54
-
55
- // Build aider arguments
56
- // Note: --no-stream is required because JetBrains proxy has stream_options issues
57
- const hasModel = args.includes('--model');
58
- const aiderArgs = [
59
- '--openai-api-base', endpoints.openai,
60
- '--openai-api-key', 'placeholder',
61
- '--model-settings-file', modelSettingsFile,
62
- '--no-stream'
63
- ];
64
-
65
- if (!hasModel) {
66
- aiderArgs.push('--model', config.MODELS.openai.default);
67
- }
68
-
69
- // Add super mode flags (auto-confirm all)
70
- if (superMode) {
71
- aiderArgs.push('--yes');
72
- console.log('🚀 Super mode: --yes (auto-confirm) enabled');
73
- }
74
-
75
- aiderArgs.push(...args);
76
-
77
- const child = spawn('aider', aiderArgs, {
78
- stdio: 'inherit',
79
- env: process.env
80
- });
81
-
82
- child.on('error', (err) => {
83
- if (err.code === 'ENOENT') {
84
- const tool = config.TOOLS.aider;
85
- console.error(`❌ ${tool.name} not found.\n`);
86
- console.error(`Install with: ${tool.install}`);
87
- console.error(`Or run: jbai install aider`);
88
- } else {
89
- console.error(`Error: ${err.message}`);
90
- }
91
- process.exit(1);
92
- });
93
-
94
- child.on('exit', (code) => process.exit(code || 0));