context-vault 2.4.1 → 2.4.2
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 +438 -0
- package/bin/cli.js +365 -69
- package/node_modules/@context-vault/core/package.json +13 -11
- package/node_modules/@context-vault/core/src/core/config.js +8 -8
- package/node_modules/@context-vault/core/src/index/db.js +5 -9
- package/node_modules/@context-vault/core/src/index/embed.js +14 -10
- package/node_modules/@context-vault/core/src/server/tools.js +50 -19
- package/package.json +34 -7
- package/scripts/local-server.js +386 -0
- package/scripts/postinstall.js +35 -2
- package/scripts/prepack.js +19 -6
- package/src/server/index.js +53 -18
package/bin/cli.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
* context-
|
|
4
|
+
* context-vault CLI — Unified entry point
|
|
5
5
|
*
|
|
6
6
|
* Usage:
|
|
7
|
-
* context-
|
|
8
|
-
* context-
|
|
9
|
-
* context-
|
|
10
|
-
* context-
|
|
7
|
+
* context-vault setup Interactive MCP installer
|
|
8
|
+
* context-vault ui [--port 3141] Launch web dashboard
|
|
9
|
+
* context-vault reindex Rebuild search index
|
|
10
|
+
* context-vault status Show vault diagnostics
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
13
|
import { createInterface } from "node:readline";
|
|
@@ -23,6 +23,7 @@ import { join, resolve, dirname } from "node:path";
|
|
|
23
23
|
import { homedir, platform } from "node:os";
|
|
24
24
|
import { execSync, fork } from "node:child_process";
|
|
25
25
|
import { fileURLToPath } from "node:url";
|
|
26
|
+
import { createServer as createNetServer } from "node:net";
|
|
26
27
|
|
|
27
28
|
const __filename = fileURLToPath(import.meta.url);
|
|
28
29
|
const __dirname = dirname(__filename);
|
|
@@ -105,19 +106,27 @@ function vscodeDataDir() {
|
|
|
105
106
|
|
|
106
107
|
// ─── Tool Detection ──────────────────────────────────────────────────────────
|
|
107
108
|
|
|
109
|
+
function commandExists(bin) {
|
|
110
|
+
try {
|
|
111
|
+
const cmd = PLATFORM === "win32" ? `where ${bin}` : `which ${bin}`;
|
|
112
|
+
execSync(cmd, { stdio: "pipe" });
|
|
113
|
+
return true;
|
|
114
|
+
} catch {
|
|
115
|
+
return false;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
108
119
|
const TOOLS = [
|
|
109
120
|
{
|
|
110
121
|
id: "claude-code",
|
|
111
122
|
name: "Claude Code",
|
|
112
|
-
detect: () =>
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
}
|
|
120
|
-
},
|
|
123
|
+
detect: () => commandExists("claude"),
|
|
124
|
+
configType: "cli",
|
|
125
|
+
},
|
|
126
|
+
{
|
|
127
|
+
id: "codex",
|
|
128
|
+
name: "Codex",
|
|
129
|
+
detect: () => commandExists("codex"),
|
|
121
130
|
configType: "cli",
|
|
122
131
|
},
|
|
123
132
|
{
|
|
@@ -144,6 +153,14 @@ const TOOLS = [
|
|
|
144
153
|
configPath: join(HOME, ".codeium", "windsurf", "mcp_config.json"),
|
|
145
154
|
configKey: "mcpServers",
|
|
146
155
|
},
|
|
156
|
+
{
|
|
157
|
+
id: "antigravity",
|
|
158
|
+
name: "Antigravity",
|
|
159
|
+
detect: () => existsSync(join(HOME, ".gemini", "antigravity")),
|
|
160
|
+
configType: "json",
|
|
161
|
+
configPath: join(HOME, ".gemini", "antigravity", "mcp_config.json"),
|
|
162
|
+
configKey: "mcpServers",
|
|
163
|
+
},
|
|
147
164
|
{
|
|
148
165
|
id: "cline",
|
|
149
166
|
name: "Cline (VS Code)",
|
|
@@ -168,10 +185,11 @@ function showHelp() {
|
|
|
168
185
|
${dim("Persistent memory for AI agents")}
|
|
169
186
|
|
|
170
187
|
${bold("Usage:")}
|
|
171
|
-
context-
|
|
188
|
+
context-vault <command> [options]
|
|
172
189
|
|
|
173
190
|
${bold("Commands:")}
|
|
174
191
|
${cyan("setup")} Interactive MCP server installer
|
|
192
|
+
${cyan("connect")} --key cv_... Connect AI tools to hosted vault
|
|
175
193
|
${cyan("serve")} Start the MCP server (used by AI clients)
|
|
176
194
|
${cyan("ui")} [--port 3141] Launch web dashboard
|
|
177
195
|
${cyan("reindex")} Rebuild search index from knowledge files
|
|
@@ -242,7 +260,7 @@ async function runSetup() {
|
|
|
242
260
|
}
|
|
243
261
|
|
|
244
262
|
let selected;
|
|
245
|
-
console.log(bold(" Which tools should context-
|
|
263
|
+
console.log(bold(" Which tools should context-vault connect to?\n"));
|
|
246
264
|
for (let i = 0; i < detected.length; i++) {
|
|
247
265
|
console.log(` ${i + 1}) ${detected[i].name}`);
|
|
248
266
|
}
|
|
@@ -272,7 +290,9 @@ async function runSetup() {
|
|
|
272
290
|
console.log(`\n ${dim("[2/2]")}${bold(" Configuring tools...\n")}`);
|
|
273
291
|
for (const tool of selected) {
|
|
274
292
|
try {
|
|
275
|
-
if (tool.configType === "cli") {
|
|
293
|
+
if (tool.configType === "cli" && tool.id === "codex") {
|
|
294
|
+
await configureCodex(tool, customVaultDir);
|
|
295
|
+
} else if (tool.configType === "cli") {
|
|
276
296
|
await configureClaude(tool, customVaultDir);
|
|
277
297
|
} else {
|
|
278
298
|
configureJsonTool(tool, customVaultDir);
|
|
@@ -314,8 +334,8 @@ async function runSetup() {
|
|
|
314
334
|
if (isInstalledPackage()) {
|
|
315
335
|
console.log(` ${dim("{")}
|
|
316
336
|
${dim('"mcpServers": {')}
|
|
317
|
-
${dim('"context-
|
|
318
|
-
${dim('"command": "context-
|
|
337
|
+
${dim('"context-vault": {')}
|
|
338
|
+
${dim('"command": "context-vault",')}
|
|
319
339
|
${dim(`"args": ["serve", "--vault-dir", "/path/to/vault"]`)}
|
|
320
340
|
${dim("}")}
|
|
321
341
|
${dim("}")}
|
|
@@ -323,7 +343,7 @@ async function runSetup() {
|
|
|
323
343
|
} else {
|
|
324
344
|
console.log(` ${dim("{")}
|
|
325
345
|
${dim('"mcpServers": {')}
|
|
326
|
-
${dim('"context-
|
|
346
|
+
${dim('"context-vault": {')}
|
|
327
347
|
${dim('"command": "node",')}
|
|
328
348
|
${dim(`"args": ["${SERVER_PATH}", "--vault-dir", "/path/to/vault"]`)}
|
|
329
349
|
${dim("}")}
|
|
@@ -338,7 +358,7 @@ async function runSetup() {
|
|
|
338
358
|
if (isNonInteractive) {
|
|
339
359
|
selected = detected;
|
|
340
360
|
} else {
|
|
341
|
-
console.log(bold(" Which tools should context-
|
|
361
|
+
console.log(bold(" Which tools should context-vault connect to?\n"));
|
|
342
362
|
for (let i = 0; i < detected.length; i++) {
|
|
343
363
|
console.log(` ${i + 1}) ${detected[i].name}`);
|
|
344
364
|
}
|
|
@@ -405,15 +425,30 @@ async function runSetup() {
|
|
|
405
425
|
writeFileSync(configPath, JSON.stringify(vaultConfig, null, 2) + "\n");
|
|
406
426
|
console.log(`\n ${green("+")} Wrote ${configPath}`);
|
|
407
427
|
|
|
408
|
-
// Pre-download embedding model
|
|
428
|
+
// Pre-download embedding model with spinner
|
|
409
429
|
console.log(`\n ${dim("[3/5]")}${bold(" Downloading embedding model...")}`);
|
|
410
430
|
console.log(dim(" all-MiniLM-L6-v2 (~22MB, one-time download)\n"));
|
|
411
|
-
|
|
412
|
-
const
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
431
|
+
{
|
|
432
|
+
const spinnerFrames = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
|
|
433
|
+
let frame = 0;
|
|
434
|
+
const start = Date.now();
|
|
435
|
+
const spinner = setInterval(() => {
|
|
436
|
+
const elapsed = ((Date.now() - start) / 1000).toFixed(0);
|
|
437
|
+
process.stdout.write(`\r ${spinnerFrames[frame++ % spinnerFrames.length]} Downloading... ${dim(`${elapsed}s`)}`);
|
|
438
|
+
}, 100);
|
|
439
|
+
|
|
440
|
+
try {
|
|
441
|
+
const { embed } = await import("@context-vault/core/index/embed");
|
|
442
|
+
await embed("warmup");
|
|
443
|
+
|
|
444
|
+
clearInterval(spinner);
|
|
445
|
+
process.stdout.write(`\r ${green("+")} Embedding model ready \n`);
|
|
446
|
+
} catch (e) {
|
|
447
|
+
clearInterval(spinner);
|
|
448
|
+
process.stdout.write(`\r ${yellow("!")} Model download failed: ${e.message} \n`);
|
|
449
|
+
console.log(dim(` Retry: context-vault setup`));
|
|
450
|
+
console.log(dim(` Semantic search disabled — full-text search still works.`));
|
|
451
|
+
}
|
|
417
452
|
}
|
|
418
453
|
|
|
419
454
|
// Clean up legacy project-root config.json if it exists
|
|
@@ -433,7 +468,9 @@ async function runSetup() {
|
|
|
433
468
|
|
|
434
469
|
for (const tool of selected) {
|
|
435
470
|
try {
|
|
436
|
-
if (tool.configType === "cli") {
|
|
471
|
+
if (tool.configType === "cli" && tool.id === "codex") {
|
|
472
|
+
await configureCodex(tool, customVaultDir);
|
|
473
|
+
} else if (tool.configType === "cli") {
|
|
437
474
|
await configureClaude(tool, customVaultDir);
|
|
438
475
|
} else {
|
|
439
476
|
configureJsonTool(tool, customVaultDir);
|
|
@@ -490,9 +527,9 @@ async function runSetup() {
|
|
|
490
527
|
` "Show my vault status"`,
|
|
491
528
|
``,
|
|
492
529
|
` ${bold("CLI Commands:")}`,
|
|
493
|
-
` context-
|
|
494
|
-
` context-
|
|
495
|
-
` context-
|
|
530
|
+
` context-vault status Show vault health`,
|
|
531
|
+
` context-vault ui Launch web dashboard`,
|
|
532
|
+
` context-vault update Check for updates`,
|
|
496
533
|
];
|
|
497
534
|
const innerWidth = Math.max(...boxLines.map((l) => l.length)) + 2;
|
|
498
535
|
const pad = (s) => s + " ".repeat(Math.max(0, innerWidth - s.length));
|
|
@@ -509,6 +546,7 @@ async function configureClaude(tool, vaultDir) {
|
|
|
509
546
|
const env = { ...process.env };
|
|
510
547
|
delete env.CLAUDECODE;
|
|
511
548
|
|
|
549
|
+
// Clean up old name
|
|
512
550
|
try {
|
|
513
551
|
execSync("claude mcp remove context-mcp -s user", { stdio: "pipe", env });
|
|
514
552
|
} catch {}
|
|
@@ -517,20 +555,57 @@ async function configureClaude(tool, vaultDir) {
|
|
|
517
555
|
execSync("claude mcp remove context-vault -s user", { stdio: "pipe", env });
|
|
518
556
|
} catch {}
|
|
519
557
|
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
558
|
+
try {
|
|
559
|
+
if (isInstalledPackage()) {
|
|
560
|
+
const cmdArgs = ["serve"];
|
|
561
|
+
if (vaultDir) cmdArgs.push("--vault-dir", `"${vaultDir}"`);
|
|
562
|
+
execSync(
|
|
563
|
+
`claude mcp add -s user context-vault -- context-vault ${cmdArgs.join(" ")}`,
|
|
564
|
+
{ stdio: "pipe", env }
|
|
565
|
+
);
|
|
566
|
+
} else {
|
|
567
|
+
const cmdArgs = [`"${SERVER_PATH}"`];
|
|
568
|
+
if (vaultDir) cmdArgs.push("--vault-dir", `"${vaultDir}"`);
|
|
569
|
+
execSync(
|
|
570
|
+
`claude mcp add -s user context-vault -- node ${cmdArgs.join(" ")}`,
|
|
571
|
+
{ stdio: "pipe", env }
|
|
572
|
+
);
|
|
573
|
+
}
|
|
574
|
+
} catch (e) {
|
|
575
|
+
const stderr = e.stderr?.toString().trim();
|
|
576
|
+
throw new Error(stderr || e.message);
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
async function configureCodex(tool, vaultDir) {
|
|
581
|
+
// Clean up old name
|
|
582
|
+
try {
|
|
583
|
+
execSync("codex mcp remove context-mcp", { stdio: "pipe" });
|
|
584
|
+
} catch {}
|
|
585
|
+
|
|
586
|
+
try {
|
|
587
|
+
execSync("codex mcp remove context-vault", { stdio: "pipe" });
|
|
588
|
+
} catch {}
|
|
589
|
+
|
|
590
|
+
try {
|
|
591
|
+
if (isInstalledPackage()) {
|
|
592
|
+
const cmdArgs = ["serve"];
|
|
593
|
+
if (vaultDir) cmdArgs.push("--vault-dir", `"${vaultDir}"`);
|
|
594
|
+
execSync(
|
|
595
|
+
`codex mcp add context-vault -- context-vault ${cmdArgs.join(" ")}`,
|
|
596
|
+
{ stdio: "pipe" }
|
|
597
|
+
);
|
|
598
|
+
} else {
|
|
599
|
+
const cmdArgs = [`"${SERVER_PATH}"`];
|
|
600
|
+
if (vaultDir) cmdArgs.push("--vault-dir", `"${vaultDir}"`);
|
|
601
|
+
execSync(
|
|
602
|
+
`codex mcp add context-vault -- node ${cmdArgs.join(" ")}`,
|
|
603
|
+
{ stdio: "pipe" }
|
|
604
|
+
);
|
|
605
|
+
}
|
|
606
|
+
} catch (e) {
|
|
607
|
+
const stderr = e.stderr?.toString().trim();
|
|
608
|
+
throw new Error(stderr || e.message);
|
|
534
609
|
}
|
|
535
610
|
}
|
|
536
611
|
|
|
@@ -559,19 +634,20 @@ function configureJsonTool(tool, vaultDir) {
|
|
|
559
634
|
config[tool.configKey] = {};
|
|
560
635
|
}
|
|
561
636
|
|
|
562
|
-
|
|
637
|
+
// Clean up old "context-mcp" key
|
|
638
|
+
delete config[tool.configKey]["context-mcp"];
|
|
563
639
|
|
|
564
640
|
if (isInstalledPackage()) {
|
|
565
641
|
const serverArgs = ["serve"];
|
|
566
642
|
if (vaultDir) serverArgs.push("--vault-dir", vaultDir);
|
|
567
|
-
config[tool.configKey]["context-
|
|
568
|
-
command: "context-
|
|
643
|
+
config[tool.configKey]["context-vault"] = {
|
|
644
|
+
command: "context-vault",
|
|
569
645
|
args: serverArgs,
|
|
570
646
|
};
|
|
571
647
|
} else {
|
|
572
648
|
const serverArgs = [SERVER_PATH];
|
|
573
649
|
if (vaultDir) serverArgs.push("--vault-dir", vaultDir);
|
|
574
|
-
config[tool.configKey]["context-
|
|
650
|
+
config[tool.configKey]["context-vault"] = {
|
|
575
651
|
command: "node",
|
|
576
652
|
args: serverArgs,
|
|
577
653
|
};
|
|
@@ -595,7 +671,7 @@ function createSeedEntries(vaultDir) {
|
|
|
595
671
|
writeFileSync(insightPath, `---
|
|
596
672
|
id: ${id1}
|
|
597
673
|
tags: ["getting-started", "vault"]
|
|
598
|
-
source: context-
|
|
674
|
+
source: context-vault-setup
|
|
599
675
|
created: ${now}
|
|
600
676
|
---
|
|
601
677
|
Welcome to your context vault! This is a seed entry created during setup.
|
|
@@ -625,7 +701,7 @@ ${insightPath}
|
|
|
625
701
|
writeFileSync(decisionPath, `---
|
|
626
702
|
id: ${id2}
|
|
627
703
|
tags: ["example", "architecture"]
|
|
628
|
-
source: context-
|
|
704
|
+
source: context-vault-setup
|
|
629
705
|
created: ${now}
|
|
630
706
|
---
|
|
631
707
|
Example decision: Use local-first data storage (SQLite + files) over cloud databases.
|
|
@@ -647,18 +723,222 @@ This is an example entry showing the decision format. Feel free to delete it.
|
|
|
647
723
|
return created;
|
|
648
724
|
}
|
|
649
725
|
|
|
726
|
+
// ─── Connect Command ─────────────────────────────────────────────────────────
|
|
727
|
+
|
|
728
|
+
async function runConnect() {
|
|
729
|
+
const apiKey = getFlag("--key");
|
|
730
|
+
const hostedUrl = getFlag("--url") || "https://www.context-vault.com";
|
|
731
|
+
|
|
732
|
+
if (!apiKey) {
|
|
733
|
+
console.log(`\n ${bold("context-vault connect")}\n`);
|
|
734
|
+
console.log(` Connect your AI tools to a hosted Context Vault.\n`);
|
|
735
|
+
console.log(` Usage:`);
|
|
736
|
+
console.log(` context-vault connect --key cv_...\n`);
|
|
737
|
+
console.log(` Options:`);
|
|
738
|
+
console.log(` --key <key> API key (required)`);
|
|
739
|
+
console.log(` --url <url> Hosted server URL (default: https://www.context-vault.com)`);
|
|
740
|
+
console.log();
|
|
741
|
+
return;
|
|
742
|
+
}
|
|
743
|
+
|
|
744
|
+
console.log();
|
|
745
|
+
console.log(` ${bold("◇ context-vault")} ${dim("connect")}`);
|
|
746
|
+
console.log();
|
|
747
|
+
|
|
748
|
+
// Detect tools
|
|
749
|
+
console.log(dim(` [1/2]`) + bold(" Detecting tools...\n"));
|
|
750
|
+
const detected = [];
|
|
751
|
+
for (const tool of TOOLS) {
|
|
752
|
+
const found = tool.detect();
|
|
753
|
+
if (found) {
|
|
754
|
+
detected.push(tool);
|
|
755
|
+
console.log(` ${green("+")} ${tool.name}`);
|
|
756
|
+
} else {
|
|
757
|
+
console.log(` ${dim("-")} ${dim(tool.name)} ${dim("(not found)")}`);
|
|
758
|
+
}
|
|
759
|
+
}
|
|
760
|
+
console.log();
|
|
761
|
+
|
|
762
|
+
if (detected.length === 0) {
|
|
763
|
+
console.log(yellow(" No supported tools detected."));
|
|
764
|
+
console.log(`\n Add this to your tool's MCP config manually:\n`);
|
|
765
|
+
console.log(dim(` ${JSON.stringify({
|
|
766
|
+
mcpServers: {
|
|
767
|
+
"context-vault": {
|
|
768
|
+
url: `${hostedUrl}/mcp`,
|
|
769
|
+
headers: { Authorization: `Bearer ${apiKey}` },
|
|
770
|
+
},
|
|
771
|
+
},
|
|
772
|
+
}, null, 2).split("\n").join("\n ")}`));
|
|
773
|
+
console.log();
|
|
774
|
+
return;
|
|
775
|
+
}
|
|
776
|
+
|
|
777
|
+
// Select tools
|
|
778
|
+
let selected;
|
|
779
|
+
if (isNonInteractive) {
|
|
780
|
+
selected = detected;
|
|
781
|
+
} else {
|
|
782
|
+
console.log(bold(" Which tools should connect to your hosted vault?\n"));
|
|
783
|
+
for (let i = 0; i < detected.length; i++) {
|
|
784
|
+
console.log(` ${i + 1}) ${detected[i].name}`);
|
|
785
|
+
}
|
|
786
|
+
console.log();
|
|
787
|
+
const answer = await prompt(
|
|
788
|
+
` Select (${dim("1,2,3")} or ${dim('"all"')}):`,
|
|
789
|
+
"all"
|
|
790
|
+
);
|
|
791
|
+
if (answer === "all" || answer === "") {
|
|
792
|
+
selected = detected;
|
|
793
|
+
} else {
|
|
794
|
+
const nums = answer.split(/[,\s]+/).map((n) => parseInt(n, 10) - 1).filter((n) => n >= 0 && n < detected.length);
|
|
795
|
+
selected = nums.map((n) => detected[n]);
|
|
796
|
+
if (selected.length === 0) selected = detected;
|
|
797
|
+
}
|
|
798
|
+
}
|
|
799
|
+
|
|
800
|
+
// Configure each tool with hosted MCP endpoint
|
|
801
|
+
console.log(`\n ${dim("[2/2]")}${bold(" Configuring tools...\n")}`);
|
|
802
|
+
for (const tool of selected) {
|
|
803
|
+
try {
|
|
804
|
+
if (tool.configType === "cli" && tool.id === "codex") {
|
|
805
|
+
configureCodexHosted(apiKey, hostedUrl);
|
|
806
|
+
} else if (tool.configType === "cli") {
|
|
807
|
+
configureClaudeHosted(apiKey, hostedUrl);
|
|
808
|
+
} else {
|
|
809
|
+
configureJsonToolHosted(tool, apiKey, hostedUrl);
|
|
810
|
+
}
|
|
811
|
+
console.log(` ${green("+")} ${tool.name} — configured`);
|
|
812
|
+
} catch (e) {
|
|
813
|
+
console.log(` ${red("x")} ${tool.name} — ${e.message}`);
|
|
814
|
+
}
|
|
815
|
+
}
|
|
816
|
+
|
|
817
|
+
console.log();
|
|
818
|
+
console.log(green(" ✓ Connected! Your AI tools can now access your hosted vault."));
|
|
819
|
+
console.log(dim(` Endpoint: ${hostedUrl}/mcp`));
|
|
820
|
+
console.log();
|
|
821
|
+
}
|
|
822
|
+
|
|
823
|
+
function configureClaudeHosted(apiKey, hostedUrl) {
|
|
824
|
+
const env = { ...process.env };
|
|
825
|
+
delete env.CLAUDECODE;
|
|
826
|
+
|
|
827
|
+
try { execSync("claude mcp remove context-mcp -s user", { stdio: "pipe", env }); } catch {}
|
|
828
|
+
try { execSync("claude mcp remove context-vault -s user", { stdio: "pipe", env }); } catch {}
|
|
829
|
+
|
|
830
|
+
try {
|
|
831
|
+
execSync(
|
|
832
|
+
`claude mcp add -s user --transport http context-vault ${hostedUrl}/mcp`,
|
|
833
|
+
{ stdio: "pipe", env }
|
|
834
|
+
);
|
|
835
|
+
} catch (e) {
|
|
836
|
+
const stderr = e.stderr?.toString().trim();
|
|
837
|
+
throw new Error(stderr || e.message);
|
|
838
|
+
}
|
|
839
|
+
}
|
|
840
|
+
|
|
841
|
+
function configureCodexHosted(apiKey, hostedUrl) {
|
|
842
|
+
try { execSync("codex mcp remove context-mcp", { stdio: "pipe" }); } catch {}
|
|
843
|
+
try { execSync("codex mcp remove context-vault", { stdio: "pipe" }); } catch {}
|
|
844
|
+
|
|
845
|
+
try {
|
|
846
|
+
execSync(
|
|
847
|
+
`codex mcp add --transport http context-vault ${hostedUrl}/mcp`,
|
|
848
|
+
{ stdio: "pipe" }
|
|
849
|
+
);
|
|
850
|
+
} catch (e) {
|
|
851
|
+
const stderr = e.stderr?.toString().trim();
|
|
852
|
+
throw new Error(stderr || e.message);
|
|
853
|
+
}
|
|
854
|
+
}
|
|
855
|
+
|
|
856
|
+
function configureJsonToolHosted(tool, apiKey, hostedUrl) {
|
|
857
|
+
const configPath = tool.configPath;
|
|
858
|
+
const configDir = dirname(configPath);
|
|
859
|
+
|
|
860
|
+
if (!existsSync(configDir)) {
|
|
861
|
+
mkdirSync(configDir, { recursive: true });
|
|
862
|
+
}
|
|
863
|
+
|
|
864
|
+
let config = {};
|
|
865
|
+
if (existsSync(configPath)) {
|
|
866
|
+
const raw = readFileSync(configPath, "utf-8");
|
|
867
|
+
try {
|
|
868
|
+
config = JSON.parse(raw);
|
|
869
|
+
} catch {
|
|
870
|
+
const bakPath = configPath + ".bak";
|
|
871
|
+
copyFileSync(configPath, bakPath);
|
|
872
|
+
config = {};
|
|
873
|
+
}
|
|
874
|
+
}
|
|
875
|
+
|
|
876
|
+
if (!config[tool.configKey]) {
|
|
877
|
+
config[tool.configKey] = {};
|
|
878
|
+
}
|
|
879
|
+
|
|
880
|
+
// Clean up old "context-mcp" key
|
|
881
|
+
delete config[tool.configKey]["context-mcp"];
|
|
882
|
+
|
|
883
|
+
config[tool.configKey]["context-vault"] = {
|
|
884
|
+
url: `${hostedUrl}/mcp`,
|
|
885
|
+
headers: {
|
|
886
|
+
Authorization: `Bearer ${apiKey}`,
|
|
887
|
+
},
|
|
888
|
+
};
|
|
889
|
+
|
|
890
|
+
writeFileSync(configPath, JSON.stringify(config, null, 2) + "\n");
|
|
891
|
+
}
|
|
892
|
+
|
|
650
893
|
// ─── UI Command ──────────────────────────────────────────────────────────────
|
|
651
894
|
|
|
652
895
|
function runUi() {
|
|
653
|
-
const
|
|
654
|
-
if (!existsSync(
|
|
655
|
-
console.error(red("
|
|
896
|
+
const appDist = resolve(ROOT, "..", "app", "dist");
|
|
897
|
+
if (!existsSync(appDist) || !existsSync(join(appDist, "index.html"))) {
|
|
898
|
+
console.error(red("Web dashboard not found."));
|
|
899
|
+
console.error(dim(" From repo: npm run build --workspace=packages/app"));
|
|
900
|
+
console.error(dim(" Then run: context-vault ui"));
|
|
901
|
+
process.exit(1);
|
|
902
|
+
}
|
|
903
|
+
|
|
904
|
+
const port = parseInt(getFlag("--port") || "3141", 10);
|
|
905
|
+
const localServer = join(ROOT, "scripts", "local-server.js");
|
|
906
|
+
if (!existsSync(localServer)) {
|
|
907
|
+
console.error(red("Local server not found."));
|
|
656
908
|
process.exit(1);
|
|
657
909
|
}
|
|
658
910
|
|
|
659
|
-
|
|
660
|
-
const
|
|
911
|
+
// Probe the port before forking
|
|
912
|
+
const probe = createNetServer();
|
|
913
|
+
probe.once("error", (e) => {
|
|
914
|
+
if (e.code === "EADDRINUSE") {
|
|
915
|
+
console.error(red(` Port ${port} is already in use.`));
|
|
916
|
+
console.error(` Try: ${cyan(`context-vault ui --port ${port + 1}`)}`);
|
|
917
|
+
process.exit(1);
|
|
918
|
+
}
|
|
919
|
+
// Other error — let the fork handle it
|
|
920
|
+
probe.close();
|
|
921
|
+
launchServer(port, localServer);
|
|
922
|
+
});
|
|
923
|
+
probe.listen(port, () => {
|
|
924
|
+
probe.close(() => {
|
|
925
|
+
launchServer(port, localServer);
|
|
926
|
+
});
|
|
927
|
+
});
|
|
928
|
+
}
|
|
929
|
+
|
|
930
|
+
function launchServer(port, localServer) {
|
|
931
|
+
const child = fork(localServer, [`--port=${port}`], { stdio: "inherit" });
|
|
661
932
|
child.on("exit", (code) => process.exit(code ?? 0));
|
|
933
|
+
|
|
934
|
+
// Open browser after a short delay
|
|
935
|
+
setTimeout(() => {
|
|
936
|
+
try {
|
|
937
|
+
const url = `http://localhost:${port}`;
|
|
938
|
+
const open = PLATFORM === "darwin" ? "open" : PLATFORM === "win32" ? "start" : "xdg-open";
|
|
939
|
+
execSync(`${open} ${url}`, { stdio: "ignore" });
|
|
940
|
+
} catch {}
|
|
941
|
+
}, 1500);
|
|
662
942
|
}
|
|
663
943
|
|
|
664
944
|
// ─── Reindex Command ─────────────────────────────────────────────────────────
|
|
@@ -676,7 +956,7 @@ async function runReindex() {
|
|
|
676
956
|
console.error(
|
|
677
957
|
red(`Vault directory not found: ${config.vaultDir}`)
|
|
678
958
|
);
|
|
679
|
-
console.error("Run " + cyan("context-
|
|
959
|
+
console.error("Run " + cyan("context-vault setup") + " to configure.");
|
|
680
960
|
process.exit(1);
|
|
681
961
|
}
|
|
682
962
|
|
|
@@ -764,7 +1044,7 @@ async function runStatus() {
|
|
|
764
1044
|
if (status.stalePaths) {
|
|
765
1045
|
console.log();
|
|
766
1046
|
console.log(yellow(" Stale paths detected in DB."));
|
|
767
|
-
console.log(` Run ${cyan("context-
|
|
1047
|
+
console.log(` Run ${cyan("context-vault reindex")} to update.`);
|
|
768
1048
|
}
|
|
769
1049
|
console.log();
|
|
770
1050
|
}
|
|
@@ -820,23 +1100,36 @@ async function runUninstall() {
|
|
|
820
1100
|
console.log(` ${bold("◇ context-vault")} ${dim("uninstall")}`);
|
|
821
1101
|
console.log();
|
|
822
1102
|
|
|
823
|
-
// Remove from Claude Code
|
|
1103
|
+
// Remove from Claude Code (both old and new names)
|
|
824
1104
|
try {
|
|
825
1105
|
const env = { ...process.env };
|
|
826
1106
|
delete env.CLAUDECODE;
|
|
827
|
-
execSync("claude mcp remove context-mcp -s user", { stdio: "pipe", env });
|
|
1107
|
+
try { execSync("claude mcp remove context-mcp -s user", { stdio: "pipe", env }); } catch {}
|
|
1108
|
+
execSync("claude mcp remove context-vault -s user", { stdio: "pipe", env });
|
|
828
1109
|
console.log(` ${green("+")} Removed from Claude Code`);
|
|
829
1110
|
} catch {
|
|
830
1111
|
console.log(` ${dim("-")} Claude Code — not configured or not installed`);
|
|
831
1112
|
}
|
|
832
1113
|
|
|
833
|
-
// Remove from
|
|
1114
|
+
// Remove from Codex (both old and new names)
|
|
1115
|
+
try {
|
|
1116
|
+
try { execSync("codex mcp remove context-mcp", { stdio: "pipe" }); } catch {}
|
|
1117
|
+
execSync("codex mcp remove context-vault", { stdio: "pipe" });
|
|
1118
|
+
console.log(` ${green("+")} Removed from Codex`);
|
|
1119
|
+
} catch {
|
|
1120
|
+
console.log(` ${dim("-")} Codex — not configured or not installed`);
|
|
1121
|
+
}
|
|
1122
|
+
|
|
1123
|
+
// Remove from JSON-configured tools (both old and new keys)
|
|
834
1124
|
for (const tool of TOOLS.filter((t) => t.configType === "json")) {
|
|
835
1125
|
if (!existsSync(tool.configPath)) continue;
|
|
836
1126
|
try {
|
|
837
1127
|
const config = JSON.parse(readFileSync(tool.configPath, "utf-8"));
|
|
838
|
-
|
|
1128
|
+
const hadOld = !!config[tool.configKey]?.["context-mcp"];
|
|
1129
|
+
const hadNew = !!config[tool.configKey]?.["context-vault"];
|
|
1130
|
+
if (hadOld || hadNew) {
|
|
839
1131
|
delete config[tool.configKey]["context-mcp"];
|
|
1132
|
+
delete config[tool.configKey]["context-vault"];
|
|
840
1133
|
writeFileSync(tool.configPath, JSON.stringify(config, null, 2) + "\n");
|
|
841
1134
|
console.log(` ${green("+")} Removed from ${tool.name}`);
|
|
842
1135
|
}
|
|
@@ -875,10 +1168,10 @@ async function runMigrate() {
|
|
|
875
1168
|
: null;
|
|
876
1169
|
|
|
877
1170
|
if (!direction) {
|
|
878
|
-
console.log(`\n ${bold("context-
|
|
1171
|
+
console.log(`\n ${bold("context-vault migrate")}\n`);
|
|
879
1172
|
console.log(` Usage:`);
|
|
880
|
-
console.log(` context-
|
|
881
|
-
console.log(` context-
|
|
1173
|
+
console.log(` context-vault migrate --to-hosted Upload local vault to hosted service`);
|
|
1174
|
+
console.log(` context-vault migrate --to-local Download hosted vault to local files`);
|
|
882
1175
|
console.log(`\n Options:`);
|
|
883
1176
|
console.log(` --url <url> Hosted server URL (default: https://vault.contextvault.dev)`);
|
|
884
1177
|
console.log(` --key <key> API key (cv_...)`);
|
|
@@ -936,7 +1229,7 @@ async function runMigrate() {
|
|
|
936
1229
|
if (results.failed > 0) {
|
|
937
1230
|
console.log(` ${red("-")} ${results.failed} failed`);
|
|
938
1231
|
}
|
|
939
|
-
console.log(dim("\n Run `context-
|
|
1232
|
+
console.log(dim("\n Run `context-vault reindex` to rebuild the search index."));
|
|
940
1233
|
}
|
|
941
1234
|
console.log();
|
|
942
1235
|
}
|
|
@@ -964,6 +1257,9 @@ async function main() {
|
|
|
964
1257
|
case "setup":
|
|
965
1258
|
await runSetup();
|
|
966
1259
|
break;
|
|
1260
|
+
case "connect":
|
|
1261
|
+
await runConnect();
|
|
1262
|
+
break;
|
|
967
1263
|
case "serve":
|
|
968
1264
|
await runServe();
|
|
969
1265
|
break;
|
|
@@ -972,7 +1268,7 @@ async function main() {
|
|
|
972
1268
|
break;
|
|
973
1269
|
case "import":
|
|
974
1270
|
case "export":
|
|
975
|
-
console.log(`Import/export removed. Add .md files to vault/ and run \`context-
|
|
1271
|
+
console.log(`Import/export removed. Add .md files to vault/ and run \`context-vault reindex\`.`);
|
|
976
1272
|
break;
|
|
977
1273
|
case "reindex":
|
|
978
1274
|
await runReindex();
|
|
@@ -991,7 +1287,7 @@ async function main() {
|
|
|
991
1287
|
break;
|
|
992
1288
|
default:
|
|
993
1289
|
console.error(red(`Unknown command: ${command}`));
|
|
994
|
-
console.error(`Run ${cyan("context-
|
|
1290
|
+
console.error(`Run ${cyan("context-vault --help")} for usage.`);
|
|
995
1291
|
process.exit(1);
|
|
996
1292
|
}
|
|
997
1293
|
}
|