jbai-cli 1.3.1 → 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.
File without changes
@@ -54,12 +54,14 @@ if (!opencodeConfig.provider) {
54
54
  // Environment variable name for the token
55
55
  const envVarName = environment === 'staging' ? 'GRAZIE_STAGING_TOKEN' : 'GRAZIE_API_TOKEN';
56
56
 
57
- // Add/update JetBrains provider with custom header (using env var reference)
57
+ // Provider names for OpenAI and Anthropic
58
+ const anthropicProviderName = environment === 'staging' ? 'jbai-anthropic-staging' : 'jbai-anthropic';
59
+
60
+ // Add/update JetBrains OpenAI provider with custom header (using env var reference)
58
61
  // Use openai-compatible SDK which properly sends custom headers
59
- // Point to OpenAI endpoint for compatibility
60
62
  opencodeConfig.provider[providerName] = {
61
63
  npm: '@ai-sdk/openai-compatible',
62
- name: `JetBrains AI (${environment})`,
64
+ name: `JetBrains AI OpenAI (${environment})`,
63
65
  options: {
64
66
  baseURL: endpoints.openai,
65
67
  apiKey: `{env:${envVarName}}`,
@@ -70,15 +72,33 @@ opencodeConfig.provider[providerName] = {
70
72
  models: {}
71
73
  };
72
74
 
73
- // Add OpenAI models (since we use openai-compatible SDK)
74
- // Set context and output limits to avoid "max_tokens too large" errors
75
+ // Add OpenAI models
75
76
  config.MODELS.openai.available.forEach(model => {
76
77
  opencodeConfig.provider[providerName].models[model] = {
77
78
  name: model,
78
- limit: {
79
- context: 128000,
80
- output: 8192
79
+ limit: { context: 128000, output: 8192 }
80
+ };
81
+ });
82
+
83
+ // Add JetBrains Anthropic provider for Claude models
84
+ opencodeConfig.provider[anthropicProviderName] = {
85
+ npm: '@ai-sdk/anthropic',
86
+ name: `JetBrains AI Anthropic (${environment})`,
87
+ options: {
88
+ baseURL: endpoints.anthropic,
89
+ apiKey: `{env:${envVarName}}`,
90
+ headers: {
91
+ 'Grazie-Authenticate-JWT': `{env:${envVarName}}`
81
92
  }
93
+ },
94
+ models: {}
95
+ };
96
+
97
+ // Add Claude models to Anthropic provider
98
+ config.MODELS.claude.available.forEach(model => {
99
+ opencodeConfig.provider[anthropicProviderName].models[model] = {
100
+ name: model,
101
+ limit: { context: 200000, output: 8192 }
82
102
  };
83
103
  });
84
104
 
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}
@@ -219,25 +212,33 @@ function httpPost(url, body, headers) {
219
212
  }
220
213
 
221
214
  function showModels() {
222
- console.log('Available Models:\n');
215
+ console.log('Available Models via JetBrains AI Platform (Grazie):\n');
223
216
 
224
- console.log('Claude (Anthropic):');
225
- config.MODELS.claude.available.forEach((m, i) => {
217
+ console.log('Claude (Anthropic) - jbai-claude:');
218
+ config.MODELS.claude.available.forEach((m) => {
226
219
  const def = m === config.MODELS.claude.default ? ' (default)' : '';
227
220
  console.log(` - ${m}${def}`);
228
221
  });
229
222
 
230
- console.log('\nGPT (OpenAI):');
231
- config.MODELS.openai.available.forEach((m, i) => {
223
+ console.log('\nGPT (OpenAI) - jbai-codex, jbai-opencode:');
224
+ config.MODELS.openai.available.forEach((m) => {
232
225
  const def = m === config.MODELS.openai.default ? ' (default)' : '';
233
226
  console.log(` - ${m}${def}`);
234
227
  });
235
228
 
236
- console.log('\nGemini (Google):');
237
- config.MODELS.gemini.available.forEach((m, i) => {
229
+ console.log('\nGemini (Google) - jbai-gemini:');
230
+ config.MODELS.gemini.available.forEach((m) => {
238
231
  const def = m === config.MODELS.gemini.default ? ' (default)' : '';
239
232
  console.log(` - ${m}${def}`);
240
233
  });
234
+
235
+ // Count total
236
+ const total = config.MODELS.claude.available.length +
237
+ config.MODELS.openai.available.length +
238
+ config.MODELS.gemini.available.length;
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.');
241
242
  }
242
243
 
243
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
@@ -12,6 +12,7 @@ const ENDPOINTS = {
12
12
  openai: 'https://api.stgn.jetbrains.ai/user/v5/llm/openai/v1',
13
13
  anthropic: 'https://api.stgn.jetbrains.ai/user/v5/llm/anthropic/v1',
14
14
  google: 'https://api.stgn.jetbrains.ai/user/v5/llm/google/v1/vertex',
15
+ profiles: 'https://api.stgn.jetbrains.ai/user/v5/llm/profiles',
15
16
  tokenUrl: 'https://platform.stgn.jetbrains.ai/'
16
17
  },
17
18
  production: {
@@ -19,17 +20,27 @@ const ENDPOINTS = {
19
20
  openai: 'https://api.jetbrains.ai/user/v5/llm/openai/v1',
20
21
  anthropic: 'https://api.jetbrains.ai/user/v5/llm/anthropic/v1',
21
22
  google: 'https://api.jetbrains.ai/user/v5/llm/google/v1/vertex',
23
+ profiles: 'https://api.jetbrains.ai/user/v5/llm/profiles',
22
24
  tokenUrl: 'https://platform.jetbrains.ai/'
23
25
  }
24
26
  };
25
27
 
28
+ // All models available from JetBrains AI Platform (Grazie)
29
+ // Model names must match EXACTLY what the Grazie API accepts
30
+ // Run 'node bin/test-models.js' to verify model availability
26
31
  const MODELS = {
27
32
  claude: {
28
33
  default: 'claude-sonnet-4-5-20250929',
29
34
  available: [
35
+ // Claude 4.5 series (latest)
36
+ 'claude-opus-4-5-20251101',
30
37
  'claude-sonnet-4-5-20250929',
38
+ 'claude-haiku-4-5-20251001',
39
+ // Claude 4.x series
31
40
  'claude-opus-4-1-20250805',
41
+ 'claude-opus-4-20250514',
32
42
  'claude-sonnet-4-20250514',
43
+ // Claude 3.x series
33
44
  'claude-3-7-sonnet-20250219',
34
45
  'claude-3-5-haiku-20241022'
35
46
  ]
@@ -37,23 +48,54 @@ const MODELS = {
37
48
  openai: {
38
49
  default: 'gpt-4o-2024-11-20',
39
50
  available: [
40
- 'gpt-4o-2024-11-20',
41
- 'gpt-5-2025-08-07',
51
+ // GPT-5.x series (latest) - require date-versioned names
52
+ 'gpt-5.2-2025-12-11',
53
+ 'gpt-5.2',
42
54
  'gpt-5.1-2025-11-13',
55
+ 'gpt-5-2025-08-07',
43
56
  'gpt-5-mini-2025-08-07',
57
+ 'gpt-5-nano-2025-08-07',
58
+ // GPT-4.x series
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',
44
69
  'o3-2025-04-16',
45
- 'o3-mini-2025-01-31'
70
+ 'o3-mini-2025-01-31',
71
+ 'o1-2024-12-17'
46
72
  ]
47
73
  },
48
74
  gemini: {
49
75
  default: 'gemini-2.5-flash',
50
76
  available: [
51
- 'gemini-2.5-flash',
52
- 'gemini-2.5-pro',
77
+ // Gemini 3.x (preview)
53
78
  'gemini-3-pro-preview',
54
- 'gemini-3-flash-preview'
79
+ 'gemini-3-flash-preview',
80
+ // Gemini 2.5
81
+ 'gemini-2.5-pro',
82
+ 'gemini-2.5-flash',
83
+ 'gemini-2.5-flash-lite',
84
+ // Gemini 2.0
85
+ 'gemini-2.0-flash-001',
86
+ 'gemini-2.0-flash-lite-001'
55
87
  ]
56
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.
92
+ };
93
+
94
+ // All models for tools that support multiple providers (OpenCode, Codex)
95
+ const ALL_MODELS = {
96
+ openai: MODELS.openai.available,
97
+ anthropic: MODELS.claude.available,
98
+ gemini: MODELS.gemini.available
57
99
  };
58
100
 
59
101
  function ensureConfigDir() {
@@ -133,11 +175,6 @@ const TOOLS = {
133
175
  command: 'codex',
134
176
  install: 'npm install -g @openai/codex'
135
177
  },
136
- aider: {
137
- name: 'Aider',
138
- command: 'aider',
139
- install: 'pipx install aider-chat'
140
- },
141
178
  gemini: {
142
179
  name: 'Gemini CLI',
143
180
  command: 'gemini',
@@ -156,6 +193,7 @@ module.exports = {
156
193
  CONFIG_FILE,
157
194
  ENDPOINTS,
158
195
  MODELS,
196
+ ALL_MODELS,
159
197
  TOOLS,
160
198
  ensureConfigDir,
161
199
  getToken,
package/package.json CHANGED
@@ -1,13 +1,12 @@
1
1
  {
2
2
  "name": "jbai-cli",
3
- "version": "1.3.1",
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));