@nexus-cortex/cli 4.28.0 → 4.29.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/bin/cortex.js +87 -0
- package/package.json +2 -2
package/bin/cortex.js
CHANGED
|
@@ -112,6 +112,86 @@ if (args.includes('--version') || args.includes('-v')) {
|
|
|
112
112
|
process.exit(0);
|
|
113
113
|
}
|
|
114
114
|
|
|
115
|
+
// ── Setup wizard (interactive API-key onboarding) ─────────────────
|
|
116
|
+
// Global config lives at ~/.cortex/.env so a global npm install works from ANY
|
|
117
|
+
// folder (the server loads it). Runs on `cortex config init` and on first run
|
|
118
|
+
// when no key is configured anywhere.
|
|
119
|
+
const PROVIDERS = [
|
|
120
|
+
{ name: 'Anthropic (Claude)', keyVar: 'ANTHROPIC_API_KEY', model: 'claude-sonnet-4-6', hint: 'sk-ant-…' },
|
|
121
|
+
{ name: 'OpenAI (GPT)', keyVar: 'OPENAI_API_KEY', model: 'gpt-5-mini', hint: 'sk-…' },
|
|
122
|
+
{ name: 'Google (Gemini)', keyVar: 'GEMINI_API_KEY', model: 'gemini-2.5-flash', hint: 'AIza…' },
|
|
123
|
+
{ name: 'DeepSeek', keyVar: 'DEEPSEEK_API_KEY', model: 'deepseek-v4-pro', hint: 'sk-…' },
|
|
124
|
+
{ name: 'xAI (Grok)', keyVar: 'XAI_API_KEY', model: 'grok-4.3', hint: 'xai-…' },
|
|
125
|
+
];
|
|
126
|
+
const KEY_VARS = [...PROVIDERS.map((p) => p.keyVar), 'GOOGLE_API_KEY'];
|
|
127
|
+
const GLOBAL_ENV = join(homedir(), '.cortex', '.env');
|
|
128
|
+
|
|
129
|
+
function hasApiKey() {
|
|
130
|
+
if (KEY_VARS.some((k) => (process.env[k] || '').trim())) return true;
|
|
131
|
+
for (const f of [GLOBAL_ENV, join(process.cwd(), '.env')]) {
|
|
132
|
+
try {
|
|
133
|
+
const txt = readFileSync(f, 'utf8');
|
|
134
|
+
if (KEY_VARS.some((k) => new RegExp('^' + k + '=\\S', 'm').test(txt))) return true;
|
|
135
|
+
} catch { /* file absent */ }
|
|
136
|
+
}
|
|
137
|
+
return false;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
function writeGlobalEnv(kv) {
|
|
141
|
+
mkdirSync(dirname(GLOBAL_ENV), { recursive: true });
|
|
142
|
+
let lines = [];
|
|
143
|
+
try { lines = readFileSync(GLOBAL_ENV, 'utf8').split('\n').filter((l) => l.length); } catch { /* new file */ }
|
|
144
|
+
for (const [k, v] of Object.entries(kv)) {
|
|
145
|
+
const i = lines.findIndex((l) => l.startsWith(k + '='));
|
|
146
|
+
if (i >= 0) lines[i] = `${k}=${v}`; else lines.push(`${k}=${v}`);
|
|
147
|
+
}
|
|
148
|
+
writeFileSync(GLOBAL_ENV, lines.join('\n') + '\n', { mode: 0o600 }); // user-only — holds a secret
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
async function runSetupWizard() {
|
|
152
|
+
if (!process.stdin.isTTY) {
|
|
153
|
+
process.stderr.write(
|
|
154
|
+
'\n No API key configured. Run `cortex config init` for interactive setup, or set one:\n' +
|
|
155
|
+
' export ANTHROPIC_API_KEY=sk-ant-…\n' +
|
|
156
|
+
' export DEFAULT_MODEL_ID=claude-sonnet-4-6\n\n',
|
|
157
|
+
);
|
|
158
|
+
process.exit(1);
|
|
159
|
+
}
|
|
160
|
+
const { createInterface } = await import('node:readline/promises');
|
|
161
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
162
|
+
try {
|
|
163
|
+
process.stdout.write('\n Welcome to Nexus Cortex — quick setup (~30s).\n\n Which AI provider?\n');
|
|
164
|
+
PROVIDERS.forEach((p, i) => process.stdout.write(` ${i + 1}) ${p.name}\n`));
|
|
165
|
+
let choice;
|
|
166
|
+
for (;;) {
|
|
167
|
+
const n = parseInt((await rl.question(`\n Choose 1-${PROVIDERS.length}: `)).trim(), 10);
|
|
168
|
+
if (n >= 1 && n <= PROVIDERS.length) { choice = PROVIDERS[n - 1]; break; }
|
|
169
|
+
process.stdout.write(` Please enter a number 1-${PROVIDERS.length}.\n`);
|
|
170
|
+
}
|
|
171
|
+
let key = '';
|
|
172
|
+
while (!key) {
|
|
173
|
+
key = (await rl.question(`\n Paste your ${choice.name} API key (${choice.hint}): `)).trim();
|
|
174
|
+
if (!key) process.stdout.write(' An API key is required.\n');
|
|
175
|
+
}
|
|
176
|
+
const model = (await rl.question(`\n Default model [${choice.model}]: `)).trim() || choice.model;
|
|
177
|
+
writeGlobalEnv({ [choice.keyVar]: key, DEFAULT_MODEL_ID: model });
|
|
178
|
+
process.stdout.write(`\n ✓ Saved to ${GLOBAL_ENV}\n You're set — try: cortex "what is 2 + 2?"\n\n`);
|
|
179
|
+
} catch {
|
|
180
|
+
// Ctrl-C / Ctrl-D / closed input — exit cleanly instead of dumping a stack trace.
|
|
181
|
+
process.stdout.write('\n Setup cancelled. Run `cortex config init` any time to finish.\n');
|
|
182
|
+
rl.close();
|
|
183
|
+
process.exit(1);
|
|
184
|
+
} finally {
|
|
185
|
+
rl.close();
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
// `cortex config init` — interactive setup (intercept before the Commander handoff).
|
|
190
|
+
if (args[0] === 'config' && args[1] === 'init') {
|
|
191
|
+
await runSetupWizard();
|
|
192
|
+
process.exit(0);
|
|
193
|
+
}
|
|
194
|
+
|
|
115
195
|
// ── Headless Commander delegation ─────────────────────────────────
|
|
116
196
|
// `cortex` is primarily the HTTP chat/PR client; the headless Commander program
|
|
117
197
|
// (autoresearch, models, message, mcp, config, …) lives in dist/index.js. If the
|
|
@@ -390,6 +470,13 @@ async function run() {
|
|
|
390
470
|
return;
|
|
391
471
|
}
|
|
392
472
|
|
|
473
|
+
// First-run onboarding: no API key anywhere → walk the user through setup before
|
|
474
|
+
// starting the server. Skipped for pure server-management invocations.
|
|
475
|
+
const SKIP_SETUP = ['--help', '-h', '--stats', '--sessions', '--tmux'].some((f) => args.includes(f));
|
|
476
|
+
if (!SKIP_SETUP && !hasApiKey()) {
|
|
477
|
+
await runSetupWizard();
|
|
478
|
+
}
|
|
479
|
+
|
|
393
480
|
await ensureServer();
|
|
394
481
|
|
|
395
482
|
// --tmux: list active tmux sessions (served by SandboxViewServer on port+1)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nexus-cortex/cli",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.29.0",
|
|
4
4
|
"description": "Nexus Cortex CLI - Terminal interface for multi-provider LLM orchestration",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
"prepack": "node ../../scripts/copy-pkg-cortex-scaffold.mjs"
|
|
20
20
|
},
|
|
21
21
|
"dependencies": {
|
|
22
|
-
"@nexus-cortex/core": "^4.
|
|
22
|
+
"@nexus-cortex/core": "^4.29.0",
|
|
23
23
|
"chalk": "^4.1.2",
|
|
24
24
|
"cli-spinners": "^2.9.0",
|
|
25
25
|
"commander": "^11.0.0",
|