code-graph-builder 0.22.0 → 0.25.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/cli.mjs +185 -139
- package/package.json +1 -1
package/bin/cli.mjs
CHANGED
|
@@ -21,7 +21,8 @@ const MODULE_PATH = "code_graph_builder.mcp.server";
|
|
|
21
21
|
const WORKSPACE_DIR = join(homedir(), ".code-graph-builder");
|
|
22
22
|
const ENV_FILE = join(WORKSPACE_DIR, ".env");
|
|
23
23
|
const IS_WIN = platform() === "win32";
|
|
24
|
-
|
|
24
|
+
// Removed hardcoded PyPI index — pip will use the user's configured source
|
|
25
|
+
// (e.g. mirrors in pip.conf / pip.ini)
|
|
25
26
|
|
|
26
27
|
// ---------------------------------------------------------------------------
|
|
27
28
|
// Tree-style UI helpers
|
|
@@ -51,14 +52,16 @@ const T = {
|
|
|
51
52
|
/**
|
|
52
53
|
* Interactive single-select menu.
|
|
53
54
|
* Arrow keys to navigate, Space to select, Enter to confirm.
|
|
54
|
-
* Returns the index of the selected option,
|
|
55
|
+
* Returns the index of the selected option, -1 if cancelled (Ctrl+C),
|
|
56
|
+
* or -2 if the user pressed ← (back to previous step).
|
|
55
57
|
*
|
|
56
58
|
* @param {string[]} options - Display labels for each option
|
|
57
59
|
* @param {string} prefix - Tree prefix for each line (e.g. " │ ")
|
|
58
60
|
* @param {number} defaultIndex - Initially highlighted index
|
|
61
|
+
* @param {boolean} allowBack - Whether ← arrow triggers back (-2)
|
|
59
62
|
* @returns {Promise<number>}
|
|
60
63
|
*/
|
|
61
|
-
function selectMenu(options, prefix = " ", defaultIndex = 0) {
|
|
64
|
+
function selectMenu(options, prefix = " ", defaultIndex = 0, allowBack = false) {
|
|
62
65
|
return new Promise((resolve) => {
|
|
63
66
|
const out = process.stderr;
|
|
64
67
|
let cursor = defaultIndex;
|
|
@@ -71,10 +74,12 @@ function selectMenu(options, prefix = " ", defaultIndex = 0) {
|
|
|
71
74
|
const CYAN = "\x1b[36m";
|
|
72
75
|
const RESET = "\x1b[0m";
|
|
73
76
|
|
|
77
|
+
const backHint = allowBack ? `${DIM} ← back${RESET}` : "";
|
|
78
|
+
|
|
74
79
|
function render(initial = false) {
|
|
75
80
|
// Move cursor up to overwrite previous render (skip on first draw)
|
|
76
81
|
if (!initial) {
|
|
77
|
-
out.write(`\x1b[${options.length}A`);
|
|
82
|
+
out.write(`\x1b[${options.length + (allowBack ? 1 : 0)}A`);
|
|
78
83
|
}
|
|
79
84
|
for (let i = 0; i < options.length; i++) {
|
|
80
85
|
const isActive = i === cursor;
|
|
@@ -88,6 +93,9 @@ function selectMenu(options, prefix = " ", defaultIndex = 0) {
|
|
|
88
93
|
// Clear line then write
|
|
89
94
|
out.write(`\x1b[2K${prefix}${radio} ${label}\n`);
|
|
90
95
|
}
|
|
96
|
+
if (allowBack) {
|
|
97
|
+
out.write(`\x1b[2K${prefix}${DIM}← Back to previous step${RESET}\n`);
|
|
98
|
+
}
|
|
91
99
|
}
|
|
92
100
|
|
|
93
101
|
// Hide cursor
|
|
@@ -116,6 +124,13 @@ function selectMenu(options, prefix = " ", defaultIndex = 0) {
|
|
|
116
124
|
return;
|
|
117
125
|
}
|
|
118
126
|
|
|
127
|
+
// Arrow left — back to previous step
|
|
128
|
+
if (key === "\x1b[D" && allowBack) {
|
|
129
|
+
cleanup();
|
|
130
|
+
resolve(-2);
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
|
|
119
134
|
// Arrow up / k
|
|
120
135
|
if (key === "\x1b[A" || key === "k") {
|
|
121
136
|
cursor = (cursor - 1 + options.length) % options.length;
|
|
@@ -328,28 +343,18 @@ async function runSetup() {
|
|
|
328
343
|
// Load existing config
|
|
329
344
|
const existing = loadEnvFile();
|
|
330
345
|
|
|
331
|
-
//
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
log(` ${T.DOT} Step 2/3 LLM Provider`);
|
|
344
|
-
log(` ${T.SIDE}`);
|
|
345
|
-
log(` ${T.BRANCH} For natural language queries & descriptions`);
|
|
346
|
-
log(` ${T.SIDE} Use ↑↓ to navigate, Space to select, Enter to confirm`);
|
|
347
|
-
log(` ${T.SIDE}`);
|
|
348
|
-
|
|
349
|
-
if (existing.LLM_API_KEY) {
|
|
350
|
-
log(` ${T.SIDE} Current: ${mask(existing.LLM_API_KEY)} → ${existing.LLM_BASE_URL || "?"}`);
|
|
351
|
-
log(` ${T.SIDE}`);
|
|
352
|
-
}
|
|
346
|
+
// Step results — preserved across back/forward navigation
|
|
347
|
+
let workspace = existing.CGB_WORKSPACE || WORKSPACE_DIR;
|
|
348
|
+
let llmKey = existing.LLM_API_KEY || "";
|
|
349
|
+
let llmBaseUrl = existing.LLM_BASE_URL || "";
|
|
350
|
+
let llmModel = existing.LLM_MODEL || "";
|
|
351
|
+
let llmProviderName = "skipped";
|
|
352
|
+
let embedKey = "";
|
|
353
|
+
let embedUrl = "";
|
|
354
|
+
let embedModel = "";
|
|
355
|
+
let embedKeyEnv = "DASHSCOPE_API_KEY";
|
|
356
|
+
let embedUrlEnv = "DASHSCOPE_BASE_URL";
|
|
357
|
+
let embedProviderName = "skipped";
|
|
353
358
|
|
|
354
359
|
const llmOptions = [
|
|
355
360
|
"Moonshot / Kimi platform.moonshot.cn",
|
|
@@ -369,66 +374,6 @@ async function runSetup() {
|
|
|
369
374
|
{ name: "LiteLLM", url: "http://localhost:4000/v1", model: "gpt-4o" },
|
|
370
375
|
];
|
|
371
376
|
|
|
372
|
-
// Close readline before raw mode menu, reopen after
|
|
373
|
-
rl.close();
|
|
374
|
-
const llmChoice = await selectMenu(llmOptions, ` ${T.SIDE} `, 6);
|
|
375
|
-
rl = createInterface({ input: process.stdin, output: process.stderr });
|
|
376
|
-
ask = (q) => new Promise((resolve) => rl.question(q, resolve));
|
|
377
|
-
|
|
378
|
-
let llmKey = existing.LLM_API_KEY || "";
|
|
379
|
-
let llmBaseUrl = existing.LLM_BASE_URL || "";
|
|
380
|
-
let llmModel = existing.LLM_MODEL || "";
|
|
381
|
-
let llmProviderName = "skipped";
|
|
382
|
-
|
|
383
|
-
if (llmChoice >= 0 && llmChoice < 5) {
|
|
384
|
-
// Known provider
|
|
385
|
-
const provider = llmProviders[llmChoice];
|
|
386
|
-
llmBaseUrl = provider.url;
|
|
387
|
-
llmModel = provider.model;
|
|
388
|
-
llmProviderName = provider.name;
|
|
389
|
-
|
|
390
|
-
log(` ${T.SIDE}`);
|
|
391
|
-
llmKey = (await ask(` ${T.SIDE} API Key (sk-...): `)).trim() || existing.LLM_API_KEY || "";
|
|
392
|
-
|
|
393
|
-
if (llmKey) {
|
|
394
|
-
const urlOverride = (await ask(` ${T.SIDE} Base URL [${llmBaseUrl}]: `)).trim();
|
|
395
|
-
if (urlOverride) llmBaseUrl = urlOverride;
|
|
396
|
-
const modelOverride = (await ask(` ${T.SIDE} Model [${llmModel}]: `)).trim();
|
|
397
|
-
if (modelOverride) llmModel = modelOverride;
|
|
398
|
-
}
|
|
399
|
-
} else if (llmChoice === 5) {
|
|
400
|
-
// Custom
|
|
401
|
-
llmProviderName = "Custom";
|
|
402
|
-
const defUrl = llmBaseUrl || existing.LLM_BASE_URL || "";
|
|
403
|
-
const defModel = llmModel || existing.LLM_MODEL || "gpt-4o";
|
|
404
|
-
const defKey = existing.LLM_API_KEY || "";
|
|
405
|
-
log(` ${T.SIDE}`);
|
|
406
|
-
llmBaseUrl = (await ask(` ${T.SIDE} API Base URL${defUrl ? ` [${defUrl}]` : ""}: `)).trim() || defUrl;
|
|
407
|
-
llmModel = (await ask(` ${T.SIDE} Model${defModel ? ` [${defModel}]` : ""}: `)).trim() || defModel;
|
|
408
|
-
llmKey = (await ask(` ${T.SIDE} API Key${defKey ? ` [${mask(defKey)}]` : " (sk-...)"}: `)).trim() || defKey;
|
|
409
|
-
}
|
|
410
|
-
// llmChoice === 6 or -1 → skip
|
|
411
|
-
|
|
412
|
-
if (llmKey) {
|
|
413
|
-
log(` ${T.LAST} ${T.OK} ${llmProviderName} / ${llmModel}`);
|
|
414
|
-
} else {
|
|
415
|
-
log(` ${T.LAST} ${T.WARN} Skipped (configure later in ${ENV_FILE})`);
|
|
416
|
-
}
|
|
417
|
-
log();
|
|
418
|
-
|
|
419
|
-
// --- Step 3: Embedding Provider ---
|
|
420
|
-
log(` ${T.DOT} Step 3/3 Embedding Provider`);
|
|
421
|
-
log(` ${T.SIDE}`);
|
|
422
|
-
log(` ${T.BRANCH} For semantic code search`);
|
|
423
|
-
log(` ${T.SIDE} Use ↑↓ to navigate, Space to select, Enter to confirm`);
|
|
424
|
-
log(` ${T.SIDE}`);
|
|
425
|
-
|
|
426
|
-
if (existing.DASHSCOPE_API_KEY || existing.EMBED_API_KEY) {
|
|
427
|
-
const ek = existing.DASHSCOPE_API_KEY || existing.EMBED_API_KEY;
|
|
428
|
-
log(` ${T.SIDE} Current: ${mask(ek)} → ${existing.DASHSCOPE_BASE_URL || existing.EMBED_BASE_URL || "?"}`);
|
|
429
|
-
log(` ${T.SIDE}`);
|
|
430
|
-
}
|
|
431
|
-
|
|
432
377
|
const embedOptions = [
|
|
433
378
|
"DashScope / Qwen dashscope.console.aliyun.com (free tier)",
|
|
434
379
|
"OpenAI Embeddings platform.openai.com",
|
|
@@ -441,56 +386,157 @@ async function runSetup() {
|
|
|
441
386
|
{ name: "OpenAI", url: "https://api.openai.com/v1", model: "text-embedding-3-small", keyEnv: "OPENAI_API_KEY", urlEnv: "OPENAI_BASE_URL" },
|
|
442
387
|
];
|
|
443
388
|
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
rl = createInterface({ input: process.stdin, output: process.stderr });
|
|
447
|
-
ask = (q) => new Promise((resolve) => rl.question(q, resolve));
|
|
389
|
+
// --- Step-based wizard with ← back support ---
|
|
390
|
+
let step = 1;
|
|
448
391
|
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
392
|
+
while (step >= 1 && step <= 3) {
|
|
393
|
+
|
|
394
|
+
// ─── Step 1: Workspace ───
|
|
395
|
+
if (step === 1) {
|
|
396
|
+
log(` ${T.DOT} Step 1/3 Workspace`);
|
|
397
|
+
log(` ${T.SIDE}`);
|
|
398
|
+
log(` ${T.BRANCH} Stores indexed repos, graphs, and embeddings`);
|
|
455
399
|
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
embedProviderName = ep.name;
|
|
464
|
-
|
|
465
|
-
log(` ${T.SIDE}`);
|
|
466
|
-
embedKey = (await ask(` ${T.SIDE} API Key: `)).trim() ||
|
|
467
|
-
existing[embedKeyEnv] || existing.DASHSCOPE_API_KEY || "";
|
|
468
|
-
|
|
469
|
-
if (embedKey) {
|
|
470
|
-
const urlOverride = (await ask(` ${T.SIDE} Base URL [${embedUrl}]: `)).trim();
|
|
471
|
-
if (urlOverride) embedUrl = urlOverride;
|
|
472
|
-
const modelOverride = (await ask(` ${T.SIDE} Model [${embedModel}]: `)).trim();
|
|
473
|
-
if (modelOverride) embedModel = modelOverride;
|
|
400
|
+
workspace =
|
|
401
|
+
(await ask(` ${T.SIDE} Path [${WORKSPACE_DIR}]: `)).trim() || WORKSPACE_DIR;
|
|
402
|
+
|
|
403
|
+
log(` ${T.LAST} ${T.OK} ${workspace}`);
|
|
404
|
+
log();
|
|
405
|
+
step = 2;
|
|
406
|
+
continue;
|
|
474
407
|
}
|
|
475
|
-
} else if (embedChoice === 2) {
|
|
476
|
-
// Custom
|
|
477
|
-
embedProviderName = "Custom";
|
|
478
|
-
const defEmbedUrl = existing.EMBED_BASE_URL || existing.DASHSCOPE_BASE_URL || "";
|
|
479
|
-
const defEmbedModel = existing.EMBED_MODEL || "text-embedding-3-small";
|
|
480
|
-
const defEmbedKey = existing.EMBED_API_KEY || existing.DASHSCOPE_API_KEY || "";
|
|
481
|
-
log(` ${T.SIDE}`);
|
|
482
|
-
embedUrl = (await ask(` ${T.SIDE} API Base URL${defEmbedUrl ? ` [${defEmbedUrl}]` : ""}: `)).trim() || defEmbedUrl;
|
|
483
|
-
embedModel = (await ask(` ${T.SIDE} Model${defEmbedModel ? ` [${defEmbedModel}]` : ""}: `)).trim() || defEmbedModel;
|
|
484
|
-
embedKey = (await ask(` ${T.SIDE} API Key${defEmbedKey ? ` [${mask(defEmbedKey)}]` : ""}: `)).trim() || defEmbedKey;
|
|
485
|
-
embedKeyEnv = "EMBED_API_KEY";
|
|
486
|
-
embedUrlEnv = "EMBED_BASE_URL";
|
|
487
|
-
}
|
|
488
|
-
// embedChoice === 3 or -1 → skip
|
|
489
408
|
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
}
|
|
493
|
-
|
|
409
|
+
// ─── Step 2: LLM Provider ───
|
|
410
|
+
if (step === 2) {
|
|
411
|
+
log(` ${T.DOT} Step 2/3 LLM Provider`);
|
|
412
|
+
log(` ${T.SIDE}`);
|
|
413
|
+
log(` ${T.BRANCH} For natural language queries & descriptions`);
|
|
414
|
+
log(` ${T.SIDE} Use ↑↓ navigate, Enter confirm, ← back`);
|
|
415
|
+
log(` ${T.SIDE}`);
|
|
416
|
+
|
|
417
|
+
if (existing.LLM_API_KEY) {
|
|
418
|
+
log(` ${T.SIDE} Current: ${mask(existing.LLM_API_KEY)} → ${existing.LLM_BASE_URL || "?"}`);
|
|
419
|
+
log(` ${T.SIDE}`);
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
rl.close();
|
|
423
|
+
const llmChoice = await selectMenu(llmOptions, ` ${T.SIDE} `, 6, true);
|
|
424
|
+
rl = createInterface({ input: process.stdin, output: process.stderr });
|
|
425
|
+
ask = (q) => new Promise((resolve) => rl.question(q, resolve));
|
|
426
|
+
|
|
427
|
+
if (llmChoice === -2) { log(); step = 1; continue; }
|
|
428
|
+
if (llmChoice === -1) { rl.close(); return; }
|
|
429
|
+
|
|
430
|
+
llmKey = existing.LLM_API_KEY || "";
|
|
431
|
+
llmBaseUrl = existing.LLM_BASE_URL || "";
|
|
432
|
+
llmModel = existing.LLM_MODEL || "";
|
|
433
|
+
llmProviderName = "skipped";
|
|
434
|
+
|
|
435
|
+
if (llmChoice >= 0 && llmChoice < 5) {
|
|
436
|
+
const provider = llmProviders[llmChoice];
|
|
437
|
+
llmBaseUrl = provider.url;
|
|
438
|
+
llmModel = provider.model;
|
|
439
|
+
llmProviderName = provider.name;
|
|
440
|
+
|
|
441
|
+
log(` ${T.SIDE}`);
|
|
442
|
+
llmKey = (await ask(` ${T.SIDE} API Key (sk-...): `)).trim() || existing.LLM_API_KEY || "";
|
|
443
|
+
|
|
444
|
+
if (llmKey) {
|
|
445
|
+
const urlOverride = (await ask(` ${T.SIDE} Base URL [${llmBaseUrl}]: `)).trim();
|
|
446
|
+
if (urlOverride) llmBaseUrl = urlOverride;
|
|
447
|
+
const modelOverride = (await ask(` ${T.SIDE} Model [${llmModel}]: `)).trim();
|
|
448
|
+
if (modelOverride) llmModel = modelOverride;
|
|
449
|
+
}
|
|
450
|
+
} else if (llmChoice === 5) {
|
|
451
|
+
llmProviderName = "Custom";
|
|
452
|
+
const defUrl = llmBaseUrl || existing.LLM_BASE_URL || "";
|
|
453
|
+
const defModel = llmModel || existing.LLM_MODEL || "gpt-4o";
|
|
454
|
+
const defKey = existing.LLM_API_KEY || "";
|
|
455
|
+
log(` ${T.SIDE}`);
|
|
456
|
+
llmBaseUrl = (await ask(` ${T.SIDE} API Base URL${defUrl ? ` [${defUrl}]` : ""}: `)).trim() || defUrl;
|
|
457
|
+
llmModel = (await ask(` ${T.SIDE} Model${defModel ? ` [${defModel}]` : ""}: `)).trim() || defModel;
|
|
458
|
+
llmKey = (await ask(` ${T.SIDE} API Key${defKey ? ` [${mask(defKey)}]` : " (sk-...)"}: `)).trim() || defKey;
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
if (llmKey) {
|
|
462
|
+
log(` ${T.LAST} ${T.OK} ${llmProviderName} / ${llmModel}`);
|
|
463
|
+
} else {
|
|
464
|
+
log(` ${T.LAST} ${T.WARN} Skipped (configure later in ${ENV_FILE})`);
|
|
465
|
+
}
|
|
466
|
+
log();
|
|
467
|
+
step = 3;
|
|
468
|
+
continue;
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
// ─── Step 3: Embedding Provider ───
|
|
472
|
+
if (step === 3) {
|
|
473
|
+
log(` ${T.DOT} Step 3/3 Embedding Provider`);
|
|
474
|
+
log(` ${T.SIDE}`);
|
|
475
|
+
log(` ${T.BRANCH} For semantic code search`);
|
|
476
|
+
log(` ${T.SIDE} Use ↑↓ navigate, Enter confirm, ← back`);
|
|
477
|
+
log(` ${T.SIDE}`);
|
|
478
|
+
|
|
479
|
+
if (existing.DASHSCOPE_API_KEY || existing.EMBED_API_KEY) {
|
|
480
|
+
const ek = existing.DASHSCOPE_API_KEY || existing.EMBED_API_KEY;
|
|
481
|
+
log(` ${T.SIDE} Current: ${mask(ek)} → ${existing.DASHSCOPE_BASE_URL || existing.EMBED_BASE_URL || "?"}`);
|
|
482
|
+
log(` ${T.SIDE}`);
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
rl.close();
|
|
486
|
+
const embedChoice = await selectMenu(embedOptions, ` ${T.SIDE} `, 3, true);
|
|
487
|
+
rl = createInterface({ input: process.stdin, output: process.stderr });
|
|
488
|
+
ask = (q) => new Promise((resolve) => rl.question(q, resolve));
|
|
489
|
+
|
|
490
|
+
if (embedChoice === -2) { log(); step = 2; continue; }
|
|
491
|
+
if (embedChoice === -1) { rl.close(); return; }
|
|
492
|
+
|
|
493
|
+
embedKey = "";
|
|
494
|
+
embedUrl = "";
|
|
495
|
+
embedModel = "";
|
|
496
|
+
embedKeyEnv = "DASHSCOPE_API_KEY";
|
|
497
|
+
embedUrlEnv = "DASHSCOPE_BASE_URL";
|
|
498
|
+
embedProviderName = "skipped";
|
|
499
|
+
|
|
500
|
+
if (embedChoice >= 0 && embedChoice < 2) {
|
|
501
|
+
const ep = embedProvidersList[embedChoice];
|
|
502
|
+
embedUrl = ep.url;
|
|
503
|
+
embedModel = ep.model;
|
|
504
|
+
embedKeyEnv = ep.keyEnv;
|
|
505
|
+
embedUrlEnv = ep.urlEnv;
|
|
506
|
+
embedProviderName = ep.name;
|
|
507
|
+
|
|
508
|
+
log(` ${T.SIDE}`);
|
|
509
|
+
embedKey = (await ask(` ${T.SIDE} API Key: `)).trim() ||
|
|
510
|
+
existing[embedKeyEnv] || existing.DASHSCOPE_API_KEY || "";
|
|
511
|
+
|
|
512
|
+
if (embedKey) {
|
|
513
|
+
const urlOverride = (await ask(` ${T.SIDE} Base URL [${embedUrl}]: `)).trim();
|
|
514
|
+
if (urlOverride) embedUrl = urlOverride;
|
|
515
|
+
const modelOverride = (await ask(` ${T.SIDE} Model [${embedModel}]: `)).trim();
|
|
516
|
+
if (modelOverride) embedModel = modelOverride;
|
|
517
|
+
}
|
|
518
|
+
} else if (embedChoice === 2) {
|
|
519
|
+
embedProviderName = "Custom";
|
|
520
|
+
const defEmbedUrl = existing.EMBED_BASE_URL || existing.DASHSCOPE_BASE_URL || "";
|
|
521
|
+
const defEmbedModel = existing.EMBED_MODEL || "text-embedding-3-small";
|
|
522
|
+
const defEmbedKey = existing.EMBED_API_KEY || existing.DASHSCOPE_API_KEY || "";
|
|
523
|
+
log(` ${T.SIDE}`);
|
|
524
|
+
embedUrl = (await ask(` ${T.SIDE} API Base URL${defEmbedUrl ? ` [${defEmbedUrl}]` : ""}: `)).trim() || defEmbedUrl;
|
|
525
|
+
embedModel = (await ask(` ${T.SIDE} Model${defEmbedModel ? ` [${defEmbedModel}]` : ""}: `)).trim() || defEmbedModel;
|
|
526
|
+
embedKey = (await ask(` ${T.SIDE} API Key${defEmbedKey ? ` [${mask(defEmbedKey)}]` : ""}: `)).trim() || defEmbedKey;
|
|
527
|
+
embedKeyEnv = "EMBED_API_KEY";
|
|
528
|
+
embedUrlEnv = "EMBED_BASE_URL";
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
if (embedKey) {
|
|
532
|
+
log(` ${T.LAST} ${T.OK} ${embedProviderName} / ${embedModel}`);
|
|
533
|
+
} else {
|
|
534
|
+
log(` ${T.LAST} ${T.WARN} Skipped (configure later in ${ENV_FILE})`);
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
step = 4; // done
|
|
538
|
+
continue;
|
|
539
|
+
}
|
|
494
540
|
}
|
|
495
541
|
|
|
496
542
|
rl.close();
|
|
@@ -540,7 +586,7 @@ async function runSetup() {
|
|
|
540
586
|
if (pip) {
|
|
541
587
|
try {
|
|
542
588
|
execSync(
|
|
543
|
-
[...pip, "install", "--upgrade",
|
|
589
|
+
[...pip, "install", "--upgrade", PYTHON_PACKAGE].map(s => `"${s}"`).join(" "),
|
|
544
590
|
{ stdio: "pipe", shell: true }
|
|
545
591
|
);
|
|
546
592
|
} catch { /* handled below */ }
|
|
@@ -551,7 +597,7 @@ async function runSetup() {
|
|
|
551
597
|
if (pip) {
|
|
552
598
|
try {
|
|
553
599
|
execSync(
|
|
554
|
-
[...pip, "install", "--upgrade",
|
|
600
|
+
[...pip, "install", "--upgrade", PYTHON_PACKAGE].map(s => `"${s}"`).join(" "),
|
|
555
601
|
{ stdio: "pipe", shell: true }
|
|
556
602
|
);
|
|
557
603
|
} catch { /* upgrade is best-effort */ }
|
|
@@ -563,7 +609,7 @@ async function runSetup() {
|
|
|
563
609
|
log(` ${T.BRANCH} ${T.OK} ${PYTHON_PACKAGE} ${ver || ""}`);
|
|
564
610
|
} else {
|
|
565
611
|
log(` ${T.BRANCH} ${T.FAIL} Package not installed`);
|
|
566
|
-
log(` ${T.LAST} Run manually: pip install
|
|
612
|
+
log(` ${T.LAST} Run manually: pip install ${PYTHON_PACKAGE}`);
|
|
567
613
|
log();
|
|
568
614
|
return;
|
|
569
615
|
}
|
|
@@ -738,13 +784,13 @@ function autoInstallAndStart(extraArgs) {
|
|
|
738
784
|
|
|
739
785
|
try {
|
|
740
786
|
execSync(
|
|
741
|
-
[...pip, "install",
|
|
787
|
+
[...pip, "install", PYTHON_PACKAGE].map(s => `"${s}"`).join(" "),
|
|
742
788
|
{ stdio: "inherit", shell: true }
|
|
743
789
|
);
|
|
744
790
|
} catch (err) {
|
|
745
791
|
process.stderr.write(
|
|
746
792
|
`\nFailed to install ${PYTHON_PACKAGE}.\n` +
|
|
747
|
-
`Try manually: ${pip.join(" ")} install
|
|
793
|
+
`Try manually: ${pip.join(" ")} install ${PYTHON_PACKAGE}\n`
|
|
748
794
|
);
|
|
749
795
|
process.exit(1);
|
|
750
796
|
}
|
|
@@ -752,7 +798,7 @@ function autoInstallAndStart(extraArgs) {
|
|
|
752
798
|
if (!pythonPackageInstalled()) {
|
|
753
799
|
process.stderr.write(
|
|
754
800
|
`\nInstallation completed but package not importable.\n` +
|
|
755
|
-
`Try manually: ${pip.join(" ")} install
|
|
801
|
+
`Try manually: ${pip.join(" ")} install ${PYTHON_PACKAGE}\n`
|
|
756
802
|
);
|
|
757
803
|
process.exit(1);
|
|
758
804
|
}
|
|
@@ -879,7 +925,7 @@ if (mode === "--setup") {
|
|
|
879
925
|
if (!PYTHON_CMD || !pythonPackageInstalled()) {
|
|
880
926
|
process.stderr.write(
|
|
881
927
|
`Error: Python package '${PYTHON_PACKAGE}' is not installed.\n` +
|
|
882
|
-
`Run: pip install
|
|
928
|
+
`Run: pip install ${PYTHON_PACKAGE}\n`
|
|
883
929
|
);
|
|
884
930
|
process.exit(1);
|
|
885
931
|
}
|