context-vault 2.15.0 → 2.16.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
@@ -64,6 +64,7 @@ function writeMarkerFile(vaultDir) {
64
64
 
65
65
  function scanForVaults() {
66
66
  const candidates = [
67
+ join(HOME, ".vault"),
67
68
  join(HOME, "vault"),
68
69
  join(HOME, "omni", "vault"),
69
70
  process.cwd(),
@@ -324,6 +325,7 @@ ${bold("Options:")}
324
325
  --version Show version
325
326
  --vault-dir <path> Set vault directory (setup/serve)
326
327
  --yes Non-interactive mode (accept all defaults)
328
+ --force Overwrite existing config without confirmation
327
329
  --skip-embeddings Skip embedding model download (FTS-only mode)
328
330
  `);
329
331
  }
@@ -538,7 +540,21 @@ async function runSetup() {
538
540
  console.log(dim(` [2/6]`) + bold(" Configuring vault...\n"));
539
541
 
540
542
  // Scan for existing vaults via marker file
541
- let defaultVaultDir = getFlag("--vault-dir") || join(HOME, "vault");
543
+ let defaultVaultDir = getFlag("--vault-dir") || join(HOME, ".vault");
544
+
545
+ // Prefer existing config vaultDir over default (prevents accidental overwrite)
546
+ if (!getFlag("--vault-dir")) {
547
+ const existingCfgPath = join(HOME, ".context-mcp", "config.json");
548
+ if (existsSync(existingCfgPath)) {
549
+ try {
550
+ const cfg = JSON.parse(readFileSync(existingCfgPath, "utf-8"));
551
+ if (cfg.vaultDir && existsSync(resolve(cfg.vaultDir))) {
552
+ defaultVaultDir = cfg.vaultDir;
553
+ }
554
+ } catch {}
555
+ }
556
+ }
557
+
542
558
  if (!getFlag("--vault-dir") && !isNonInteractive) {
543
559
  const existingVaults = scanForVaults();
544
560
  if (existingVaults.length === 1) {
@@ -576,7 +592,7 @@ async function runSetup() {
576
592
  const vaultDir = isNonInteractive
577
593
  ? defaultVaultDir
578
594
  : await prompt(` Vault directory:`, defaultVaultDir);
579
- const resolvedVaultDir = resolve(vaultDir);
595
+ let resolvedVaultDir = resolve(vaultDir);
580
596
 
581
597
  // Guard: vault dir path must not be an existing file
582
598
  if (existsSync(resolvedVaultDir)) {
@@ -626,6 +642,57 @@ async function runSetup() {
626
642
  Object.assign(vaultConfig, JSON.parse(readFileSync(configPath, "utf-8")));
627
643
  } catch {}
628
644
  }
645
+
646
+ const existingVaultDir = vaultConfig.vaultDir;
647
+ if (
648
+ existingVaultDir &&
649
+ resolve(existingVaultDir) !== resolvedVaultDir &&
650
+ !flags.has("--force")
651
+ ) {
652
+ let entryCount = 0;
653
+ try {
654
+ const knowledgeDir = join(resolve(existingVaultDir), "knowledge");
655
+ if (existsSync(knowledgeDir)) {
656
+ const countMd = (d) => {
657
+ let n = 0;
658
+ for (const e of readdirSync(d, { withFileTypes: true })) {
659
+ if (e.isDirectory()) n += countMd(join(d, e.name));
660
+ else if (e.name.endsWith(".md")) n++;
661
+ }
662
+ return n;
663
+ };
664
+ entryCount = countMd(knowledgeDir);
665
+ }
666
+ } catch {}
667
+
668
+ console.log();
669
+ console.log(
670
+ yellow(` ⚠ Existing config points to: ${resolve(existingVaultDir)}`) +
671
+ (entryCount > 0 ? dim(` (${entryCount} entries)`) : ""),
672
+ );
673
+ console.log(` Setup would change vaultDir to: ${resolvedVaultDir}`);
674
+
675
+ if (isNonInteractive) {
676
+ console.log();
677
+ console.log(
678
+ red(" Refusing to overwrite vaultDir in non-interactive mode."),
679
+ );
680
+ console.log(
681
+ dim(" Use --force to override, or --vault-dir to set explicitly."),
682
+ );
683
+ process.exit(1);
684
+ }
685
+
686
+ console.log();
687
+ const overwrite = await prompt(" Overwrite? (y/N):", "N");
688
+ if (overwrite.toLowerCase() !== "y" && overwrite.toLowerCase() !== "yes") {
689
+ console.log(
690
+ dim(` Keeping existing vaultDir: ${resolve(existingVaultDir)}`),
691
+ );
692
+ resolvedVaultDir = resolve(existingVaultDir);
693
+ }
694
+ }
695
+
629
696
  vaultConfig.vaultDir = resolvedVaultDir;
630
697
  vaultConfig.dataDir = dataDir;
631
698
  vaultConfig.dbPath = join(dataDir, "vault.db");
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@context-vault/core",
3
- "version": "2.15.0",
3
+ "version": "2.16.0",
4
4
  "type": "module",
5
5
  "description": "Shared core: capture, index, retrieve, tools, and utilities for context-vault",
6
6
  "main": "src/index.js",
@@ -27,7 +27,7 @@ export function resolveConfig() {
27
27
  join(HOME, ".context-mcp"),
28
28
  );
29
29
  const config = {
30
- vaultDir: join(HOME, "vault"),
30
+ vaultDir: join(HOME, ".vault"),
31
31
  dataDir,
32
32
  dbPath: join(dataDir, "vault.db"),
33
33
  devDir: join(HOME, "dev"),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "context-vault",
3
- "version": "2.15.0",
3
+ "version": "2.16.0",
4
4
  "type": "module",
5
5
  "description": "Persistent memory for AI agents — saves and searches knowledge across sessions",
6
6
  "bin": {
@@ -138,6 +138,24 @@ async function main() {
138
138
  { capabilities: { tools: {} } },
139
139
  );
140
140
 
141
+ // Hot-reload config.json on every tool call (Option C from #144).
142
+ // resolveConfig() re-reads the small file each time — negligible I/O
143
+ // compared to DB queries and embedding operations that follow.
144
+ let lastVaultDir = config.vaultDir;
145
+ Object.defineProperty(ctx, "config", {
146
+ get() {
147
+ const fresh = resolveConfig();
148
+ if (fresh.vaultDir !== lastVaultDir) {
149
+ console.error(
150
+ `[context-vault] Config reloaded: vaultDir changed to ${fresh.vaultDir}`,
151
+ );
152
+ lastVaultDir = fresh.vaultDir;
153
+ }
154
+ return fresh;
155
+ },
156
+ configurable: true,
157
+ });
158
+
141
159
  registerTools(server, ctx);
142
160
 
143
161
  // ── Graceful Shutdown ────────────────────────────────────────────────────