ventureos 1.0.6 → 1.0.7
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/install.js +83 -13
- package/package.json +1 -1
package/install.js
CHANGED
|
@@ -15,6 +15,7 @@ import { stdin as input, stdout as output } from 'process';
|
|
|
15
15
|
import fs from 'fs';
|
|
16
16
|
import path from 'path';
|
|
17
17
|
import { fileURLToPath } from 'url';
|
|
18
|
+
import { spawnSync } from 'child_process';
|
|
18
19
|
|
|
19
20
|
const __filename = fileURLToPath(import.meta.url);
|
|
20
21
|
const PACKAGE_ROOT = path.dirname(__filename);
|
|
@@ -40,6 +41,11 @@ const PROVIDERS = {
|
|
|
40
41
|
},
|
|
41
42
|
};
|
|
42
43
|
|
|
44
|
+
// CLI tools that can be used instead of an API key
|
|
45
|
+
const CLI_TOOLS = {
|
|
46
|
+
anthropic: { cmd: 'claude', label: 'Claude CLI' },
|
|
47
|
+
};
|
|
48
|
+
|
|
43
49
|
const cmd = process.argv[2];
|
|
44
50
|
|
|
45
51
|
if (cmd === 'start') {
|
|
@@ -283,17 +289,41 @@ async function startChat() {
|
|
|
283
289
|
const providerKey = PROVIDERS[config.llm] ? config.llm : 'anthropic';
|
|
284
290
|
const provider = PROVIDERS[providerKey];
|
|
285
291
|
|
|
286
|
-
// ── Get API key
|
|
292
|
+
// ── Get API key or use CLI mode ────────────────────────────────────────────
|
|
287
293
|
let apiKey = process.env[provider.envVar];
|
|
294
|
+
let useCLI = false;
|
|
295
|
+
let cliCmd = null;
|
|
296
|
+
|
|
288
297
|
if (!apiKey) {
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
console.
|
|
293
|
-
|
|
294
|
-
|
|
298
|
+
const cli = detectCLI(providerKey);
|
|
299
|
+
if (cli) {
|
|
300
|
+
console.log(`\n 🔑 ${provider.envVar} not set in environment.\n`);
|
|
301
|
+
console.log(` How would you like to connect?\n`);
|
|
302
|
+
console.log(` 1. Enter API key`);
|
|
303
|
+
console.log(` 2. Use ${cli.label} (detected on your system)\n`);
|
|
304
|
+
const choice = (await rl.question(' Select [1-2]: ')).trim();
|
|
305
|
+
if (choice === '2') {
|
|
306
|
+
useCLI = true;
|
|
307
|
+
cliCmd = cli.cmd;
|
|
308
|
+
} else {
|
|
309
|
+
apiKey = (await rl.question(`\n Enter your ${provider.label} API key: `)).trim();
|
|
310
|
+
if (!apiKey) {
|
|
311
|
+
console.error('\n ❌ No API key provided.\n');
|
|
312
|
+
rl.close();
|
|
313
|
+
process.exit(1);
|
|
314
|
+
}
|
|
315
|
+
console.log(`\n 💡 Tip: export ${provider.envVar}=your-key to skip this next time.\n`);
|
|
316
|
+
}
|
|
317
|
+
} else {
|
|
318
|
+
console.log(`\n 🔑 ${provider.envVar} not set in environment.`);
|
|
319
|
+
apiKey = (await rl.question(` Enter your ${provider.label} API key: `)).trim();
|
|
320
|
+
if (!apiKey) {
|
|
321
|
+
console.error('\n ❌ No API key provided.\n');
|
|
322
|
+
rl.close();
|
|
323
|
+
process.exit(1);
|
|
324
|
+
}
|
|
325
|
+
console.log(`\n 💡 Tip: export ${provider.envVar}=your-key to skip this next time.\n`);
|
|
295
326
|
}
|
|
296
|
-
console.log(`\n 💡 Tip: export ${provider.envVar}=your-key to skip this next time.\n`);
|
|
297
327
|
}
|
|
298
328
|
|
|
299
329
|
// ── Load system prompt ─────────────────────────────────────────────────────
|
|
@@ -320,7 +350,7 @@ async function startChat() {
|
|
|
320
350
|
`--- ventureOS/_memory/venture-state.yaml ---\n${stateContent}`;
|
|
321
351
|
|
|
322
352
|
console.log(line());
|
|
323
|
-
console.log(` ✓ Connected to ${provider.label}`);
|
|
353
|
+
console.log(` ✓ Connected ${useCLI ? `via ${cliCmd} CLI` : `to ${provider.label}`}`);
|
|
324
354
|
console.log(` ✓ Type your message and press Enter. Type "exit" or Ctrl+C to quit.`);
|
|
325
355
|
console.log(line() + '\n');
|
|
326
356
|
|
|
@@ -330,9 +360,9 @@ async function startChat() {
|
|
|
330
360
|
showSpinner(' Victor is thinking');
|
|
331
361
|
let firstResponse;
|
|
332
362
|
try {
|
|
333
|
-
firstResponse =
|
|
334
|
-
{ role: 'user', content: activationMsg }
|
|
335
|
-
|
|
363
|
+
firstResponse = useCLI
|
|
364
|
+
? await callViaCLI(cliCmd, systemPrompt, [{ role: 'user', content: activationMsg }])
|
|
365
|
+
: await callLLM(providerKey, apiKey, provider.defaultModel, systemPrompt, [{ role: 'user', content: activationMsg }]);
|
|
336
366
|
} catch (err) {
|
|
337
367
|
stopSpinner();
|
|
338
368
|
console.error(`\n ❌ API error: ${err.message}`);
|
|
@@ -368,7 +398,9 @@ async function startChat() {
|
|
|
368
398
|
showSpinner(' Victor is thinking');
|
|
369
399
|
let response;
|
|
370
400
|
try {
|
|
371
|
-
response =
|
|
401
|
+
response = useCLI
|
|
402
|
+
? await callViaCLI(cliCmd, systemPrompt, messages)
|
|
403
|
+
: await callLLM(providerKey, apiKey, provider.defaultModel, systemPrompt, messages);
|
|
372
404
|
} catch (err) {
|
|
373
405
|
stopSpinner();
|
|
374
406
|
console.error(`\n ❌ API error: ${err.message}\n`);
|
|
@@ -385,6 +417,19 @@ async function startChat() {
|
|
|
385
417
|
rl.close();
|
|
386
418
|
}
|
|
387
419
|
|
|
420
|
+
// ─── CLI Detection ─────────────────────────────────────────────────────────────
|
|
421
|
+
|
|
422
|
+
function detectCLI(providerKey) {
|
|
423
|
+
const tool = CLI_TOOLS[providerKey];
|
|
424
|
+
if (!tool) return null;
|
|
425
|
+
try {
|
|
426
|
+
const result = spawnSync('which', [tool.cmd], { encoding: 'utf8', stdio: 'pipe' });
|
|
427
|
+
return result.status === 0 && result.stdout.trim() ? tool : null;
|
|
428
|
+
} catch {
|
|
429
|
+
return null;
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
|
|
388
433
|
// ─── Spinner ───────────────────────────────────────────────────────────────────
|
|
389
434
|
function showSpinner(msg) {
|
|
390
435
|
const frames = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];
|
|
@@ -442,6 +487,31 @@ async function callLLM(provider, apiKey, model, system, messages) {
|
|
|
442
487
|
throw new Error(`Unknown provider: ${provider}`);
|
|
443
488
|
}
|
|
444
489
|
|
|
490
|
+
async function callViaCLI(cliCmd, system, messages) {
|
|
491
|
+
// Build full context: system + conversation history + latest user message
|
|
492
|
+
let prompt = system + '\n\n';
|
|
493
|
+
|
|
494
|
+
for (const msg of messages.slice(0, -1)) {
|
|
495
|
+
const role = msg.role === 'user' ? 'Human' : 'Assistant';
|
|
496
|
+
prompt += `${role}: ${msg.content}\n\n`;
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
const lastMsg = messages[messages.length - 1];
|
|
500
|
+
prompt += `Human: ${lastMsg.content}`;
|
|
501
|
+
|
|
502
|
+
const result = spawnSync(cliCmd, ['-p', prompt], {
|
|
503
|
+
encoding: 'utf8',
|
|
504
|
+
maxBuffer: 10 * 1024 * 1024,
|
|
505
|
+
timeout: 120000,
|
|
506
|
+
});
|
|
507
|
+
|
|
508
|
+
if (result.error) throw result.error;
|
|
509
|
+
if (result.status !== 0) {
|
|
510
|
+
throw new Error(result.stderr?.trim() || `${cliCmd} CLI exited with code ${result.status}`);
|
|
511
|
+
}
|
|
512
|
+
return result.stdout.trim();
|
|
513
|
+
}
|
|
514
|
+
|
|
445
515
|
async function callAnthropic(apiKey, model, system, messages) {
|
|
446
516
|
const res = await fetch('https://api.anthropic.com/v1/messages', {
|
|
447
517
|
method: 'POST',
|