ventureos 1.0.5 → 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 +85 -15
- package/package.json +1 -1
package/install.js
CHANGED
|
@@ -15,11 +15,14 @@ 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);
|
|
21
22
|
|
|
22
23
|
// Must be defined before startChat() runs (accessed synchronously before first await)
|
|
24
|
+
let _spinner;
|
|
25
|
+
|
|
23
26
|
const PROVIDERS = {
|
|
24
27
|
anthropic: {
|
|
25
28
|
label: 'Claude (Anthropic)',
|
|
@@ -38,6 +41,11 @@ const PROVIDERS = {
|
|
|
38
41
|
},
|
|
39
42
|
};
|
|
40
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
|
+
|
|
41
49
|
const cmd = process.argv[2];
|
|
42
50
|
|
|
43
51
|
if (cmd === 'start') {
|
|
@@ -281,17 +289,41 @@ async function startChat() {
|
|
|
281
289
|
const providerKey = PROVIDERS[config.llm] ? config.llm : 'anthropic';
|
|
282
290
|
const provider = PROVIDERS[providerKey];
|
|
283
291
|
|
|
284
|
-
// ── Get API key
|
|
292
|
+
// ── Get API key or use CLI mode ────────────────────────────────────────────
|
|
285
293
|
let apiKey = process.env[provider.envVar];
|
|
294
|
+
let useCLI = false;
|
|
295
|
+
let cliCmd = null;
|
|
296
|
+
|
|
286
297
|
if (!apiKey) {
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
console.
|
|
291
|
-
|
|
292
|
-
|
|
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`);
|
|
293
326
|
}
|
|
294
|
-
console.log(`\n 💡 Tip: export ${provider.envVar}=your-key to skip this next time.\n`);
|
|
295
327
|
}
|
|
296
328
|
|
|
297
329
|
// ── Load system prompt ─────────────────────────────────────────────────────
|
|
@@ -318,7 +350,7 @@ async function startChat() {
|
|
|
318
350
|
`--- ventureOS/_memory/venture-state.yaml ---\n${stateContent}`;
|
|
319
351
|
|
|
320
352
|
console.log(line());
|
|
321
|
-
console.log(` ✓ Connected to ${provider.label}`);
|
|
353
|
+
console.log(` ✓ Connected ${useCLI ? `via ${cliCmd} CLI` : `to ${provider.label}`}`);
|
|
322
354
|
console.log(` ✓ Type your message and press Enter. Type "exit" or Ctrl+C to quit.`);
|
|
323
355
|
console.log(line() + '\n');
|
|
324
356
|
|
|
@@ -328,9 +360,9 @@ async function startChat() {
|
|
|
328
360
|
showSpinner(' Victor is thinking');
|
|
329
361
|
let firstResponse;
|
|
330
362
|
try {
|
|
331
|
-
firstResponse =
|
|
332
|
-
{ role: 'user', content: activationMsg }
|
|
333
|
-
|
|
363
|
+
firstResponse = useCLI
|
|
364
|
+
? await callViaCLI(cliCmd, systemPrompt, [{ role: 'user', content: activationMsg }])
|
|
365
|
+
: await callLLM(providerKey, apiKey, provider.defaultModel, systemPrompt, [{ role: 'user', content: activationMsg }]);
|
|
334
366
|
} catch (err) {
|
|
335
367
|
stopSpinner();
|
|
336
368
|
console.error(`\n ❌ API error: ${err.message}`);
|
|
@@ -366,7 +398,9 @@ async function startChat() {
|
|
|
366
398
|
showSpinner(' Victor is thinking');
|
|
367
399
|
let response;
|
|
368
400
|
try {
|
|
369
|
-
response =
|
|
401
|
+
response = useCLI
|
|
402
|
+
? await callViaCLI(cliCmd, systemPrompt, messages)
|
|
403
|
+
: await callLLM(providerKey, apiKey, provider.defaultModel, systemPrompt, messages);
|
|
370
404
|
} catch (err) {
|
|
371
405
|
stopSpinner();
|
|
372
406
|
console.error(`\n ❌ API error: ${err.message}\n`);
|
|
@@ -383,9 +417,20 @@ async function startChat() {
|
|
|
383
417
|
rl.close();
|
|
384
418
|
}
|
|
385
419
|
|
|
386
|
-
// ───
|
|
420
|
+
// ─── CLI Detection ─────────────────────────────────────────────────────────────
|
|
387
421
|
|
|
388
|
-
|
|
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
|
+
|
|
433
|
+
// ─── Spinner ───────────────────────────────────────────────────────────────────
|
|
389
434
|
function showSpinner(msg) {
|
|
390
435
|
const frames = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];
|
|
391
436
|
let i = 0;
|
|
@@ -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',
|