context-vault 3.11.0 → 3.12.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.js CHANGED
@@ -85,6 +85,48 @@ function isNpx() {
85
85
  return ROOT.includes('/_npx/') || ROOT.includes('\\_npx\\');
86
86
  }
87
87
 
88
+ /** Check if a global install of context-vault exists on PATH (not npx cache) */
89
+ function hasGlobalInstall() {
90
+ try {
91
+ const cmd = platform() === 'win32' ? 'where context-vault' : 'which context-vault';
92
+ const which = execSync(cmd, { encoding: 'utf-8', stdio: 'pipe', timeout: 3000 }).trim();
93
+ return !!which && !which.includes('/_npx/') && !which.includes('\\_npx\\');
94
+ } catch { return false; }
95
+ }
96
+
97
+ /**
98
+ * Determine the best server config for tool MCP configs.
99
+ * Priority: global binary > npx fallback > local dev path.
100
+ * Even when running via npx, prefer the global binary if it exists
101
+ * (e.g., we just installed it during setup).
102
+ */
103
+ function getServerConfig(vaultDir) {
104
+ const serverArgs = ['serve'];
105
+ if (vaultDir) serverArgs.push('--vault-dir', vaultDir);
106
+
107
+ if (hasGlobalInstall()) {
108
+ return { command: 'context-vault', args: serverArgs };
109
+ }
110
+ if (isNpx()) {
111
+ return {
112
+ command: 'npx',
113
+ args: ['-y', 'context-vault', 'serve', ...(vaultDir ? ['--vault-dir', vaultDir] : [])],
114
+ env: { NODE_OPTIONS: '--no-warnings=ExperimentalWarning' },
115
+ };
116
+ }
117
+ if (isInstalledPackage()) {
118
+ return { command: 'context-vault', args: serverArgs };
119
+ }
120
+ // Local dev clone
121
+ const nodeArgs = [SERVER_PATH];
122
+ if (vaultDir) nodeArgs.push('--vault-dir', vaultDir);
123
+ return {
124
+ command: process.execPath,
125
+ args: nodeArgs,
126
+ env: { NODE_OPTIONS: '--no-warnings=ExperimentalWarning' },
127
+ };
128
+ }
129
+
88
130
  /** Detect user experience level based on dev environment signals */
89
131
  function detectUserExperience() {
90
132
  if (isNonInteractive) return 'developer';
@@ -760,6 +802,58 @@ async function runSetup() {
760
802
  console.log();
761
803
  }
762
804
 
805
+ // Global install: when running via npx, offer to install globally so the
806
+ // MCP server binary is on PATH. This makes tool configs reliable (no npx
807
+ // cache dependency) and startup faster (no npx overhead on every spawn).
808
+ if (isNpx() && !isDryRun) {
809
+ const hasGlobal = (() => {
810
+ try {
811
+ const cmd = platform() === 'win32' ? 'where context-vault' : 'which context-vault';
812
+ const which = execSync(cmd, { encoding: 'utf-8', stdio: 'pipe', timeout: 3000 }).trim();
813
+ // Verify it's not pointing back to the npx cache
814
+ return which && !which.includes('/_npx/') && !which.includes('\\_npx\\');
815
+ } catch { return false; }
816
+ })();
817
+
818
+ if (!hasGlobal) {
819
+ if (!isNonInteractive) {
820
+ console.log(dim(' context-vault needs a permanent install to run as an MCP server.'));
821
+ console.log(dim(' Without it, AI tools must re-download the package on every launch.\n'));
822
+ const installAnswer = await prompt(' Install globally via npm? (Y/n):', 'Y');
823
+ if (installAnswer.toLowerCase() !== 'n') {
824
+ console.log();
825
+ try {
826
+ console.log(dim(' Installing context-vault globally...\n'));
827
+ execSync('npm install -g context-vault@' + VERSION, {
828
+ stdio: 'inherit',
829
+ timeout: 120000,
830
+ });
831
+ console.log(`\n ${green('✓')} Installed context-vault v${VERSION} globally\n`);
832
+ } catch (e) {
833
+ console.log(`\n ${yellow('!')} Global install failed: ${e.message}`);
834
+ console.log(dim(' Falling back to npx-based config. You can install later:'));
835
+ console.log(dim(' npm install -g context-vault\n'));
836
+ }
837
+ } else {
838
+ console.log(dim('\n Skipped. MCP configs will use npx (slower startup).\n'));
839
+ }
840
+ } else {
841
+ // Non-interactive (--yes): auto-install globally
842
+ try {
843
+ console.log(dim(' Installing context-vault globally...\n'));
844
+ execSync('npm install -g context-vault@' + VERSION, {
845
+ stdio: ['pipe', 'pipe', 'pipe'],
846
+ timeout: 120000,
847
+ });
848
+ console.log(` ${green('✓')} Installed context-vault v${VERSION} globally\n`);
849
+ } catch (e) {
850
+ console.log(` ${yellow('!')} Global install failed: ${e.message}`);
851
+ console.log(dim(' Continuing with npx-based config.\n'));
852
+ }
853
+ }
854
+ }
855
+ }
856
+
763
857
  // Detect tools
764
858
  console.log(dim(` [1/7]`) + bold(' Detecting tools...\n'));
765
859
  verbose(userLevel, 'Scanning for AI tools on this machine.');
@@ -1480,53 +1574,13 @@ async function configureClaude(tool, vaultDir) {
1480
1574
  }
1481
1575
 
1482
1576
  try {
1483
- if (isNpx()) {
1484
- const serverArgs = ['-y', 'context-vault', 'serve'];
1485
- if (vaultDir) serverArgs.push('--vault-dir', vaultDir);
1486
- execFileSync(
1487
- 'claude',
1488
- [
1489
- 'mcp',
1490
- 'add',
1491
- '-s',
1492
- 'user',
1493
- 'context-vault',
1494
- '-e',
1495
- 'NODE_OPTIONS=--no-warnings=ExperimentalWarning',
1496
- '--',
1497
- 'npx',
1498
- ...serverArgs,
1499
- ],
1500
- { stdio: 'pipe', env }
1501
- );
1502
- } else if (isInstalledPackage()) {
1503
- const serverArgs = ['serve'];
1504
- if (vaultDir) serverArgs.push('--vault-dir', vaultDir);
1505
- execFileSync(
1506
- 'claude',
1507
- ['mcp', 'add', '-s', 'user', 'context-vault', '--', 'context-vault', ...serverArgs],
1508
- { stdio: 'pipe', env }
1509
- );
1510
- } else {
1511
- const nodeArgs = [SERVER_PATH];
1512
- if (vaultDir) nodeArgs.push('--vault-dir', vaultDir);
1513
- execFileSync(
1514
- 'claude',
1515
- [
1516
- 'mcp',
1517
- 'add',
1518
- '-s',
1519
- 'user',
1520
- 'context-vault',
1521
- '-e',
1522
- 'NODE_OPTIONS=--no-warnings=ExperimentalWarning',
1523
- '--',
1524
- process.execPath,
1525
- ...nodeArgs,
1526
- ],
1527
- { stdio: 'pipe', env }
1528
- );
1577
+ const srvCfg = getServerConfig(vaultDir);
1578
+ const claudeArgs = ['mcp', 'add', '-s', 'user', 'context-vault'];
1579
+ if (srvCfg.env?.NODE_OPTIONS) {
1580
+ claudeArgs.push('-e', `NODE_OPTIONS=${srvCfg.env.NODE_OPTIONS}`);
1529
1581
  }
1582
+ claudeArgs.push('--', srvCfg.command, ...srvCfg.args);
1583
+ execFileSync('claude', claudeArgs, { stdio: 'pipe', env });
1530
1584
  } catch (e) {
1531
1585
  const stderr = e.stderr?.toString().trim();
1532
1586
  throw new Error(stderr || e.message);
@@ -1542,25 +1596,10 @@ async function configureCodex(tool, vaultDir) {
1542
1596
  }
1543
1597
 
1544
1598
  try {
1545
- if (isNpx()) {
1546
- const serverArgs = ['-y', 'context-vault', 'serve'];
1547
- if (vaultDir) serverArgs.push('--vault-dir', vaultDir);
1548
- execFileSync('codex', ['mcp', 'add', 'context-vault', '--', 'npx', ...serverArgs], {
1549
- stdio: 'pipe',
1550
- });
1551
- } else if (isInstalledPackage()) {
1552
- const serverArgs = ['serve'];
1553
- if (vaultDir) serverArgs.push('--vault-dir', vaultDir);
1554
- execFileSync('codex', ['mcp', 'add', 'context-vault', '--', 'context-vault', ...serverArgs], {
1555
- stdio: 'pipe',
1556
- });
1557
- } else {
1558
- const nodeArgs = [SERVER_PATH];
1559
- if (vaultDir) nodeArgs.push('--vault-dir', vaultDir);
1560
- execFileSync('codex', ['mcp', 'add', 'context-vault', '--', process.execPath, ...nodeArgs], {
1561
- stdio: 'pipe',
1562
- });
1563
- }
1599
+ const srvCfg = getServerConfig(vaultDir);
1600
+ execFileSync('codex', ['mcp', 'add', 'context-vault', '--', srvCfg.command, ...srvCfg.args], {
1601
+ stdio: 'pipe',
1602
+ });
1564
1603
  } catch (e) {
1565
1604
  const stderr = e.stderr?.toString().trim();
1566
1605
  throw new Error(stderr || e.message);
@@ -1664,29 +1703,7 @@ function configureJsonTool(tool, vaultDir) {
1664
1703
  // Clean up old "context-mcp" key
1665
1704
  delete config[tool.configKey]['context-mcp'];
1666
1705
 
1667
- if (isNpx()) {
1668
- const serverArgs = vaultDir ? ['--vault-dir', vaultDir] : [];
1669
- config[tool.configKey]['context-vault'] = {
1670
- command: 'npx',
1671
- args: ['-y', 'context-vault', 'serve', ...serverArgs],
1672
- env: { NODE_OPTIONS: '--no-warnings=ExperimentalWarning' },
1673
- };
1674
- } else if (isInstalledPackage()) {
1675
- const serverArgs = ['serve'];
1676
- if (vaultDir) serverArgs.push('--vault-dir', vaultDir);
1677
- config[tool.configKey]['context-vault'] = {
1678
- command: 'context-vault',
1679
- args: serverArgs,
1680
- };
1681
- } else {
1682
- const serverArgs = [SERVER_PATH];
1683
- if (vaultDir) serverArgs.push('--vault-dir', vaultDir);
1684
- config[tool.configKey]['context-vault'] = {
1685
- command: process.execPath,
1686
- args: serverArgs,
1687
- env: { NODE_OPTIONS: '--no-warnings=ExperimentalWarning' },
1688
- };
1689
- }
1706
+ config[tool.configKey]['context-vault'] = getServerConfig(vaultDir);
1690
1707
 
1691
1708
  writeFileSync(configPath, JSON.stringify(config, null, 2) + '\n');
1692
1709
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@context-vault/core",
3
- "version": "3.11.0",
3
+ "version": "3.12.0",
4
4
  "type": "module",
5
5
  "description": "Pure local engine: capture, index, search, and utilities for context-vault",
6
6
  "main": "dist/main.js",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "context-vault",
3
- "version": "3.11.0",
3
+ "version": "3.12.0",
4
4
  "type": "module",
5
5
  "description": "Persistent memory for AI agents — saves and searches knowledge across sessions",
6
6
  "bin": {
@@ -67,7 +67,7 @@
67
67
  "@context-vault/core"
68
68
  ],
69
69
  "dependencies": {
70
- "@context-vault/core": "^3.11.0",
70
+ "@context-vault/core": "^3.12.0",
71
71
  "@modelcontextprotocol/sdk": "^1.26.0",
72
72
  "adm-zip": "^0.5.16",
73
73
  "sqlite-vec": "^0.1.0"