jbai-cli 1.1.0 → 1.1.1

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
@@ -152,12 +152,30 @@ jbai-gemini --model gemini-2.5-pro "Your question"
152
152
  | `jbai token set` | Set/update token |
153
153
  | `jbai test` | Test API connections |
154
154
  | `jbai models` | List all models |
155
+ | `jbai install` | Install all AI tools |
156
+ | `jbai install claude` | Install specific tool |
157
+ | `jbai doctor` | Check tool installation status |
155
158
  | `jbai env staging` | Use staging environment |
156
159
  | `jbai env production` | Use production environment |
157
160
 
158
- ## Prerequisites
161
+ ## Installing AI Tools
159
162
 
160
- Install the underlying tools you want to use:
163
+ jbai-cli can install the underlying tools for you:
164
+
165
+ ```bash
166
+ # Install all tools at once
167
+ jbai install
168
+
169
+ # Install specific tool
170
+ jbai install claude
171
+ jbai install codex
172
+ jbai install aider
173
+
174
+ # Check what's installed
175
+ jbai doctor
176
+ ```
177
+
178
+ ### Manual Installation
161
179
 
162
180
  | Tool | Install Command |
163
181
  |------|-----------------|
package/bin/jbai-aider.js CHANGED
@@ -49,7 +49,10 @@ const child = spawn('aider', aiderArgs, {
49
49
 
50
50
  child.on('error', (err) => {
51
51
  if (err.code === 'ENOENT') {
52
- console.error('❌ Aider not found. Install: pip install aider-chat');
52
+ const tool = config.TOOLS.aider;
53
+ console.error(`❌ ${tool.name} not found.\n`);
54
+ console.error(`Install with: ${tool.install}`);
55
+ console.error(`Or run: jbai install aider`);
53
56
  } else {
54
57
  console.error(`Error: ${err.message}`);
55
58
  }
@@ -47,7 +47,10 @@ const child = spawn('claude', finalArgs, {
47
47
 
48
48
  child.on('error', (err) => {
49
49
  if (err.code === 'ENOENT') {
50
- console.error('❌ Claude Code not found. Install: npm install -g @anthropic-ai/claude-code');
50
+ const tool = config.TOOLS.claude;
51
+ console.error(`❌ ${tool.name} not found.\n`);
52
+ console.error(`Install with: ${tool.install}`);
53
+ console.error(`Or run: jbai install claude`);
51
54
  } else {
52
55
  console.error(`Error: ${err.message}`);
53
56
  }
package/bin/jbai-codex.js CHANGED
@@ -82,7 +82,10 @@ const child = spawn('codex', finalArgs, {
82
82
 
83
83
  child.on('error', (err) => {
84
84
  if (err.code === 'ENOENT') {
85
- console.error('❌ Codex not found. Install: npm install -g @openai/codex');
85
+ const tool = config.TOOLS.codex;
86
+ console.error(`❌ ${tool.name} not found.\n`);
87
+ console.error(`Install with: ${tool.install}`);
88
+ console.error(`Or run: jbai install codex`);
86
89
  } else {
87
90
  console.error(`Error: ${err.message}`);
88
91
  }
@@ -48,7 +48,10 @@ const child = spawn('opencode', finalArgs, {
48
48
 
49
49
  child.on('error', (err) => {
50
50
  if (err.code === 'ENOENT') {
51
- console.error('❌ OpenCode not found. Install: go install github.com/opencode-ai/opencode@latest');
51
+ const tool = config.TOOLS.opencode;
52
+ console.error(`❌ ${tool.name} not found.\n`);
53
+ console.error(`Install with: ${tool.install}`);
54
+ console.error(`Or run: jbai install opencode`);
52
55
  } else {
53
56
  console.error(`Error: ${err.message}`);
54
57
  }
package/bin/jbai.js CHANGED
@@ -1,10 +1,37 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- const { spawn } = require('child_process');
3
+ const { spawn, execSync } = require('child_process');
4
4
  const readline = require('readline');
5
5
  const https = require('https');
6
6
  const config = require('../lib/config');
7
7
 
8
+ const TOOLS = {
9
+ claude: {
10
+ name: 'Claude Code',
11
+ command: 'claude',
12
+ install: 'npm install -g @anthropic-ai/claude-code',
13
+ check: 'claude --version'
14
+ },
15
+ codex: {
16
+ name: 'Codex CLI',
17
+ command: 'codex',
18
+ install: 'npm install -g @openai/codex',
19
+ check: 'codex --version'
20
+ },
21
+ aider: {
22
+ name: 'Aider',
23
+ command: 'aider',
24
+ install: 'pip install aider-chat',
25
+ check: 'aider --version'
26
+ },
27
+ opencode: {
28
+ name: 'OpenCode',
29
+ command: 'opencode',
30
+ install: 'go install github.com/opencode-ai/opencode@latest',
31
+ check: 'opencode --version'
32
+ }
33
+ };
34
+
8
35
  const VERSION = require('../package.json').version;
9
36
 
10
37
  const HELP = `
@@ -17,6 +44,9 @@ COMMANDS:
17
44
  jbai test Test all API endpoints
18
45
  jbai env [staging|production] Switch environment
19
46
  jbai models List available models
47
+ jbai install Install all AI tools (claude, codex, aider)
48
+ jbai install claude Install specific tool
49
+ jbai doctor Check which tools are installed
20
50
  jbai help Show this help
21
51
 
22
52
  TOOL WRAPPERS:
@@ -218,6 +248,131 @@ function setEnvironment(env) {
218
248
  console.log(` Token URL: ${config.ENDPOINTS[env].tokenUrl}`);
219
249
  }
220
250
 
251
+ function isToolInstalled(toolKey) {
252
+ const tool = TOOLS[toolKey];
253
+ if (!tool) return false;
254
+ try {
255
+ execSync(`which ${tool.command}`, { stdio: 'ignore' });
256
+ return true;
257
+ } catch {
258
+ return false;
259
+ }
260
+ }
261
+
262
+ function doctor() {
263
+ console.log('Tool Status:\n');
264
+
265
+ const token = config.getToken();
266
+ console.log(`Token: ${token ? '✅ Set' : '❌ Not set'}`);
267
+ if (token) {
268
+ console.log(`Environment: ${config.getEnvironment()}`);
269
+ console.log(`Expired: ${config.isTokenExpired(token) ? '⚠️ Yes' : '✅ No'}`);
270
+ }
271
+ console.log('');
272
+
273
+ for (const [key, tool] of Object.entries(TOOLS)) {
274
+ const installed = isToolInstalled(key);
275
+ const status = installed ? '✅' : '❌';
276
+ console.log(`${status} ${tool.name.padEnd(12)} ${installed ? 'Installed' : 'Not installed'}`);
277
+ if (!installed) {
278
+ console.log(` Install: ${tool.install}`);
279
+ }
280
+ }
281
+
282
+ console.log('\n✅ Gemini Built-in (no install needed)');
283
+ }
284
+
285
+ async function installTools(toolKey) {
286
+ const rl = readline.createInterface({
287
+ input: process.stdin,
288
+ output: process.stdout
289
+ });
290
+
291
+ const askConfirm = (question) => new Promise(resolve => {
292
+ rl.question(question, answer => resolve(answer.toLowerCase() === 'y' || answer === ''));
293
+ });
294
+
295
+ if (toolKey && toolKey !== 'all') {
296
+ // Install specific tool
297
+ const tool = TOOLS[toolKey];
298
+ if (!tool) {
299
+ console.log(`Unknown tool: ${toolKey}`);
300
+ console.log(`Available: ${Object.keys(TOOLS).join(', ')}`);
301
+ rl.close();
302
+ return;
303
+ }
304
+
305
+ if (isToolInstalled(toolKey)) {
306
+ console.log(`✅ ${tool.name} is already installed`);
307
+ rl.close();
308
+ return;
309
+ }
310
+
311
+ console.log(`Installing ${tool.name}...`);
312
+ console.log(`Running: ${tool.install}\n`);
313
+
314
+ try {
315
+ execSync(tool.install, { stdio: 'inherit' });
316
+ console.log(`\n✅ ${tool.name} installed successfully`);
317
+ } catch (e) {
318
+ console.log(`\n❌ Failed to install ${tool.name}`);
319
+ }
320
+ rl.close();
321
+ return;
322
+ }
323
+
324
+ // Install all tools
325
+ console.log('This will install the following tools:\n');
326
+
327
+ const toInstall = [];
328
+ for (const [key, tool] of Object.entries(TOOLS)) {
329
+ const installed = isToolInstalled(key);
330
+ if (installed) {
331
+ console.log(`✅ ${tool.name} - already installed`);
332
+ } else {
333
+ console.log(`📦 ${tool.name} - will install`);
334
+ console.log(` ${tool.install}`);
335
+ toInstall.push({ key, tool });
336
+ }
337
+ }
338
+
339
+ if (toInstall.length === 0) {
340
+ console.log('\n✅ All tools are already installed!');
341
+ rl.close();
342
+ return;
343
+ }
344
+
345
+ console.log('');
346
+ const confirm = await askConfirm(`Install ${toInstall.length} tool(s)? [Y/n] `);
347
+
348
+ if (!confirm) {
349
+ console.log('Cancelled');
350
+ rl.close();
351
+ return;
352
+ }
353
+
354
+ for (const { key, tool } of toInstall) {
355
+ console.log(`\n📦 Installing ${tool.name}...`);
356
+ console.log(`Running: ${tool.install}\n`);
357
+
358
+ try {
359
+ execSync(tool.install, { stdio: 'inherit' });
360
+ console.log(`✅ ${tool.name} installed`);
361
+ } catch (e) {
362
+ console.log(`❌ Failed to install ${tool.name}`);
363
+ const skip = await askConfirm('Continue with other tools? [Y/n] ');
364
+ if (!skip) {
365
+ rl.close();
366
+ return;
367
+ }
368
+ }
369
+ }
370
+
371
+ rl.close();
372
+ console.log('\n✅ Installation complete!');
373
+ console.log('Run: jbai doctor to verify');
374
+ }
375
+
221
376
  // Main
222
377
  const [,, command, ...args] = process.argv;
223
378
 
@@ -238,6 +393,13 @@ switch (command) {
238
393
  case 'env':
239
394
  setEnvironment(args[0]);
240
395
  break;
396
+ case 'install':
397
+ installTools(args[0]);
398
+ break;
399
+ case 'doctor':
400
+ case 'status':
401
+ doctor();
402
+ break;
241
403
  case 'help':
242
404
  case '--help':
243
405
  case '-h':
package/lib/config.js CHANGED
@@ -122,12 +122,36 @@ function isTokenExpired(token) {
122
122
  return expiry < new Date();
123
123
  }
124
124
 
125
+ const TOOLS = {
126
+ claude: {
127
+ name: 'Claude Code',
128
+ command: 'claude',
129
+ install: 'npm install -g @anthropic-ai/claude-code'
130
+ },
131
+ codex: {
132
+ name: 'Codex CLI',
133
+ command: 'codex',
134
+ install: 'npm install -g @openai/codex'
135
+ },
136
+ aider: {
137
+ name: 'Aider',
138
+ command: 'aider',
139
+ install: 'pip install aider-chat'
140
+ },
141
+ opencode: {
142
+ name: 'OpenCode',
143
+ command: 'opencode',
144
+ install: 'go install github.com/opencode-ai/opencode@latest'
145
+ }
146
+ };
147
+
125
148
  module.exports = {
126
149
  CONFIG_DIR,
127
150
  TOKEN_FILE,
128
151
  CONFIG_FILE,
129
152
  ENDPOINTS,
130
153
  MODELS,
154
+ TOOLS,
131
155
  ensureConfigDir,
132
156
  getToken,
133
157
  setToken,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jbai-cli",
3
- "version": "1.1.0",
3
+ "version": "1.1.1",
4
4
  "description": "CLI wrappers to use AI coding tools (Claude Code, Codex, Aider, Gemini) with JetBrains AI Platform",
5
5
  "keywords": [
6
6
  "jetbrains",