jbai-cli 1.9.1 → 1.9.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 +1 -1
- package/bin/jbai-claude.js +16 -9
- package/bin/jbai-codex.js +12 -39
- package/bin/jbai-continue.js +27 -43
- package/bin/jbai-council.js +665 -0
- package/bin/jbai-gemini.js +17 -6
- package/bin/jbai-goose.js +11 -39
- package/bin/jbai-opencode.js +122 -20
- package/bin/jbai-proxy.js +1129 -64
- package/bin/jbai.js +77 -41
- package/bin/test-cli-tictactoe.js +279 -0
- package/bin/test-clients.js +38 -6
- package/bin/test-model-lists.js +100 -0
- package/lib/config.js +39 -6
- package/lib/model-list.js +117 -0
- package/lib/proxy.js +46 -0
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -299,7 +299,7 @@ jbai-continue # select model in TUI
|
|
|
299
299
|
| `jbai token` | Show token status |
|
|
300
300
|
| `jbai token set` | Set/update token |
|
|
301
301
|
| `jbai test` | Test API connections |
|
|
302
|
-
| `jbai models` | List
|
|
302
|
+
| `jbai models [tool]` | List Grazie models |
|
|
303
303
|
| `jbai proxy setup` | Setup proxy + configure Codex Desktop |
|
|
304
304
|
| `jbai proxy status` | Check proxy status |
|
|
305
305
|
| `jbai proxy stop` | Stop proxy |
|
package/bin/jbai-claude.js
CHANGED
|
@@ -2,15 +2,22 @@
|
|
|
2
2
|
|
|
3
3
|
const { runWithHandoff, stripHandoffFlag } = require('../lib/interactive-handoff');
|
|
4
4
|
const config = require('../lib/config');
|
|
5
|
+
const { isModelsCommand, showModelsForTool } = require('../lib/model-list');
|
|
5
6
|
const { ensureToken } = require('../lib/ensure-token');
|
|
7
|
+
const { PROXY_PORT, ensureProxy } = require('../lib/proxy');
|
|
6
8
|
|
|
7
9
|
(async () => {
|
|
8
|
-
const token = await ensureToken();
|
|
9
|
-
const endpoints = config.getEndpoints();
|
|
10
10
|
let args = process.argv.slice(2);
|
|
11
11
|
const handoffConfig = stripHandoffFlag(args);
|
|
12
12
|
args = handoffConfig.args;
|
|
13
13
|
|
|
14
|
+
if (isModelsCommand(args)) {
|
|
15
|
+
showModelsForTool('claude', 'Available Grazie models for jbai-claude:');
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const token = await ensureToken();
|
|
20
|
+
|
|
14
21
|
// Check for super mode (--super, --yolo, -s)
|
|
15
22
|
const superFlags = ['--super', '--yolo', '-s'];
|
|
16
23
|
const superMode = args.some(a => superFlags.includes(a));
|
|
@@ -26,19 +33,19 @@ const { ensureToken } = require('../lib/ensure-token');
|
|
|
26
33
|
console.log('🚀 Super mode: --dangerously-skip-permissions enabled');
|
|
27
34
|
}
|
|
28
35
|
|
|
29
|
-
//
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
36
|
+
// Auto-start proxy if not running (serves /anthropic/v1/models with only Grazie Claude models)
|
|
37
|
+
await ensureProxy();
|
|
38
|
+
|
|
39
|
+
// Route through proxy — it handles JWT injection and serves provider-filtered model list
|
|
33
40
|
const env = {
|
|
34
41
|
...process.env,
|
|
35
|
-
ANTHROPIC_BASE_URL:
|
|
42
|
+
ANTHROPIC_BASE_URL: `http://127.0.0.1:${PROXY_PORT}/anthropic`,
|
|
36
43
|
ANTHROPIC_API_KEY: 'placeholder',
|
|
37
|
-
ANTHROPIC_CUSTOM_HEADERS: `Grazie-Authenticate-JWT: ${token}`
|
|
38
44
|
};
|
|
39
45
|
|
|
40
|
-
// Remove any existing auth token that might conflict
|
|
46
|
+
// Remove any existing auth token/headers that might conflict
|
|
41
47
|
delete env.ANTHROPIC_AUTH_TOKEN;
|
|
48
|
+
delete env.ANTHROPIC_CUSTOM_HEADERS;
|
|
42
49
|
|
|
43
50
|
const child = runWithHandoff({
|
|
44
51
|
command: 'claude',
|
package/bin/jbai-codex.js
CHANGED
|
@@ -4,46 +4,14 @@ const { runWithHandoff, stripHandoffFlag } = require('../lib/interactive-handoff
|
|
|
4
4
|
const fs = require('fs');
|
|
5
5
|
const path = require('path');
|
|
6
6
|
const os = require('os');
|
|
7
|
-
const http = require('http');
|
|
8
7
|
const config = require('../lib/config');
|
|
8
|
+
const { isModelsCommand, showModelsForTool } = require('../lib/model-list');
|
|
9
9
|
const { ensureToken } = require('../lib/ensure-token');
|
|
10
|
+
const { PROXY_PORT, ensureProxy } = require('../lib/proxy');
|
|
10
11
|
|
|
11
|
-
const PROXY_PORT = 18080;
|
|
12
12
|
const PROXY_PROVIDER = 'jbai-proxy';
|
|
13
13
|
|
|
14
|
-
function isProxyRunning() {
|
|
15
|
-
return new Promise((resolve) => {
|
|
16
|
-
const req = http.get(`http://127.0.0.1:${PROXY_PORT}/health`, { timeout: 1000 }, (res) => {
|
|
17
|
-
let body = '';
|
|
18
|
-
res.on('data', chunk => body += chunk);
|
|
19
|
-
res.on('end', () => {
|
|
20
|
-
try {
|
|
21
|
-
const info = JSON.parse(body);
|
|
22
|
-
resolve(info.status === 'ok');
|
|
23
|
-
} catch {
|
|
24
|
-
resolve(false);
|
|
25
|
-
}
|
|
26
|
-
});
|
|
27
|
-
});
|
|
28
|
-
req.on('error', () => resolve(false));
|
|
29
|
-
req.on('timeout', () => { req.destroy(); resolve(false); });
|
|
30
|
-
});
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
function startProxy() {
|
|
34
|
-
const { spawn } = require('child_process');
|
|
35
|
-
const proxyScript = path.join(__dirname, 'jbai-proxy.js');
|
|
36
|
-
const child = spawn(process.execPath, [proxyScript, '--port', String(PROXY_PORT), '--_daemon'], {
|
|
37
|
-
detached: true,
|
|
38
|
-
stdio: 'ignore',
|
|
39
|
-
});
|
|
40
|
-
child.unref();
|
|
41
|
-
}
|
|
42
|
-
|
|
43
14
|
(async () => {
|
|
44
|
-
const token = await ensureToken();
|
|
45
|
-
const environment = config.getEnvironment();
|
|
46
|
-
const envVarName = environment === 'staging' ? 'GRAZIE_STAGING_TOKEN' : 'GRAZIE_API_TOKEN';
|
|
47
15
|
let args = process.argv.slice(2);
|
|
48
16
|
const handoffConfig = stripHandoffFlag(args);
|
|
49
17
|
args = handoffConfig.args;
|
|
@@ -53,13 +21,18 @@ function startProxy() {
|
|
|
53
21
|
const superMode = args.some(a => superFlags.includes(a));
|
|
54
22
|
args = args.filter(a => !superFlags.includes(a));
|
|
55
23
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
// Wait briefly for proxy to start
|
|
60
|
-
await new Promise(r => setTimeout(r, 500));
|
|
24
|
+
if (isModelsCommand(args)) {
|
|
25
|
+
showModelsForTool('codex', 'Available Grazie models for jbai-codex:');
|
|
26
|
+
return;
|
|
61
27
|
}
|
|
62
28
|
|
|
29
|
+
const token = await ensureToken();
|
|
30
|
+
const environment = config.getEnvironment();
|
|
31
|
+
const envVarName = environment === 'staging' ? 'GRAZIE_STAGING_TOKEN' : 'GRAZIE_API_TOKEN';
|
|
32
|
+
|
|
33
|
+
// Auto-start proxy if not running (serves /v1/models with our model list)
|
|
34
|
+
await ensureProxy();
|
|
35
|
+
|
|
63
36
|
// Ensure Codex config exists
|
|
64
37
|
const codexDir = path.join(os.homedir(), '.codex');
|
|
65
38
|
const codexConfig = path.join(codexDir, 'config.toml');
|
package/bin/jbai-continue.js
CHANGED
|
@@ -11,48 +11,19 @@ const { runWithHandoff, stripHandoffFlag } = require('../lib/interactive-handoff
|
|
|
11
11
|
const fs = require('fs');
|
|
12
12
|
const path = require('path');
|
|
13
13
|
const os = require('os');
|
|
14
|
-
const http = require('http');
|
|
15
14
|
const config = require('../lib/config');
|
|
15
|
+
const { isModelsCommand, showModelsForTool } = require('../lib/model-list');
|
|
16
16
|
const { ensureToken } = require('../lib/ensure-token');
|
|
17
|
+
const { PROXY_PORT, ensureProxy } = require('../lib/proxy');
|
|
17
18
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
function isProxyRunning() {
|
|
21
|
-
return new Promise((resolve) => {
|
|
22
|
-
const req = http.get(`http://127.0.0.1:${PROXY_PORT}/health`, { timeout: 1000 }, (res) => {
|
|
23
|
-
let body = '';
|
|
24
|
-
res.on('data', chunk => body += chunk);
|
|
25
|
-
res.on('end', () => {
|
|
26
|
-
try {
|
|
27
|
-
const info = JSON.parse(body);
|
|
28
|
-
resolve(info.status === 'ok');
|
|
29
|
-
} catch {
|
|
30
|
-
resolve(false);
|
|
31
|
-
}
|
|
32
|
-
});
|
|
33
|
-
});
|
|
34
|
-
req.on('error', () => resolve(false));
|
|
35
|
-
req.on('timeout', () => { req.destroy(); resolve(false); });
|
|
36
|
-
});
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
function startProxy() {
|
|
40
|
-
const { spawn } = require('child_process');
|
|
41
|
-
const proxyScript = path.join(__dirname, 'jbai-proxy.js');
|
|
42
|
-
const child = spawn(process.execPath, [proxyScript, '--port', String(PROXY_PORT), '--_daemon'], {
|
|
43
|
-
detached: true,
|
|
44
|
-
stdio: 'ignore',
|
|
45
|
-
});
|
|
46
|
-
child.unref();
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
function buildContinueConfig() {
|
|
19
|
+
function buildContinueConfig(requestedModel) {
|
|
50
20
|
const proxyBase = `http://127.0.0.1:${PROXY_PORT}`;
|
|
51
21
|
const models = [];
|
|
22
|
+
const targetModel = requestedModel || config.MODELS.claude.default;
|
|
52
23
|
|
|
53
24
|
// Add Claude models first (default provider)
|
|
54
25
|
config.MODELS.claude.available.forEach(model => {
|
|
55
|
-
const isDefault = model ===
|
|
26
|
+
const isDefault = model === targetModel;
|
|
56
27
|
models.push({
|
|
57
28
|
name: isDefault ? `${model} (default)` : model,
|
|
58
29
|
provider: 'anthropic',
|
|
@@ -65,8 +36,9 @@ function buildContinueConfig() {
|
|
|
65
36
|
|
|
66
37
|
// Add OpenAI models via proxy
|
|
67
38
|
config.MODELS.openai.available.forEach(model => {
|
|
39
|
+
const isDefault = model === targetModel;
|
|
68
40
|
models.push({
|
|
69
|
-
name: model,
|
|
41
|
+
name: isDefault ? `${model} (default)` : model,
|
|
70
42
|
provider: 'openai',
|
|
71
43
|
model,
|
|
72
44
|
apiBase: `${proxyBase}/openai/v1`,
|
|
@@ -75,7 +47,8 @@ function buildContinueConfig() {
|
|
|
75
47
|
});
|
|
76
48
|
});
|
|
77
49
|
|
|
78
|
-
const
|
|
50
|
+
const defaultEntry = models.find(m => m.model === targetModel);
|
|
51
|
+
const defaultModel = defaultEntry ? defaultEntry.name : `${config.MODELS.claude.default} (default)`;
|
|
79
52
|
|
|
80
53
|
return {
|
|
81
54
|
name: 'JetBrains AI',
|
|
@@ -115,8 +88,6 @@ function toYaml(obj, indent = 0) {
|
|
|
115
88
|
}
|
|
116
89
|
|
|
117
90
|
(async () => {
|
|
118
|
-
const token = await ensureToken();
|
|
119
|
-
const environment = config.getEnvironment();
|
|
120
91
|
let args = process.argv.slice(2);
|
|
121
92
|
const handoffConfig = stripHandoffFlag(args);
|
|
122
93
|
args = handoffConfig.args;
|
|
@@ -126,12 +97,25 @@ function toYaml(obj, indent = 0) {
|
|
|
126
97
|
const superMode = args.some(a => superFlags.includes(a));
|
|
127
98
|
args = args.filter(a => !superFlags.includes(a));
|
|
128
99
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
await new Promise(r => setTimeout(r, 500));
|
|
100
|
+
if (isModelsCommand(args)) {
|
|
101
|
+
showModelsForTool('continue', 'Available Grazie models for jbai-continue:');
|
|
102
|
+
return;
|
|
133
103
|
}
|
|
134
104
|
|
|
105
|
+
// Extract --model/-m from args (Continue CLI uses a different --model semantics)
|
|
106
|
+
let requestedModel = null;
|
|
107
|
+
const modelFlagIdx = args.findIndex(a => a === '--model' || a === '-m');
|
|
108
|
+
if (modelFlagIdx >= 0) {
|
|
109
|
+
requestedModel = args[modelFlagIdx + 1] || null;
|
|
110
|
+
args.splice(modelFlagIdx, 2);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
const token = await ensureToken();
|
|
114
|
+
const environment = config.getEnvironment();
|
|
115
|
+
|
|
116
|
+
// Auto-start proxy if not running
|
|
117
|
+
await ensureProxy();
|
|
118
|
+
|
|
135
119
|
// Write Continue config
|
|
136
120
|
const configDir = path.join(os.homedir(), '.continue');
|
|
137
121
|
const configFile = path.join(configDir, 'config.yaml');
|
|
@@ -140,7 +124,7 @@ function toYaml(obj, indent = 0) {
|
|
|
140
124
|
fs.mkdirSync(configDir, { recursive: true });
|
|
141
125
|
}
|
|
142
126
|
|
|
143
|
-
const continueConfig = buildContinueConfig();
|
|
127
|
+
const continueConfig = buildContinueConfig(requestedModel);
|
|
144
128
|
const yaml = `# Auto-generated by jbai-cli — do not edit manually\n${toYaml(continueConfig)}`;
|
|
145
129
|
fs.writeFileSync(configFile, yaml);
|
|
146
130
|
|