context-vault 3.11.0 → 3.13.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,51 @@ 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 (not npx cache) */
89
+ function hasGlobalInstall() {
90
+ try {
91
+ // Can't use `which` here because npx prepends its cache to PATH,
92
+ // so `which context-vault` returns the npx cache path, not the global one.
93
+ // Instead, check the npm global prefix bin directory directly.
94
+ const prefix = execSync('npm prefix -g', { encoding: 'utf-8', stdio: 'pipe', timeout: 5000 }).trim();
95
+ const bin = platform() === 'win32' ? 'context-vault.cmd' : 'context-vault';
96
+ return existsSync(join(prefix, 'bin', bin));
97
+ } catch { return false; }
98
+ }
99
+
100
+ /**
101
+ * Determine the best server config for tool MCP configs.
102
+ * Priority: global binary > npx fallback > local dev path.
103
+ * Even when running via npx, prefer the global binary if it exists
104
+ * (e.g., we just installed it during setup).
105
+ */
106
+ function getServerConfig(vaultDir) {
107
+ const serverArgs = ['serve'];
108
+ if (vaultDir) serverArgs.push('--vault-dir', vaultDir);
109
+
110
+ if (hasGlobalInstall()) {
111
+ return { command: 'context-vault', args: serverArgs };
112
+ }
113
+ if (isNpx()) {
114
+ return {
115
+ command: 'npx',
116
+ args: ['-y', 'context-vault', 'serve', ...(vaultDir ? ['--vault-dir', vaultDir] : [])],
117
+ env: { NODE_OPTIONS: '--no-warnings=ExperimentalWarning' },
118
+ };
119
+ }
120
+ if (isInstalledPackage()) {
121
+ return { command: 'context-vault', args: serverArgs };
122
+ }
123
+ // Local dev clone
124
+ const nodeArgs = [SERVER_PATH];
125
+ if (vaultDir) nodeArgs.push('--vault-dir', vaultDir);
126
+ return {
127
+ command: process.execPath,
128
+ args: nodeArgs,
129
+ env: { NODE_OPTIONS: '--no-warnings=ExperimentalWarning' },
130
+ };
131
+ }
132
+
88
133
  /** Detect user experience level based on dev environment signals */
89
134
  function detectUserExperience() {
90
135
  if (isNonInteractive) return 'developer';
@@ -760,6 +805,51 @@ async function runSetup() {
760
805
  console.log();
761
806
  }
762
807
 
808
+ // Global install: when running via npx, offer to install globally so the
809
+ // MCP server binary is on PATH. This makes tool configs reliable (no npx
810
+ // cache dependency) and startup faster (no npx overhead on every spawn).
811
+ if (isNpx() && !isDryRun) {
812
+ const hasGlobal = hasGlobalInstall();
813
+
814
+ if (!hasGlobal) {
815
+ if (!isNonInteractive) {
816
+ console.log(dim(' context-vault needs a permanent install to run as an MCP server.'));
817
+ console.log(dim(' Without it, AI tools must re-download the package on every launch.\n'));
818
+ const installAnswer = await prompt(' Install globally via npm? (Y/n):', 'Y');
819
+ if (installAnswer.toLowerCase() !== 'n') {
820
+ console.log();
821
+ try {
822
+ console.log(dim(' Installing context-vault globally...\n'));
823
+ execSync('npm install -g context-vault@' + VERSION, {
824
+ stdio: 'inherit',
825
+ timeout: 120000,
826
+ });
827
+ console.log(`\n ${green('✓')} Installed context-vault v${VERSION} globally\n`);
828
+ } catch (e) {
829
+ console.log(`\n ${yellow('!')} Global install failed: ${e.message}`);
830
+ console.log(dim(' Falling back to npx-based config. You can install later:'));
831
+ console.log(dim(' npm install -g context-vault\n'));
832
+ }
833
+ } else {
834
+ console.log(dim('\n Skipped. MCP configs will use npx (slower startup).\n'));
835
+ }
836
+ } else {
837
+ // Non-interactive (--yes): auto-install globally
838
+ try {
839
+ console.log(dim(' Installing context-vault globally...\n'));
840
+ execSync('npm install -g context-vault@' + VERSION, {
841
+ stdio: ['pipe', 'pipe', 'pipe'],
842
+ timeout: 120000,
843
+ });
844
+ console.log(` ${green('✓')} Installed context-vault v${VERSION} globally\n`);
845
+ } catch (e) {
846
+ console.log(` ${yellow('!')} Global install failed: ${e.message}`);
847
+ console.log(dim(' Continuing with npx-based config.\n'));
848
+ }
849
+ }
850
+ }
851
+ }
852
+
763
853
  // Detect tools
764
854
  console.log(dim(` [1/7]`) + bold(' Detecting tools...\n'));
765
855
  verbose(userLevel, 'Scanning for AI tools on this machine.');
@@ -1480,53 +1570,13 @@ async function configureClaude(tool, vaultDir) {
1480
1570
  }
1481
1571
 
1482
1572
  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
- );
1573
+ const srvCfg = getServerConfig(vaultDir);
1574
+ const claudeArgs = ['mcp', 'add', '-s', 'user', 'context-vault'];
1575
+ if (srvCfg.env?.NODE_OPTIONS) {
1576
+ claudeArgs.push('-e', `NODE_OPTIONS=${srvCfg.env.NODE_OPTIONS}`);
1529
1577
  }
1578
+ claudeArgs.push('--', srvCfg.command, ...srvCfg.args);
1579
+ execFileSync('claude', claudeArgs, { stdio: 'pipe', env });
1530
1580
  } catch (e) {
1531
1581
  const stderr = e.stderr?.toString().trim();
1532
1582
  throw new Error(stderr || e.message);
@@ -1542,25 +1592,10 @@ async function configureCodex(tool, vaultDir) {
1542
1592
  }
1543
1593
 
1544
1594
  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
- }
1595
+ const srvCfg = getServerConfig(vaultDir);
1596
+ execFileSync('codex', ['mcp', 'add', 'context-vault', '--', srvCfg.command, ...srvCfg.args], {
1597
+ stdio: 'pipe',
1598
+ });
1564
1599
  } catch (e) {
1565
1600
  const stderr = e.stderr?.toString().trim();
1566
1601
  throw new Error(stderr || e.message);
@@ -1664,29 +1699,7 @@ function configureJsonTool(tool, vaultDir) {
1664
1699
  // Clean up old "context-mcp" key
1665
1700
  delete config[tool.configKey]['context-mcp'];
1666
1701
 
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
- }
1702
+ config[tool.configKey]['context-vault'] = getServerConfig(vaultDir);
1690
1703
 
1691
1704
  writeFileSync(configPath, JSON.stringify(config, null, 2) + '\n');
1692
1705
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@context-vault/core",
3
- "version": "3.11.0",
3
+ "version": "3.13.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.13.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.13.0",
71
71
  "@modelcontextprotocol/sdk": "^1.26.0",
72
72
  "adm-zip": "^0.5.16",
73
73
  "sqlite-vec": "^0.1.0"