jbai-cli 1.9.6 → 2.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 +34 -38
- package/bin/jbai-claude-opus.js +6 -0
- package/bin/jbai-claude-sonnet.js +6 -0
- package/bin/jbai-claude.js +3 -17
- package/bin/jbai-codex-5.2.js +6 -0
- package/bin/jbai-codex-5.3.js +6 -0
- package/bin/jbai-codex-5.4.js +6 -0
- package/bin/jbai-codex-rockhopper.js +6 -0
- package/bin/jbai-codex.js +13 -17
- package/bin/jbai-continue.js +3 -17
- package/bin/jbai-council.js +1 -1
- package/bin/jbai-gemini-3.1.js +6 -0
- package/bin/jbai-gemini-supernova.js +6 -0
- package/bin/jbai-gemini.js +3 -17
- package/bin/jbai-goose.js +3 -18
- 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 +6 -51
- package/bin/jbai-proxy.js +27 -5
- package/bin/jbai.js +337 -122
- package/lib/completions.js +255 -0
- package/lib/config.js +18 -82
- package/lib/model-list.js +2 -2
- package/lib/postinstall.js +3 -23
- package/lib/shortcut.js +47 -0
- package/package.json +13 -4
- package/lib/handoff.js +0 -152
- package/lib/interactive-handoff.js +0 -220
|
@@ -0,0 +1,255 @@
|
|
|
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
|
+
// jbai subcommands
|
|
19
|
+
const JBAI_SUBCOMMANDS = [
|
|
20
|
+
'menu', 'token', 'test', 'env', 'models', 'install', 'doctor',
|
|
21
|
+
'status', 'proxy', 'help', 'version', 'completions',
|
|
22
|
+
];
|
|
23
|
+
|
|
24
|
+
const JBAI_TOKEN_SUBCOMMANDS = ['set', 'refresh'];
|
|
25
|
+
const JBAI_ENV_VALUES = ['staging', 'production'];
|
|
26
|
+
const JBAI_MODELS_VALUES = ['all', 'claude', 'codex', 'gemini', 'opencode', 'goose', 'continue'];
|
|
27
|
+
const JBAI_INSTALL_VALUES = ['all', 'claude', 'codex', 'gemini', 'opencode', 'goose', 'continue'];
|
|
28
|
+
const SUPER_FLAGS = ['--super', '--yolo', '-s'];
|
|
29
|
+
const COMMON_FLAGS = ['--model', '--models', '--help'];
|
|
30
|
+
|
|
31
|
+
// Collect all model names for --model completion
|
|
32
|
+
const ALL_MODELS = [
|
|
33
|
+
...config.MODELS.claude.available,
|
|
34
|
+
...config.MODELS.openai.available,
|
|
35
|
+
...config.MODELS.codex.available,
|
|
36
|
+
...config.MODELS.gemini.available,
|
|
37
|
+
...config.MODELS.grazie.available,
|
|
38
|
+
];
|
|
39
|
+
// Dedupe
|
|
40
|
+
const UNIQUE_MODELS = [...new Set(ALL_MODELS)].sort();
|
|
41
|
+
|
|
42
|
+
function generateZsh() {
|
|
43
|
+
// Group shortcuts by tool for descriptive completions
|
|
44
|
+
const shortcutDescriptions = {};
|
|
45
|
+
for (const bin of ALL_BINS) {
|
|
46
|
+
if (bin === 'jbai' || bin === 'jbai-proxy') continue;
|
|
47
|
+
// e.g. jbai-codex-rockhopper -> "Codex + Rockhopper Alpha"
|
|
48
|
+
shortcutDescriptions[bin] = bin;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
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-5.4 jbai-codex-rockhopper jbai-gemini-3.1 jbai-gemini-supernova jbai-opencode-rockhopper jbai-opencode-grok jbai-opencode-deepseek
|
|
52
|
+
# ─── jbai-cli zsh completions (auto-generated) ───
|
|
53
|
+
|
|
54
|
+
# Complete model names after --model flag
|
|
55
|
+
_jbai_models() {
|
|
56
|
+
local models=(
|
|
57
|
+
${UNIQUE_MODELS.map(m => ` '${m}'`).join('\n')}
|
|
58
|
+
)
|
|
59
|
+
_describe 'model' models
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
# Main jbai command completions
|
|
63
|
+
_jbai() {
|
|
64
|
+
local -a subcommands=(
|
|
65
|
+
'menu:Open interactive control panel'
|
|
66
|
+
'token:Show or manage authentication token'
|
|
67
|
+
'test:Test API endpoints'
|
|
68
|
+
'env:Switch environment (staging/production)'
|
|
69
|
+
'models:List available models'
|
|
70
|
+
'install:Install AI tools'
|
|
71
|
+
'doctor:Check installed tools'
|
|
72
|
+
'status:Check installed tools'
|
|
73
|
+
'proxy:Manage local proxy'
|
|
74
|
+
'help:Show help'
|
|
75
|
+
'version:Show version'
|
|
76
|
+
'completions:Shell completions'
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
if (( CURRENT == 2 )); then
|
|
80
|
+
_describe 'command' subcommands
|
|
81
|
+
return
|
|
82
|
+
fi
|
|
83
|
+
|
|
84
|
+
case "\${words[2]}" in
|
|
85
|
+
token)
|
|
86
|
+
if (( CURRENT == 3 )); then
|
|
87
|
+
local -a token_cmds=('set:Set token interactively' 'refresh:Refresh token via API')
|
|
88
|
+
_describe 'token command' token_cmds
|
|
89
|
+
fi
|
|
90
|
+
;;
|
|
91
|
+
env)
|
|
92
|
+
if (( CURRENT == 3 )); then
|
|
93
|
+
local -a envs=('staging' 'production')
|
|
94
|
+
_describe 'environment' envs
|
|
95
|
+
fi
|
|
96
|
+
;;
|
|
97
|
+
models)
|
|
98
|
+
if (( CURRENT == 3 )); then
|
|
99
|
+
local -a tools=(${JBAI_MODELS_VALUES.map(v => `'${v}'`).join(' ')})
|
|
100
|
+
_describe 'tool filter' tools
|
|
101
|
+
fi
|
|
102
|
+
;;
|
|
103
|
+
install)
|
|
104
|
+
if (( CURRENT == 3 )); then
|
|
105
|
+
local -a tools=(${JBAI_INSTALL_VALUES.map(v => `'${v}'`).join(' ')})
|
|
106
|
+
_describe 'tool' tools
|
|
107
|
+
fi
|
|
108
|
+
;;
|
|
109
|
+
completions)
|
|
110
|
+
if (( CURRENT == 3 )); then
|
|
111
|
+
local -a opts=('--install:Add to ~/.zshrc' '--bash:Print bash completions')
|
|
112
|
+
_describe 'option' opts
|
|
113
|
+
fi
|
|
114
|
+
;;
|
|
115
|
+
esac
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
# Tool wrapper completions (jbai-claude, jbai-codex, etc.)
|
|
119
|
+
_jbai_tool_wrapper() {
|
|
120
|
+
_arguments -s \\
|
|
121
|
+
'--model[Model to use]:model:_jbai_models' \\
|
|
122
|
+
'-m[Model to use]:model:_jbai_models' \\
|
|
123
|
+
'--super[Enable super/auto mode]' \\
|
|
124
|
+
'--yolo[Enable super/auto mode]' \\
|
|
125
|
+
'-s[Enable super/auto mode]' \\
|
|
126
|
+
'--models[List available models]' \\
|
|
127
|
+
'--list-models[List available models]' \\
|
|
128
|
+
'--help[Show help]' \\
|
|
129
|
+
'models:List available models' \\
|
|
130
|
+
'*:pass-through:'
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
# Register completions
|
|
134
|
+
compdef _jbai jbai
|
|
135
|
+
compdef _jbai_tool_wrapper jbai-claude jbai-codex jbai-gemini jbai-opencode jbai-goose jbai-continue
|
|
136
|
+
compdef _jbai_tool_wrapper jbai-claude-opus jbai-claude-sonnet
|
|
137
|
+
compdef _jbai_tool_wrapper jbai-codex-5.2 jbai-codex-5.3 jbai-codex-5.4 jbai-codex-rockhopper
|
|
138
|
+
compdef _jbai_tool_wrapper jbai-gemini-3.1 jbai-gemini-supernova
|
|
139
|
+
compdef _jbai_tool_wrapper jbai-opencode-rockhopper jbai-opencode-grok jbai-opencode-deepseek
|
|
140
|
+
`;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
function generateBash() {
|
|
144
|
+
return `# ─── jbai-cli bash completions (auto-generated) ───
|
|
145
|
+
|
|
146
|
+
_jbai_completions() {
|
|
147
|
+
local cur="\${COMP_WORDS[COMP_CWORD]}"
|
|
148
|
+
local prev="\${COMP_WORDS[COMP_CWORD-1]}"
|
|
149
|
+
|
|
150
|
+
# jbai subcommands
|
|
151
|
+
if [[ "\${COMP_WORDS[0]}" == "jbai" && \${COMP_CWORD} -eq 1 ]]; then
|
|
152
|
+
COMPREPLY=( $(compgen -W "${JBAI_SUBCOMMANDS.join(' ')}" -- "$cur") )
|
|
153
|
+
return
|
|
154
|
+
fi
|
|
155
|
+
|
|
156
|
+
# jbai token <sub>
|
|
157
|
+
if [[ "\${COMP_WORDS[1]}" == "token" && \${COMP_CWORD} -eq 2 ]]; then
|
|
158
|
+
COMPREPLY=( $(compgen -W "${JBAI_TOKEN_SUBCOMMANDS.join(' ')}" -- "$cur") )
|
|
159
|
+
return
|
|
160
|
+
fi
|
|
161
|
+
|
|
162
|
+
# jbai env <value>
|
|
163
|
+
if [[ "\${COMP_WORDS[1]}" == "env" && \${COMP_CWORD} -eq 2 ]]; then
|
|
164
|
+
COMPREPLY=( $(compgen -W "${JBAI_ENV_VALUES.join(' ')}" -- "$cur") )
|
|
165
|
+
return
|
|
166
|
+
fi
|
|
167
|
+
|
|
168
|
+
# jbai models <value>
|
|
169
|
+
if [[ "\${COMP_WORDS[1]}" == "models" && \${COMP_CWORD} -eq 2 ]]; then
|
|
170
|
+
COMPREPLY=( $(compgen -W "${JBAI_MODELS_VALUES.join(' ')}" -- "$cur") )
|
|
171
|
+
return
|
|
172
|
+
fi
|
|
173
|
+
|
|
174
|
+
# jbai install <value>
|
|
175
|
+
if [[ "\${COMP_WORDS[1]}" == "install" && \${COMP_CWORD} -eq 2 ]]; then
|
|
176
|
+
COMPREPLY=( $(compgen -W "${JBAI_INSTALL_VALUES.join(' ')}" -- "$cur") )
|
|
177
|
+
return
|
|
178
|
+
fi
|
|
179
|
+
|
|
180
|
+
# --model completion
|
|
181
|
+
if [[ "$prev" == "--model" || "$prev" == "-m" ]]; then
|
|
182
|
+
COMPREPLY=( $(compgen -W "${UNIQUE_MODELS.join(' ')}" -- "$cur") )
|
|
183
|
+
return
|
|
184
|
+
fi
|
|
185
|
+
|
|
186
|
+
# Generic flags for tool wrappers
|
|
187
|
+
COMPREPLY=( $(compgen -W "--model --super --yolo --models --help models" -- "$cur") )
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
_jbai_tool_completions() {
|
|
191
|
+
local cur="\${COMP_WORDS[COMP_CWORD]}"
|
|
192
|
+
local prev="\${COMP_WORDS[COMP_CWORD-1]}"
|
|
193
|
+
|
|
194
|
+
if [[ "$prev" == "--model" || "$prev" == "-m" ]]; then
|
|
195
|
+
COMPREPLY=( $(compgen -W "${UNIQUE_MODELS.join(' ')}" -- "$cur") )
|
|
196
|
+
return
|
|
197
|
+
fi
|
|
198
|
+
|
|
199
|
+
COMPREPLY=( $(compgen -W "--model --super --yolo --models --help models" -- "$cur") )
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
complete -F _jbai_completions jbai
|
|
203
|
+
complete -F _jbai_tool_completions jbai-claude jbai-codex jbai-gemini jbai-opencode jbai-goose jbai-continue
|
|
204
|
+
complete -F _jbai_tool_completions jbai-claude-opus jbai-claude-sonnet
|
|
205
|
+
complete -F _jbai_tool_completions jbai-codex-5.2 jbai-codex-5.3 jbai-codex-5.4 jbai-codex-rockhopper
|
|
206
|
+
complete -F _jbai_tool_completions jbai-gemini-3.1 jbai-gemini-supernova
|
|
207
|
+
complete -F _jbai_tool_completions jbai-opencode-rockhopper jbai-opencode-grok jbai-opencode-deepseek
|
|
208
|
+
`;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
function getCompletionFilePath() {
|
|
212
|
+
return path.join(config.CONFIG_DIR, 'completions.zsh');
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
function installZsh() {
|
|
216
|
+
const completionFile = getCompletionFilePath();
|
|
217
|
+
const zshrc = path.join(os.homedir(), '.zshrc');
|
|
218
|
+
|
|
219
|
+
// Write completion file
|
|
220
|
+
config.ensureConfigDir();
|
|
221
|
+
fs.writeFileSync(completionFile, generateZsh(), { mode: 0o644 });
|
|
222
|
+
console.log(`Written: ${completionFile}`);
|
|
223
|
+
|
|
224
|
+
// Check if already sourced in .zshrc
|
|
225
|
+
const sourceLine = `[ -f "${completionFile}" ] && source "${completionFile}"`;
|
|
226
|
+
|
|
227
|
+
if (fs.existsSync(zshrc)) {
|
|
228
|
+
const content = fs.readFileSync(zshrc, 'utf-8');
|
|
229
|
+
if (content.includes('jbai') && content.includes('completions.zsh')) {
|
|
230
|
+
console.log('Already in ~/.zshrc — updating completion file only');
|
|
231
|
+
return;
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
fs.appendFileSync(zshrc, `\n# jbai-cli completions\n${sourceLine}\n`);
|
|
236
|
+
console.log('Added to ~/.zshrc');
|
|
237
|
+
console.log('\nRun: source ~/.zshrc (or open a new terminal)');
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
function run(args) {
|
|
241
|
+
if (args.includes('--install')) {
|
|
242
|
+
installZsh();
|
|
243
|
+
return;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
if (args.includes('--bash')) {
|
|
247
|
+
process.stdout.write(generateBash());
|
|
248
|
+
return;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
// Default: print zsh completions to stdout
|
|
252
|
+
process.stdout.write(generateZsh());
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
module.exports = { run, generateZsh, generateBash, installZsh, getCompletionFilePath };
|
package/lib/config.js
CHANGED
|
@@ -31,118 +31,50 @@ const ENDPOINTS = {
|
|
|
31
31
|
// Run 'node bin/test-models.js' to verify model availability
|
|
32
32
|
const MODELS = {
|
|
33
33
|
claude: {
|
|
34
|
-
default: 'claude-sonnet-4-
|
|
34
|
+
default: 'claude-sonnet-4-6',
|
|
35
35
|
available: [
|
|
36
|
-
// Claude 4.6 series (latest)
|
|
37
36
|
'claude-opus-4-6',
|
|
38
|
-
|
|
39
|
-
'claude-opus-4-5-20251101',
|
|
40
|
-
'claude-sonnet-4-5-20250929',
|
|
41
|
-
'claude-haiku-4-5-20251001',
|
|
42
|
-
// Claude 4.x series
|
|
43
|
-
'claude-opus-4-1-20250805',
|
|
44
|
-
'claude-sonnet-4-20250514',
|
|
45
|
-
// Claude 3.x series
|
|
46
|
-
'claude-3-7-sonnet-20250219',
|
|
47
|
-
'claude-3-5-haiku-20241022'
|
|
37
|
+
'claude-sonnet-4-6',
|
|
48
38
|
]
|
|
49
39
|
},
|
|
50
40
|
openai: {
|
|
51
41
|
// Chat/Completions models (used by OpenCode)
|
|
52
|
-
//
|
|
53
|
-
default: 'gpt-5.
|
|
42
|
+
// NOTE: codex-only models (gpt-5.x-codex) do NOT work on chat/completions
|
|
43
|
+
default: 'gpt-5.4',
|
|
54
44
|
available: [
|
|
55
|
-
|
|
56
|
-
'gpt-5.3-codex',
|
|
57
|
-
'gpt-5.2-2025-12-11',
|
|
45
|
+
'gpt-5.4',
|
|
58
46
|
'gpt-5.2',
|
|
59
|
-
'gpt-5.1-2025-11-13',
|
|
60
|
-
'gpt-5-2025-08-07',
|
|
61
|
-
'gpt-5-mini-2025-08-07',
|
|
62
|
-
'gpt-5-nano-2025-08-07',
|
|
63
|
-
// GPT-4.1 series
|
|
64
|
-
'gpt-4.1-2025-04-14',
|
|
65
|
-
'gpt-4.1-mini-2025-04-14',
|
|
66
|
-
'gpt-4.1-nano-2025-04-14',
|
|
67
|
-
// GPT-4o/4-turbo
|
|
68
|
-
'gpt-4o-2024-11-20',
|
|
69
|
-
'gpt-4o-mini-2024-07-18',
|
|
70
|
-
'gpt-4-turbo-2024-04-09',
|
|
71
|
-
'gpt-4-0613',
|
|
72
|
-
// O-series (reasoning) - use max_completion_tokens instead of max_tokens
|
|
73
|
-
'o4-mini-2025-04-16',
|
|
74
47
|
'o3-2025-04-16',
|
|
75
|
-
'o3-mini-2025-01-31',
|
|
76
|
-
'o1-2024-12-17',
|
|
77
|
-
// Legacy
|
|
78
|
-
'gpt-3.5-turbo-0125'
|
|
79
48
|
]
|
|
80
49
|
},
|
|
81
50
|
// Codex CLI uses OpenAI models via the "responses" API (wire_api = "responses")
|
|
82
|
-
// Includes chat-capable models PLUS codex-only models (responses API only)
|
|
83
51
|
codex: {
|
|
84
|
-
default: 'gpt-5.
|
|
52
|
+
default: 'gpt-5.4',
|
|
85
53
|
available: [
|
|
86
|
-
|
|
54
|
+
'gpt-5.4',
|
|
87
55
|
'gpt-5.3-codex',
|
|
88
|
-
'gpt-5.3-codex-api-preview',
|
|
89
|
-
// GPT-5.x chat models (also work via responses API)
|
|
90
|
-
'gpt-5.2-2025-12-11',
|
|
91
|
-
'gpt-5.2',
|
|
92
|
-
'gpt-5.1-2025-11-13',
|
|
93
|
-
'gpt-5-2025-08-07',
|
|
94
56
|
'gpt-5.2-codex',
|
|
95
|
-
'
|
|
96
|
-
'gpt-5.1-codex-max',
|
|
97
|
-
'gpt-5.1-codex',
|
|
98
|
-
'gpt-5.1-codex-mini',
|
|
99
|
-
'gpt-5-codex',
|
|
100
|
-
// O-series (also work via responses API)
|
|
101
|
-
'o4-mini-2025-04-16',
|
|
102
|
-
'o3-2025-04-16'
|
|
57
|
+
'o3-2025-04-16',
|
|
103
58
|
]
|
|
104
59
|
},
|
|
105
60
|
gemini: {
|
|
106
|
-
default: 'gemini-2.5-
|
|
61
|
+
default: 'gemini-2.5-pro',
|
|
107
62
|
available: [
|
|
108
|
-
|
|
63
|
+
'gemini-3.1-pro-preview',
|
|
109
64
|
'gemini-3-pro-preview',
|
|
110
|
-
'gemini-3-flash-preview',
|
|
111
|
-
// Gemini 2.5
|
|
112
65
|
'gemini-2.5-pro',
|
|
113
66
|
'gemini-2.5-flash',
|
|
114
|
-
'gemini-2.5-flash-lite',
|
|
115
|
-
// Gemini 2.0
|
|
116
|
-
'gemini-2.0-flash-001',
|
|
117
|
-
'gemini-2.0-flash-lite-001'
|
|
118
67
|
]
|
|
119
68
|
},
|
|
120
69
|
// Grazie native Chat API models — accessible via /grazie-openai/v1 translation layer.
|
|
121
70
|
// Full list is dynamic (fetched from /user/v5/llm/profiles), this is a static fallback.
|
|
71
|
+
// Only coding-capable models with tool use support.
|
|
122
72
|
grazie: {
|
|
123
|
-
default: '
|
|
73
|
+
default: 'xai-grok-4',
|
|
124
74
|
available: [
|
|
125
|
-
// Google
|
|
126
|
-
'google-gemini-3-1-pro',
|
|
127
|
-
'google-gemini-3-0-flash',
|
|
128
|
-
'google-chat-gemini-pro-2.5',
|
|
129
|
-
'google-gemini-2.5-flash',
|
|
130
|
-
// DeepSeek
|
|
131
|
-
'deepseek-r1',
|
|
132
|
-
'deepseek-chat-v3',
|
|
133
|
-
// Mistral
|
|
134
|
-
'mistral-large',
|
|
135
|
-
'mistral-small',
|
|
136
|
-
// xAI / Grok
|
|
137
75
|
'xai-grok-4',
|
|
138
|
-
'xai-grok-
|
|
139
|
-
'
|
|
140
|
-
// Qwen
|
|
141
|
-
'qwen-max',
|
|
142
|
-
'qwen-plus',
|
|
143
|
-
// Meta (via OpenRouter)
|
|
144
|
-
'openrouter-meta-llama-4-maverick',
|
|
145
|
-
'openrouter-meta-llama-4-scout',
|
|
76
|
+
'xai-grok-code-fast-1',
|
|
77
|
+
'deepseek-r1',
|
|
146
78
|
]
|
|
147
79
|
}
|
|
148
80
|
};
|
|
@@ -150,6 +82,10 @@ const MODELS = {
|
|
|
150
82
|
// Model aliases: some CLI tools send short names that Grazie doesn't recognise yet.
|
|
151
83
|
// Map them to the Grazie-accepted equivalents so the proxy can rewrite on the fly.
|
|
152
84
|
const MODEL_ALIASES = {
|
|
85
|
+
// Temporary compatibility mapping: staging currently exposes GPT-5.4 as spark preview.
|
|
86
|
+
// Keep user-facing defaults on gpt-5.4 and rewrite at the proxy edge.
|
|
87
|
+
'gpt-5.4': 'gpt-5.3-codex-spark-preview',
|
|
88
|
+
'openai-gpt-5-4': 'gpt-5.3-codex-spark-preview',
|
|
153
89
|
};
|
|
154
90
|
|
|
155
91
|
// All models for tools that support multiple providers (OpenCode, Codex)
|
package/lib/model-list.js
CHANGED
|
@@ -56,7 +56,7 @@ function getGroupsForTool(tool) {
|
|
|
56
56
|
defaultModel: config.MODELS.openai.default,
|
|
57
57
|
},
|
|
58
58
|
{
|
|
59
|
-
title: 'Grazie Native
|
|
59
|
+
title: 'Grazie Native (xAI, DeepSeek)',
|
|
60
60
|
models: config.MODELS.grazie.available,
|
|
61
61
|
defaultModel: config.MODELS.grazie.default,
|
|
62
62
|
},
|
|
@@ -85,7 +85,7 @@ function getGroupsForTool(tool) {
|
|
|
85
85
|
defaultModel: config.MODELS.gemini.default,
|
|
86
86
|
},
|
|
87
87
|
{
|
|
88
|
-
title: 'Grazie Native
|
|
88
|
+
title: 'Grazie Native (xAI, DeepSeek)',
|
|
89
89
|
models: config.MODELS.grazie.available,
|
|
90
90
|
defaultModel: config.MODELS.grazie.default,
|
|
91
91
|
},
|
package/lib/postinstall.js
CHANGED
|
@@ -1,30 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
const fs = require('fs');
|
|
4
|
-
const path = require('path');
|
|
5
3
|
const config = require('./config');
|
|
6
4
|
|
|
7
|
-
// Fix node-pty spawn-helper permissions (macOS/Linux)
|
|
8
|
-
// The prebuilt binary sometimes loses execute permissions during npm install
|
|
9
|
-
try {
|
|
10
|
-
const platform = process.platform === 'darwin' ? 'darwin' : process.platform;
|
|
11
|
-
const arch = process.arch;
|
|
12
|
-
const spawnHelperPath = path.join(
|
|
13
|
-
__dirname,
|
|
14
|
-
'..',
|
|
15
|
-
'node_modules',
|
|
16
|
-
'node-pty',
|
|
17
|
-
'prebuilds',
|
|
18
|
-
`${platform}-${arch}`,
|
|
19
|
-
'spawn-helper'
|
|
20
|
-
);
|
|
21
|
-
if (fs.existsSync(spawnHelperPath)) {
|
|
22
|
-
fs.chmodSync(spawnHelperPath, 0o755);
|
|
23
|
-
}
|
|
24
|
-
} catch {
|
|
25
|
-
// Ignore errors - this is a best-effort fix
|
|
26
|
-
}
|
|
27
|
-
|
|
28
5
|
console.log(`
|
|
29
6
|
╔══════════════════════════════════════════════════════════════╗
|
|
30
7
|
║ jbai-cli installed! ║
|
|
@@ -46,5 +23,8 @@ Next steps:
|
|
|
46
23
|
$ jbai-goose # Goose (Block)
|
|
47
24
|
$ jbai-continue # Continue CLI
|
|
48
25
|
|
|
26
|
+
4. Enable tab completions:
|
|
27
|
+
$ jbai completions --install
|
|
28
|
+
|
|
49
29
|
Run 'jbai help' for more options.
|
|
50
30
|
`);
|
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.1",
|
|
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,9 +30,20 @@
|
|
|
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-5.4": "bin/jbai-codex-5.4.js",
|
|
39
|
+
"jbai-codex-rockhopper": "bin/jbai-codex-rockhopper.js",
|
|
34
40
|
"jbai-gemini": "bin/jbai-gemini.js",
|
|
41
|
+
"jbai-gemini-3.1": "bin/jbai-gemini-3.1.js",
|
|
42
|
+
"jbai-gemini-supernova": "bin/jbai-gemini-supernova.js",
|
|
35
43
|
"jbai-opencode": "bin/jbai-opencode.js",
|
|
44
|
+
"jbai-opencode-rockhopper": "bin/jbai-opencode-rockhopper.js",
|
|
45
|
+
"jbai-opencode-grok": "bin/jbai-opencode-grok.js",
|
|
46
|
+
"jbai-opencode-deepseek": "bin/jbai-opencode-deepseek.js",
|
|
36
47
|
"jbai-goose": "bin/jbai-goose.js",
|
|
37
48
|
"jbai-continue": "bin/jbai-continue.js",
|
|
38
49
|
"jbai-council": "bin/jbai-council.js"
|
|
@@ -45,9 +56,7 @@
|
|
|
45
56
|
"engines": {
|
|
46
57
|
"node": ">=18.0.0"
|
|
47
58
|
},
|
|
48
|
-
"dependencies": {
|
|
49
|
-
"node-pty": "^1.1.0"
|
|
50
|
-
},
|
|
59
|
+
"dependencies": {},
|
|
51
60
|
"scripts": {
|
|
52
61
|
"postinstall": "node lib/postinstall.js",
|
|
53
62
|
"test": "node bin/jbai.js test"
|
package/lib/handoff.js
DELETED
|
@@ -1,152 +0,0 @@
|
|
|
1
|
-
const { execSync } = require('child_process');
|
|
2
|
-
const config = require('./config');
|
|
3
|
-
|
|
4
|
-
function getGitOutput(command, cwd = process.cwd()) {
|
|
5
|
-
try {
|
|
6
|
-
return execSync(command, { stdio: ['ignore', 'pipe', 'ignore'], cwd }).toString().trim();
|
|
7
|
-
} catch {
|
|
8
|
-
return '';
|
|
9
|
-
}
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
function getGitRepoUrl(cwd = process.cwd()) {
|
|
13
|
-
return getGitOutput('git remote get-url origin', cwd);
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
function getGitRef(cwd = process.cwd()) {
|
|
17
|
-
const branch = getGitOutput('git rev-parse --abbrev-ref HEAD', cwd);
|
|
18
|
-
if (branch && branch !== 'HEAD') {
|
|
19
|
-
return branch;
|
|
20
|
-
}
|
|
21
|
-
return getGitOutput('git rev-parse HEAD', cwd);
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
function openUrl(url) {
|
|
25
|
-
const escaped = url.replace(/"/g, '\\"');
|
|
26
|
-
try {
|
|
27
|
-
if (process.platform === 'darwin') {
|
|
28
|
-
execSync(`open "${escaped}"`, { stdio: 'ignore' });
|
|
29
|
-
return true;
|
|
30
|
-
}
|
|
31
|
-
if (process.platform === 'win32') {
|
|
32
|
-
execSync(`start "" "${escaped}"`, { stdio: 'ignore' });
|
|
33
|
-
return true;
|
|
34
|
-
}
|
|
35
|
-
execSync(`xdg-open "${escaped}"`, { stdio: 'ignore' });
|
|
36
|
-
return true;
|
|
37
|
-
} catch {
|
|
38
|
-
return false;
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
function normalizeGrazieEnvironment(env) {
|
|
43
|
-
if (!env) {
|
|
44
|
-
return config.getEnvironment() === 'production' ? 'PRODUCTION' : 'STAGING';
|
|
45
|
-
}
|
|
46
|
-
return env.toString().toUpperCase();
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
function getDefaultModel() {
|
|
50
|
-
return config.MODELS.claude.default;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
function parseBool(value, fallback) {
|
|
54
|
-
if (value === undefined || value === null) {
|
|
55
|
-
return fallback;
|
|
56
|
-
}
|
|
57
|
-
const normalized = value.toString().toLowerCase();
|
|
58
|
-
if (['0', 'false', 'no', 'off'].includes(normalized)) return false;
|
|
59
|
-
if (['1', 'true', 'yes', 'on'].includes(normalized)) return true;
|
|
60
|
-
return fallback;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
async function createHandoff({
|
|
64
|
-
task,
|
|
65
|
-
repoUrl,
|
|
66
|
-
ref,
|
|
67
|
-
branchName,
|
|
68
|
-
grazieToken,
|
|
69
|
-
grazieEnvironment,
|
|
70
|
-
grazieModel,
|
|
71
|
-
gitToken,
|
|
72
|
-
facadeToken,
|
|
73
|
-
orcaUrl,
|
|
74
|
-
source,
|
|
75
|
-
autoStart,
|
|
76
|
-
shouldOpen,
|
|
77
|
-
cwd,
|
|
78
|
-
}) {
|
|
79
|
-
const finalTask = task && task.trim()
|
|
80
|
-
? task.trim()
|
|
81
|
-
: 'Continue the current task from the CLI session.';
|
|
82
|
-
|
|
83
|
-
const finalRepoUrl = repoUrl && repoUrl.trim() ? repoUrl.trim() : getGitRepoUrl(cwd);
|
|
84
|
-
if (!finalRepoUrl) {
|
|
85
|
-
throw new Error('Could not determine git repo. Use --repo or set JBAI_HANDOFF_REPO.');
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
const finalGrazieToken = grazieToken || config.getToken();
|
|
89
|
-
if (!finalGrazieToken) {
|
|
90
|
-
throw new Error('No Grazie token found. Run: jbai token set');
|
|
91
|
-
}
|
|
92
|
-
if (config.isTokenExpired(finalGrazieToken)) {
|
|
93
|
-
throw new Error('Grazie token expired. Run: jbai token refresh');
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
const finalRef = ref || getGitRef(cwd);
|
|
97
|
-
const finalOrcaUrl = (orcaUrl || process.env.ORCA_LAB_URL || 'http://localhost:3000')
|
|
98
|
-
.replace(/\/$/, '');
|
|
99
|
-
const finalFacadeToken = facadeToken || process.env.FACADE_JWT_TOKEN || '';
|
|
100
|
-
const finalGitToken = gitToken || process.env.GITHUB_TOKEN || process.env.GH_TOKEN || '';
|
|
101
|
-
const finalGrazieEnv = normalizeGrazieEnvironment(
|
|
102
|
-
grazieEnvironment || process.env.JBAI_HANDOFF_ENV
|
|
103
|
-
);
|
|
104
|
-
const finalModel = grazieModel || process.env.JBAI_HANDOFF_MODEL || getDefaultModel();
|
|
105
|
-
const finalAutoStart = parseBool(autoStart ?? process.env.JBAI_HANDOFF_AUTO_START, true);
|
|
106
|
-
const openBrowser = parseBool(shouldOpen ?? process.env.JBAI_HANDOFF_OPEN, true);
|
|
107
|
-
|
|
108
|
-
const payload = {
|
|
109
|
-
task: finalTask,
|
|
110
|
-
repoUrl: finalRepoUrl,
|
|
111
|
-
ref: finalRef || undefined,
|
|
112
|
-
branchName: branchName || process.env.JBAI_HANDOFF_BRANCH || undefined,
|
|
113
|
-
gitToken: finalGitToken || undefined,
|
|
114
|
-
grazieToken: finalGrazieToken,
|
|
115
|
-
grazieEnvironment: finalGrazieEnv,
|
|
116
|
-
grazieModel: finalModel,
|
|
117
|
-
source: source || 'jbai-cli',
|
|
118
|
-
autoStart: finalAutoStart,
|
|
119
|
-
};
|
|
120
|
-
|
|
121
|
-
const headers = {
|
|
122
|
-
'Content-Type': 'application/json',
|
|
123
|
-
...(finalFacadeToken ? { Authorization: `Bearer ${finalFacadeToken}` } : {}),
|
|
124
|
-
};
|
|
125
|
-
|
|
126
|
-
const response = await fetch(`${finalOrcaUrl}/api/handoff`, {
|
|
127
|
-
method: 'POST',
|
|
128
|
-
headers,
|
|
129
|
-
body: JSON.stringify(payload),
|
|
130
|
-
});
|
|
131
|
-
|
|
132
|
-
if (!response.ok) {
|
|
133
|
-
const errorText = await response.text().catch(() => '');
|
|
134
|
-
const detail = errorText ? ` ${errorText}` : '';
|
|
135
|
-
throw new Error(`Orca Lab handoff failed (${response.status}).${detail}`);
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
const result = await response.json();
|
|
139
|
-
|
|
140
|
-
if (openBrowser && result.environmentUrl) {
|
|
141
|
-
openUrl(result.environmentUrl);
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
return result;
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
module.exports = {
|
|
148
|
-
createHandoff,
|
|
149
|
-
getGitRepoUrl,
|
|
150
|
-
getGitRef,
|
|
151
|
-
openUrl,
|
|
152
|
-
};
|