jbai-cli 1.9.2 → 2.1.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.
- package/README.md +3 -4
- package/bin/jbai-claude-opus.js +6 -0
- package/bin/jbai-claude-sonnet.js +6 -0
- package/bin/jbai-claude.js +16 -9
- package/bin/jbai-codex-5.2.js +6 -0
- package/bin/jbai-codex-5.3.js +6 -0
- package/bin/jbai-codex-rockhopper.js +6 -0
- 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-3.1.js +6 -0
- package/bin/jbai-gemini-supernova.js +6 -0
- package/bin/jbai-gemini.js +17 -6
- package/bin/jbai-goose.js +11 -39
- package/bin/jbai-opencode-deepseek.js +6 -0
- package/bin/jbai-opencode-grok.js +6 -0
- package/bin/jbai-opencode-rockhopper.js +6 -0
- package/bin/jbai-opencode.js +122 -20
- package/bin/jbai-proxy.js +1110 -66
- package/bin/jbai.js +99 -42
- 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/completions.js +258 -0
- package/lib/config.js +46 -8
- package/lib/model-list.js +117 -0
- package/lib/postinstall.js +3 -0
- package/lib/proxy.js +46 -0
- package/lib/shortcut.js +47 -0
- package/package.json +13 -2
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shell completions for jbai-cli.
|
|
3
|
+
*
|
|
4
|
+
* `jbai completions` — print zsh completion script to stdout
|
|
5
|
+
* `jbai completions --install` — append source line to ~/.zshrc
|
|
6
|
+
* `jbai completions --bash` — print bash completion script to stdout
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
const fs = require('fs');
|
|
10
|
+
const path = require('path');
|
|
11
|
+
const os = require('os');
|
|
12
|
+
const config = require('./config');
|
|
13
|
+
|
|
14
|
+
// Read bin entries from package.json for the canonical list of commands.
|
|
15
|
+
const pkg = require('../package.json');
|
|
16
|
+
const ALL_BINS = Object.keys(pkg.bin).sort();
|
|
17
|
+
|
|
18
|
+
// Shortcuts = bins that have a dash after the tool name (jbai-codex-5.3, etc.)
|
|
19
|
+
const TOOLS = ['claude', 'codex', 'gemini', 'opencode', 'goose', 'continue', 'council', 'proxy'];
|
|
20
|
+
|
|
21
|
+
// jbai subcommands
|
|
22
|
+
const JBAI_SUBCOMMANDS = [
|
|
23
|
+
'token', 'test', 'handoff', 'env', 'models', 'install', 'doctor',
|
|
24
|
+
'status', 'proxy', 'help', 'version', 'completions',
|
|
25
|
+
];
|
|
26
|
+
|
|
27
|
+
const JBAI_TOKEN_SUBCOMMANDS = ['set', 'refresh'];
|
|
28
|
+
const JBAI_ENV_VALUES = ['staging', 'production'];
|
|
29
|
+
const JBAI_MODELS_VALUES = ['all', 'claude', 'codex', 'gemini', 'opencode', 'goose', 'continue'];
|
|
30
|
+
const JBAI_INSTALL_VALUES = ['all', 'claude', 'codex', 'gemini', 'opencode', 'goose', 'continue'];
|
|
31
|
+
const SUPER_FLAGS = ['--super', '--yolo', '-s'];
|
|
32
|
+
const COMMON_FLAGS = ['--model', '--models', '--help'];
|
|
33
|
+
|
|
34
|
+
// Collect all model names for --model completion
|
|
35
|
+
const ALL_MODELS = [
|
|
36
|
+
...config.MODELS.claude.available,
|
|
37
|
+
...config.MODELS.openai.available,
|
|
38
|
+
...config.MODELS.codex.available,
|
|
39
|
+
...config.MODELS.gemini.available,
|
|
40
|
+
...config.MODELS.grazie.available,
|
|
41
|
+
];
|
|
42
|
+
// Dedupe
|
|
43
|
+
const UNIQUE_MODELS = [...new Set(ALL_MODELS)].sort();
|
|
44
|
+
|
|
45
|
+
function generateZsh() {
|
|
46
|
+
// Group shortcuts by tool for descriptive completions
|
|
47
|
+
const shortcutDescriptions = {};
|
|
48
|
+
for (const bin of ALL_BINS) {
|
|
49
|
+
if (bin === 'jbai' || bin === 'jbai-proxy') continue;
|
|
50
|
+
// e.g. jbai-codex-rockhopper -> "Codex + Rockhopper Alpha"
|
|
51
|
+
shortcutDescriptions[bin] = bin;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
return `#compdef jbai jbai-claude jbai-codex jbai-gemini jbai-opencode jbai-goose jbai-continue jbai-council jbai-proxy jbai-claude-opus jbai-claude-sonnet jbai-codex-5.2 jbai-codex-5.3 jbai-codex-rockhopper jbai-gemini-3.1 jbai-gemini-supernova jbai-opencode-rockhopper jbai-opencode-grok jbai-opencode-deepseek
|
|
55
|
+
# ─── jbai-cli zsh completions (auto-generated) ───
|
|
56
|
+
|
|
57
|
+
# Complete model names after --model flag
|
|
58
|
+
_jbai_models() {
|
|
59
|
+
local models=(
|
|
60
|
+
${UNIQUE_MODELS.map(m => ` '${m}'`).join('\n')}
|
|
61
|
+
)
|
|
62
|
+
_describe 'model' models
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
# Main jbai command completions
|
|
66
|
+
_jbai() {
|
|
67
|
+
local -a subcommands=(
|
|
68
|
+
'token:Show or manage authentication token'
|
|
69
|
+
'test:Test API endpoints'
|
|
70
|
+
'handoff:Continue task in Orca Lab'
|
|
71
|
+
'env:Switch environment (staging/production)'
|
|
72
|
+
'models:List available models'
|
|
73
|
+
'install:Install AI tools'
|
|
74
|
+
'doctor:Check installed tools'
|
|
75
|
+
'status:Check installed tools'
|
|
76
|
+
'proxy:Manage local proxy'
|
|
77
|
+
'help:Show help'
|
|
78
|
+
'version:Show version'
|
|
79
|
+
'completions:Shell completions'
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
if (( CURRENT == 2 )); then
|
|
83
|
+
_describe 'command' subcommands
|
|
84
|
+
return
|
|
85
|
+
fi
|
|
86
|
+
|
|
87
|
+
case "\${words[2]}" in
|
|
88
|
+
token)
|
|
89
|
+
if (( CURRENT == 3 )); then
|
|
90
|
+
local -a token_cmds=('set:Set token interactively' 'refresh:Refresh token via API')
|
|
91
|
+
_describe 'token command' token_cmds
|
|
92
|
+
fi
|
|
93
|
+
;;
|
|
94
|
+
env)
|
|
95
|
+
if (( CURRENT == 3 )); then
|
|
96
|
+
local -a envs=('staging' 'production')
|
|
97
|
+
_describe 'environment' envs
|
|
98
|
+
fi
|
|
99
|
+
;;
|
|
100
|
+
models)
|
|
101
|
+
if (( CURRENT == 3 )); then
|
|
102
|
+
local -a tools=(${JBAI_MODELS_VALUES.map(v => `'${v}'`).join(' ')})
|
|
103
|
+
_describe 'tool filter' tools
|
|
104
|
+
fi
|
|
105
|
+
;;
|
|
106
|
+
install)
|
|
107
|
+
if (( CURRENT == 3 )); then
|
|
108
|
+
local -a tools=(${JBAI_INSTALL_VALUES.map(v => `'${v}'`).join(' ')})
|
|
109
|
+
_describe 'tool' tools
|
|
110
|
+
fi
|
|
111
|
+
;;
|
|
112
|
+
completions)
|
|
113
|
+
if (( CURRENT == 3 )); then
|
|
114
|
+
local -a opts=('--install:Add to ~/.zshrc' '--bash:Print bash completions')
|
|
115
|
+
_describe 'option' opts
|
|
116
|
+
fi
|
|
117
|
+
;;
|
|
118
|
+
esac
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
# Tool wrapper completions (jbai-claude, jbai-codex, etc.)
|
|
122
|
+
_jbai_tool_wrapper() {
|
|
123
|
+
_arguments -s \\
|
|
124
|
+
'--model[Model to use]:model:_jbai_models' \\
|
|
125
|
+
'-m[Model to use]:model:_jbai_models' \\
|
|
126
|
+
'--super[Enable super/auto mode]' \\
|
|
127
|
+
'--yolo[Enable super/auto mode]' \\
|
|
128
|
+
'-s[Enable super/auto mode]' \\
|
|
129
|
+
'--models[List available models]' \\
|
|
130
|
+
'--list-models[List available models]' \\
|
|
131
|
+
'--help[Show help]' \\
|
|
132
|
+
'models:List available models' \\
|
|
133
|
+
'*:pass-through:'
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
# Register completions
|
|
137
|
+
compdef _jbai jbai
|
|
138
|
+
compdef _jbai_tool_wrapper jbai-claude jbai-codex jbai-gemini jbai-opencode jbai-goose jbai-continue
|
|
139
|
+
compdef _jbai_tool_wrapper jbai-claude-opus jbai-claude-sonnet
|
|
140
|
+
compdef _jbai_tool_wrapper jbai-codex-5.2 jbai-codex-5.3 jbai-codex-rockhopper
|
|
141
|
+
compdef _jbai_tool_wrapper jbai-gemini-3.1 jbai-gemini-supernova
|
|
142
|
+
compdef _jbai_tool_wrapper jbai-opencode-rockhopper jbai-opencode-grok jbai-opencode-deepseek
|
|
143
|
+
`;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
function generateBash() {
|
|
147
|
+
return `# ─── jbai-cli bash completions (auto-generated) ───
|
|
148
|
+
|
|
149
|
+
_jbai_completions() {
|
|
150
|
+
local cur="\${COMP_WORDS[COMP_CWORD]}"
|
|
151
|
+
local prev="\${COMP_WORDS[COMP_CWORD-1]}"
|
|
152
|
+
|
|
153
|
+
# jbai subcommands
|
|
154
|
+
if [[ "\${COMP_WORDS[0]}" == "jbai" && \${COMP_CWORD} -eq 1 ]]; then
|
|
155
|
+
COMPREPLY=( $(compgen -W "${JBAI_SUBCOMMANDS.join(' ')}" -- "$cur") )
|
|
156
|
+
return
|
|
157
|
+
fi
|
|
158
|
+
|
|
159
|
+
# jbai token <sub>
|
|
160
|
+
if [[ "\${COMP_WORDS[1]}" == "token" && \${COMP_CWORD} -eq 2 ]]; then
|
|
161
|
+
COMPREPLY=( $(compgen -W "${JBAI_TOKEN_SUBCOMMANDS.join(' ')}" -- "$cur") )
|
|
162
|
+
return
|
|
163
|
+
fi
|
|
164
|
+
|
|
165
|
+
# jbai env <value>
|
|
166
|
+
if [[ "\${COMP_WORDS[1]}" == "env" && \${COMP_CWORD} -eq 2 ]]; then
|
|
167
|
+
COMPREPLY=( $(compgen -W "${JBAI_ENV_VALUES.join(' ')}" -- "$cur") )
|
|
168
|
+
return
|
|
169
|
+
fi
|
|
170
|
+
|
|
171
|
+
# jbai models <value>
|
|
172
|
+
if [[ "\${COMP_WORDS[1]}" == "models" && \${COMP_CWORD} -eq 2 ]]; then
|
|
173
|
+
COMPREPLY=( $(compgen -W "${JBAI_MODELS_VALUES.join(' ')}" -- "$cur") )
|
|
174
|
+
return
|
|
175
|
+
fi
|
|
176
|
+
|
|
177
|
+
# jbai install <value>
|
|
178
|
+
if [[ "\${COMP_WORDS[1]}" == "install" && \${COMP_CWORD} -eq 2 ]]; then
|
|
179
|
+
COMPREPLY=( $(compgen -W "${JBAI_INSTALL_VALUES.join(' ')}" -- "$cur") )
|
|
180
|
+
return
|
|
181
|
+
fi
|
|
182
|
+
|
|
183
|
+
# --model completion
|
|
184
|
+
if [[ "$prev" == "--model" || "$prev" == "-m" ]]; then
|
|
185
|
+
COMPREPLY=( $(compgen -W "${UNIQUE_MODELS.join(' ')}" -- "$cur") )
|
|
186
|
+
return
|
|
187
|
+
fi
|
|
188
|
+
|
|
189
|
+
# Generic flags for tool wrappers
|
|
190
|
+
COMPREPLY=( $(compgen -W "--model --super --yolo --models --help models" -- "$cur") )
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
_jbai_tool_completions() {
|
|
194
|
+
local cur="\${COMP_WORDS[COMP_CWORD]}"
|
|
195
|
+
local prev="\${COMP_WORDS[COMP_CWORD-1]}"
|
|
196
|
+
|
|
197
|
+
if [[ "$prev" == "--model" || "$prev" == "-m" ]]; then
|
|
198
|
+
COMPREPLY=( $(compgen -W "${UNIQUE_MODELS.join(' ')}" -- "$cur") )
|
|
199
|
+
return
|
|
200
|
+
fi
|
|
201
|
+
|
|
202
|
+
COMPREPLY=( $(compgen -W "--model --super --yolo --models --help models" -- "$cur") )
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
complete -F _jbai_completions jbai
|
|
206
|
+
complete -F _jbai_tool_completions jbai-claude jbai-codex jbai-gemini jbai-opencode jbai-goose jbai-continue
|
|
207
|
+
complete -F _jbai_tool_completions jbai-claude-opus jbai-claude-sonnet
|
|
208
|
+
complete -F _jbai_tool_completions jbai-codex-5.2 jbai-codex-5.3 jbai-codex-rockhopper
|
|
209
|
+
complete -F _jbai_tool_completions jbai-gemini-3.1 jbai-gemini-supernova
|
|
210
|
+
complete -F _jbai_tool_completions jbai-opencode-rockhopper jbai-opencode-grok jbai-opencode-deepseek
|
|
211
|
+
`;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
function getCompletionFilePath() {
|
|
215
|
+
return path.join(config.CONFIG_DIR, 'completions.zsh');
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
function installZsh() {
|
|
219
|
+
const completionFile = getCompletionFilePath();
|
|
220
|
+
const zshrc = path.join(os.homedir(), '.zshrc');
|
|
221
|
+
|
|
222
|
+
// Write completion file
|
|
223
|
+
config.ensureConfigDir();
|
|
224
|
+
fs.writeFileSync(completionFile, generateZsh(), { mode: 0o644 });
|
|
225
|
+
console.log(`Written: ${completionFile}`);
|
|
226
|
+
|
|
227
|
+
// Check if already sourced in .zshrc
|
|
228
|
+
const sourceLine = `[ -f "${completionFile}" ] && source "${completionFile}"`;
|
|
229
|
+
|
|
230
|
+
if (fs.existsSync(zshrc)) {
|
|
231
|
+
const content = fs.readFileSync(zshrc, 'utf-8');
|
|
232
|
+
if (content.includes('jbai') && content.includes('completions.zsh')) {
|
|
233
|
+
console.log('Already in ~/.zshrc — updating completion file only');
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
fs.appendFileSync(zshrc, `\n# jbai-cli completions\n${sourceLine}\n`);
|
|
239
|
+
console.log('Added to ~/.zshrc');
|
|
240
|
+
console.log('\nRun: source ~/.zshrc (or open a new terminal)');
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
function run(args) {
|
|
244
|
+
if (args.includes('--install')) {
|
|
245
|
+
installZsh();
|
|
246
|
+
return;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
if (args.includes('--bash')) {
|
|
250
|
+
process.stdout.write(generateBash());
|
|
251
|
+
return;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
// Default: print zsh completions to stdout
|
|
255
|
+
process.stdout.write(generateZsh());
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
module.exports = { run, generateZsh, generateBash, installZsh, getCompletionFilePath };
|
package/lib/config.js
CHANGED
|
@@ -35,6 +35,7 @@ const MODELS = {
|
|
|
35
35
|
available: [
|
|
36
36
|
// Claude 4.6 series (latest)
|
|
37
37
|
'claude-opus-4-6',
|
|
38
|
+
'claude-sonnet-4-6',
|
|
38
39
|
// Claude 4.5 series
|
|
39
40
|
'claude-opus-4-5-20251101',
|
|
40
41
|
'claude-sonnet-4-5-20250929',
|
|
@@ -53,7 +54,7 @@ const MODELS = {
|
|
|
53
54
|
default: 'gpt-5.2-2025-12-11',
|
|
54
55
|
available: [
|
|
55
56
|
// GPT-5.x series (latest) - require date-versioned names
|
|
56
|
-
|
|
57
|
+
'gpt-5.3-codex',
|
|
57
58
|
'gpt-5.2-2025-12-11',
|
|
58
59
|
'gpt-5.2',
|
|
59
60
|
'gpt-5.1-2025-11-13',
|
|
@@ -83,9 +84,11 @@ const MODELS = {
|
|
|
83
84
|
codex: {
|
|
84
85
|
default: 'gpt-5.3-codex',
|
|
85
86
|
available: [
|
|
87
|
+
// Hidden/EAP models (JB internal NDA)
|
|
88
|
+
'rockhopper-alpha',
|
|
89
|
+
'gpt-5.3-codex-api-preview',
|
|
86
90
|
// Codex-specific models (responses API only, NOT available via chat/completions)
|
|
87
91
|
'gpt-5.3-codex',
|
|
88
|
-
'gpt-5.3-codex-api-preview',
|
|
89
92
|
// GPT-5.x chat models (also work via responses API)
|
|
90
93
|
'gpt-5.2-2025-12-11',
|
|
91
94
|
'gpt-5.2',
|
|
@@ -105,6 +108,9 @@ const MODELS = {
|
|
|
105
108
|
gemini: {
|
|
106
109
|
default: 'gemini-2.5-flash',
|
|
107
110
|
available: [
|
|
111
|
+
// Hidden/EAP models (JB internal NDA)
|
|
112
|
+
'supernova',
|
|
113
|
+
'gemini-3.1-pro-preview',
|
|
108
114
|
// Gemini 3.x (preview)
|
|
109
115
|
'gemini-3-pro-preview',
|
|
110
116
|
'gemini-3-flash-preview',
|
|
@@ -116,23 +122,55 @@ const MODELS = {
|
|
|
116
122
|
'gemini-2.0-flash-001',
|
|
117
123
|
'gemini-2.0-flash-lite-001'
|
|
118
124
|
]
|
|
125
|
+
},
|
|
126
|
+
// Grazie native Chat API models — accessible via /grazie-openai/v1 translation layer.
|
|
127
|
+
// Full list is dynamic (fetched from /user/v5/llm/profiles), this is a static fallback.
|
|
128
|
+
grazie: {
|
|
129
|
+
default: 'google-gemini-3-0-flash',
|
|
130
|
+
available: [
|
|
131
|
+
// Google
|
|
132
|
+
'google-gemini-3-1-pro',
|
|
133
|
+
'google-gemini-3-0-flash',
|
|
134
|
+
'google-gemini-3-0-pro-snowball',
|
|
135
|
+
'google-chat-gemini-pro-2.5',
|
|
136
|
+
'google-gemini-2.5-flash',
|
|
137
|
+
// DeepSeek
|
|
138
|
+
'deepseek-r1',
|
|
139
|
+
'openrouter-deepseek-v3-2',
|
|
140
|
+
// Mistral
|
|
141
|
+
'mistral-large',
|
|
142
|
+
'mistral-small',
|
|
143
|
+
'openrouter-mistral-large-2512',
|
|
144
|
+
// xAI / Grok
|
|
145
|
+
'xai-grok-4',
|
|
146
|
+
'xai-grok-4-1-fast',
|
|
147
|
+
'xai-grok-code-fast-1',
|
|
148
|
+
// Qwen
|
|
149
|
+
'qwen-max',
|
|
150
|
+
'qwen-plus',
|
|
151
|
+
// Kimi
|
|
152
|
+
'openrouter-kimi-k2-5',
|
|
153
|
+
'openrouter-kimi-k2-thinking',
|
|
154
|
+
// MiniMax
|
|
155
|
+
'openrouter-minimax-m2-1',
|
|
156
|
+
// ZhipuAI
|
|
157
|
+
'openrouter-zhipuai-glm-4-7',
|
|
158
|
+
'openrouter-zhipuai-glm-4-7-flash',
|
|
159
|
+
]
|
|
119
160
|
}
|
|
120
|
-
// NOTE: Other providers (DeepSeek, Mistral, Qwen, XAI, Meta, Grok) are available
|
|
121
|
-
// via Grazie native Chat API but NOT via the OpenAI-compatible proxy.
|
|
122
|
-
// They are not supported by CLI tools that use OpenAI API format.
|
|
123
161
|
};
|
|
124
162
|
|
|
125
|
-
// Model aliases:
|
|
163
|
+
// Model aliases: some CLI tools send short names that Grazie doesn't recognise yet.
|
|
126
164
|
// Map them to the Grazie-accepted equivalents so the proxy can rewrite on the fly.
|
|
127
165
|
const MODEL_ALIASES = {
|
|
128
|
-
'gpt-5.3-codex': 'gpt-5.3-codex-api-preview',
|
|
129
166
|
};
|
|
130
167
|
|
|
131
168
|
// All models for tools that support multiple providers (OpenCode, Codex)
|
|
132
169
|
const ALL_MODELS = {
|
|
133
170
|
openai: MODELS.openai.available,
|
|
134
171
|
anthropic: MODELS.claude.available,
|
|
135
|
-
gemini: MODELS.gemini.available
|
|
172
|
+
gemini: MODELS.gemini.available,
|
|
173
|
+
grazie: MODELS.grazie.available
|
|
136
174
|
};
|
|
137
175
|
|
|
138
176
|
function ensureConfigDir() {
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
const config = require('./config');
|
|
2
|
+
|
|
3
|
+
function formatModels(models, defaultModel) {
|
|
4
|
+
return models.map((m) => {
|
|
5
|
+
const def = m === defaultModel ? ' (default)' : '';
|
|
6
|
+
return ` - ${m}${def}`;
|
|
7
|
+
}).join('\n');
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
function printGroups(groups) {
|
|
11
|
+
for (const group of groups) {
|
|
12
|
+
console.log(`${group.title}:`);
|
|
13
|
+
console.log(formatModels(group.models, group.defaultModel));
|
|
14
|
+
console.log('');
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function getGroupsForTool(tool) {
|
|
19
|
+
switch (tool) {
|
|
20
|
+
case 'claude':
|
|
21
|
+
return [
|
|
22
|
+
{
|
|
23
|
+
title: 'Claude (Anthropic)',
|
|
24
|
+
models: config.MODELS.claude.available,
|
|
25
|
+
defaultModel: config.MODELS.claude.default,
|
|
26
|
+
},
|
|
27
|
+
];
|
|
28
|
+
case 'codex':
|
|
29
|
+
return [
|
|
30
|
+
{
|
|
31
|
+
title: 'Codex (OpenAI Responses)',
|
|
32
|
+
models: config.MODELS.codex.available,
|
|
33
|
+
defaultModel: config.MODELS.codex.default,
|
|
34
|
+
},
|
|
35
|
+
];
|
|
36
|
+
case 'gemini':
|
|
37
|
+
return [
|
|
38
|
+
{
|
|
39
|
+
title: 'Gemini (Google)',
|
|
40
|
+
models: config.MODELS.gemini.available,
|
|
41
|
+
defaultModel: config.MODELS.gemini.default,
|
|
42
|
+
},
|
|
43
|
+
];
|
|
44
|
+
case 'opencode':
|
|
45
|
+
case 'goose':
|
|
46
|
+
case 'continue':
|
|
47
|
+
return [
|
|
48
|
+
{
|
|
49
|
+
title: 'Claude (Anthropic)',
|
|
50
|
+
models: config.MODELS.claude.available,
|
|
51
|
+
defaultModel: config.MODELS.claude.default,
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
title: 'GPT (OpenAI Chat)',
|
|
55
|
+
models: config.MODELS.openai.available,
|
|
56
|
+
defaultModel: config.MODELS.openai.default,
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
title: 'Grazie Native Chat (Google, DeepSeek, Mistral, xAI, Qwen, etc.)',
|
|
60
|
+
models: config.MODELS.grazie.available,
|
|
61
|
+
defaultModel: config.MODELS.grazie.default,
|
|
62
|
+
},
|
|
63
|
+
];
|
|
64
|
+
case 'all':
|
|
65
|
+
default:
|
|
66
|
+
return [
|
|
67
|
+
{
|
|
68
|
+
title: 'Claude (Anthropic)',
|
|
69
|
+
models: config.MODELS.claude.available,
|
|
70
|
+
defaultModel: config.MODELS.claude.default,
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
title: 'GPT (OpenAI Chat)',
|
|
74
|
+
models: config.MODELS.openai.available,
|
|
75
|
+
defaultModel: config.MODELS.openai.default,
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
title: 'Codex (OpenAI Responses)',
|
|
79
|
+
models: config.MODELS.codex.available,
|
|
80
|
+
defaultModel: config.MODELS.codex.default,
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
title: 'Gemini (Google)',
|
|
84
|
+
models: config.MODELS.gemini.available,
|
|
85
|
+
defaultModel: config.MODELS.gemini.default,
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
title: 'Grazie Native Chat (Google, DeepSeek, Mistral, xAI, Qwen, etc.)',
|
|
89
|
+
models: config.MODELS.grazie.available,
|
|
90
|
+
defaultModel: config.MODELS.grazie.default,
|
|
91
|
+
},
|
|
92
|
+
];
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function showModelsForTool(tool, heading) {
|
|
97
|
+
const title = heading || 'Available Grazie models:';
|
|
98
|
+
console.log(`${title}\n`);
|
|
99
|
+
const groups = getGroupsForTool(tool);
|
|
100
|
+
printGroups(groups);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function isModelsCommand(args, { allowCommand = true } = {}) {
|
|
104
|
+
if (args.includes('--models') || args.includes('--list-models')) {
|
|
105
|
+
return true;
|
|
106
|
+
}
|
|
107
|
+
if (allowCommand && args[0] === 'models') {
|
|
108
|
+
return true;
|
|
109
|
+
}
|
|
110
|
+
return false;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
module.exports = {
|
|
114
|
+
getGroupsForTool,
|
|
115
|
+
isModelsCommand,
|
|
116
|
+
showModelsForTool,
|
|
117
|
+
};
|
package/lib/postinstall.js
CHANGED
package/lib/proxy.js
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
const http = require('http');
|
|
2
|
+
const { spawn } = require('child_process');
|
|
3
|
+
const path = require('path');
|
|
4
|
+
|
|
5
|
+
const PROXY_PORT = 18080;
|
|
6
|
+
|
|
7
|
+
function isProxyRunning(port = PROXY_PORT) {
|
|
8
|
+
return new Promise((resolve) => {
|
|
9
|
+
const req = http.get(`http://127.0.0.1:${port}/health`, { timeout: 1000 }, (res) => {
|
|
10
|
+
let body = '';
|
|
11
|
+
res.on('data', chunk => body += chunk);
|
|
12
|
+
res.on('end', () => {
|
|
13
|
+
try {
|
|
14
|
+
const info = JSON.parse(body);
|
|
15
|
+
resolve(info.status === 'ok');
|
|
16
|
+
} catch {
|
|
17
|
+
resolve(false);
|
|
18
|
+
}
|
|
19
|
+
});
|
|
20
|
+
});
|
|
21
|
+
req.on('error', () => resolve(false));
|
|
22
|
+
req.on('timeout', () => { req.destroy(); resolve(false); });
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function startProxy(port = PROXY_PORT) {
|
|
27
|
+
const proxyScript = path.join(__dirname, '..', 'bin', 'jbai-proxy.js');
|
|
28
|
+
const child = spawn(process.execPath, [proxyScript, '--port', String(port), '--_daemon'], {
|
|
29
|
+
detached: true,
|
|
30
|
+
stdio: 'ignore',
|
|
31
|
+
});
|
|
32
|
+
child.unref();
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
async function ensureProxy(port = PROXY_PORT) {
|
|
36
|
+
if (await isProxyRunning(port)) return;
|
|
37
|
+
startProxy(port);
|
|
38
|
+
// Poll until proxy is ready (up to 5 seconds)
|
|
39
|
+
for (let i = 0; i < 20; i++) {
|
|
40
|
+
await new Promise(r => setTimeout(r, 250));
|
|
41
|
+
if (await isProxyRunning(port)) return;
|
|
42
|
+
}
|
|
43
|
+
// Proxy didn't start in time — proceed anyway, wrappers will fail with clear errors
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
module.exports = { PROXY_PORT, isProxyRunning, startProxy, ensureProxy };
|
package/lib/shortcut.js
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared logic for per-model shortcut scripts.
|
|
3
|
+
*
|
|
4
|
+
* Each shortcut (e.g. jbai-codex-rockhopper) is a thin wrapper that calls
|
|
5
|
+
* the base tool wrapper (jbai-codex, jbai-claude, …) with a fixed model
|
|
6
|
+
* and super mode enabled by default.
|
|
7
|
+
*
|
|
8
|
+
* Usage in a shortcut script:
|
|
9
|
+
* require('../lib/shortcut').run({
|
|
10
|
+
* tool: 'codex', // base wrapper to delegate to
|
|
11
|
+
* model: 'rockhopper-alpha',
|
|
12
|
+
* label: 'Rockhopper Alpha',
|
|
13
|
+
* });
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
const { spawn } = require('child_process');
|
|
17
|
+
const path = require('path');
|
|
18
|
+
|
|
19
|
+
function run({ tool, model, label }) {
|
|
20
|
+
const args = process.argv.slice(2);
|
|
21
|
+
|
|
22
|
+
// Already force super mode + the pinned model
|
|
23
|
+
const extraArgs = ['--super', '--model', model];
|
|
24
|
+
|
|
25
|
+
// If user already passed --model, skip our default
|
|
26
|
+
if (args.includes('--model') || args.includes('-m')) {
|
|
27
|
+
extraArgs.splice(extraArgs.indexOf('--model'), 2);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const wrapperScript = path.join(__dirname, '..', 'bin', `jbai-${tool}.js`);
|
|
31
|
+
const finalArgs = [wrapperScript, ...extraArgs, ...args];
|
|
32
|
+
|
|
33
|
+
console.log(`⚡ ${label || model} (super mode)`);
|
|
34
|
+
|
|
35
|
+
const child = spawn(process.execPath, finalArgs, {
|
|
36
|
+
stdio: 'inherit',
|
|
37
|
+
env: process.env,
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
child.on('exit', (code) => process.exit(code || 0));
|
|
41
|
+
child.on('error', (err) => {
|
|
42
|
+
console.error(`Error: ${err.message}`);
|
|
43
|
+
process.exit(1);
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
module.exports = { run };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "jbai-cli",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "2.1.0",
|
|
4
4
|
"description": "CLI wrappers to use AI coding tools (Claude Code, Codex, Gemini CLI, OpenCode, Goose, Continue) with JetBrains AI Platform",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"jetbrains",
|
|
@@ -30,11 +30,22 @@
|
|
|
30
30
|
"jbai": "bin/jbai.js",
|
|
31
31
|
"jbai-proxy": "bin/jbai-proxy.js",
|
|
32
32
|
"jbai-claude": "bin/jbai-claude.js",
|
|
33
|
+
"jbai-claude-opus": "bin/jbai-claude-opus.js",
|
|
34
|
+
"jbai-claude-sonnet": "bin/jbai-claude-sonnet.js",
|
|
33
35
|
"jbai-codex": "bin/jbai-codex.js",
|
|
36
|
+
"jbai-codex-5.2": "bin/jbai-codex-5.2.js",
|
|
37
|
+
"jbai-codex-5.3": "bin/jbai-codex-5.3.js",
|
|
38
|
+
"jbai-codex-rockhopper": "bin/jbai-codex-rockhopper.js",
|
|
34
39
|
"jbai-gemini": "bin/jbai-gemini.js",
|
|
40
|
+
"jbai-gemini-3.1": "bin/jbai-gemini-3.1.js",
|
|
41
|
+
"jbai-gemini-supernova": "bin/jbai-gemini-supernova.js",
|
|
35
42
|
"jbai-opencode": "bin/jbai-opencode.js",
|
|
43
|
+
"jbai-opencode-rockhopper": "bin/jbai-opencode-rockhopper.js",
|
|
44
|
+
"jbai-opencode-grok": "bin/jbai-opencode-grok.js",
|
|
45
|
+
"jbai-opencode-deepseek": "bin/jbai-opencode-deepseek.js",
|
|
36
46
|
"jbai-goose": "bin/jbai-goose.js",
|
|
37
|
-
"jbai-continue": "bin/jbai-continue.js"
|
|
47
|
+
"jbai-continue": "bin/jbai-continue.js",
|
|
48
|
+
"jbai-council": "bin/jbai-council.js"
|
|
38
49
|
},
|
|
39
50
|
"files": [
|
|
40
51
|
"bin/",
|