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 +20 -2
- package/bin/jbai-aider.js +4 -1
- package/bin/jbai-claude.js +4 -1
- package/bin/jbai-codex.js +4 -1
- package/bin/jbai-opencode.js +4 -1
- package/bin/jbai.js +163 -1
- package/lib/config.js +24 -0
- package/package.json +1 -1
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
|
-
##
|
|
161
|
+
## Installing AI Tools
|
|
159
162
|
|
|
160
|
-
|
|
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
|
-
|
|
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
|
}
|
package/bin/jbai-claude.js
CHANGED
|
@@ -47,7 +47,10 @@ const child = spawn('claude', finalArgs, {
|
|
|
47
47
|
|
|
48
48
|
child.on('error', (err) => {
|
|
49
49
|
if (err.code === 'ENOENT') {
|
|
50
|
-
|
|
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
|
-
|
|
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
|
}
|
package/bin/jbai-opencode.js
CHANGED
|
@@ -48,7 +48,10 @@ const child = spawn('opencode', finalArgs, {
|
|
|
48
48
|
|
|
49
49
|
child.on('error', (err) => {
|
|
50
50
|
if (err.code === 'ENOENT') {
|
|
51
|
-
|
|
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,
|