context-vault 2.7.0 → 2.8.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
@@ -1,5 +1,15 @@
1
1
  #!/usr/bin/env node
2
2
 
3
+ // Node.js version guard — must run before any ESM imports
4
+ const nodeVersion = parseInt(process.versions.node.split(".")[0], 10);
5
+ if (nodeVersion < 20) {
6
+ process.stderr.write(
7
+ `\ncontext-vault requires Node.js >= 20 (you have ${process.versions.node}).\n` +
8
+ `Install a newer version: https://nodejs.org/\n\n`,
9
+ );
10
+ process.exit(1);
11
+ }
12
+
3
13
  /**
4
14
  * context-vault CLI — Unified entry point
5
15
  *
@@ -21,7 +31,7 @@ import {
21
31
  } from "node:fs";
22
32
  import { join, resolve, dirname } from "node:path";
23
33
  import { homedir, platform } from "node:os";
24
- import { execSync, fork } from "node:child_process";
34
+ import { execSync, execFile, fork } from "node:child_process";
25
35
  import { fileURLToPath } from "node:url";
26
36
  import { createServer as createNetServer } from "node:net";
27
37
 
@@ -106,14 +116,11 @@ function vscodeDataDir() {
106
116
 
107
117
  // ─── Tool Detection ──────────────────────────────────────────────────────────
108
118
 
109
- function commandExists(bin) {
110
- try {
111
- const cmd = PLATFORM === "win32" ? `where ${bin}` : `which ${bin}`;
112
- execSync(cmd, { stdio: "pipe", timeout: 5000 });
113
- return true;
114
- } catch {
115
- return false;
116
- }
119
+ function commandExistsAsync(bin) {
120
+ const cmd = PLATFORM === "win32" ? "where" : "which";
121
+ return new Promise((resolve) => {
122
+ execFile(cmd, [bin], { timeout: 5000 }, (err) => resolve(!err));
123
+ });
117
124
  }
118
125
 
119
126
  /** Check if a directory exists at any of the given paths */
@@ -125,13 +132,13 @@ const TOOLS = [
125
132
  {
126
133
  id: "claude-code",
127
134
  name: "Claude Code",
128
- detect: () => commandExists("claude"),
135
+ detect: () => commandExistsAsync("claude"),
129
136
  configType: "cli",
130
137
  },
131
138
  {
132
139
  id: "codex",
133
140
  name: "Codex",
134
- detect: () => commandExists("codex"),
141
+ detect: () => commandExistsAsync("codex"),
135
142
  configType: "cli",
136
143
  },
137
144
  {
@@ -145,7 +152,8 @@ const TOOLS = [
145
152
  {
146
153
  id: "cursor",
147
154
  name: "Cursor",
148
- detect: () => anyDirExists(join(HOME, ".cursor"), join(appDataDir(), "Cursor")),
155
+ detect: () =>
156
+ anyDirExists(join(HOME, ".cursor"), join(appDataDir(), "Cursor")),
149
157
  configType: "json",
150
158
  configPath: join(HOME, ".cursor", "mcp.json"),
151
159
  configKey: "mcpServers",
@@ -153,10 +161,8 @@ const TOOLS = [
153
161
  {
154
162
  id: "windsurf",
155
163
  name: "Windsurf",
156
- detect: () => anyDirExists(
157
- join(HOME, ".codeium", "windsurf"),
158
- join(HOME, ".windsurf"),
159
- ),
164
+ detect: () =>
165
+ anyDirExists(join(HOME, ".codeium", "windsurf"), join(HOME, ".windsurf")),
160
166
  configType: "json",
161
167
  configPath: join(HOME, ".codeium", "windsurf", "mcp_config.json"),
162
168
  configKey: "mcpServers",
@@ -164,10 +170,8 @@ const TOOLS = [
164
170
  {
165
171
  id: "antigravity",
166
172
  name: "Antigravity (Gemini CLI)",
167
- detect: () => anyDirExists(
168
- join(HOME, ".gemini", "antigravity"),
169
- join(HOME, ".gemini"),
170
- ),
173
+ detect: () =>
174
+ anyDirExists(join(HOME, ".gemini", "antigravity"), join(HOME, ".gemini")),
171
175
  configType: "json",
172
176
  configPath: join(HOME, ".gemini", "antigravity", "mcp_config.json"),
173
177
  configKey: "mcpServers",
@@ -182,7 +186,7 @@ const TOOLS = [
182
186
  vscodeDataDir(),
183
187
  "saoudrizwan.claude-dev",
184
188
  "settings",
185
- "cline_mcp_settings.json"
189
+ "cline_mcp_settings.json",
186
190
  ),
187
191
  configKey: "mcpServers",
188
192
  },
@@ -190,18 +194,43 @@ const TOOLS = [
190
194
  id: "roo-code",
191
195
  name: "Roo Code (VS Code)",
192
196
  detect: () =>
193
- existsSync(join(vscodeDataDir(), "rooveterinaryinc.roo-cline", "settings")),
197
+ existsSync(
198
+ join(vscodeDataDir(), "rooveterinaryinc.roo-cline", "settings"),
199
+ ),
194
200
  configType: "json",
195
201
  configPath: join(
196
202
  vscodeDataDir(),
197
203
  "rooveterinaryinc.roo-cline",
198
204
  "settings",
199
- "cline_mcp_settings.json"
205
+ "cline_mcp_settings.json",
200
206
  ),
201
207
  configKey: "mcpServers",
202
208
  },
203
209
  ];
204
210
 
211
+ /** Detect all tools in parallel. Returns { detected: Tool[], results: { tool, found }[] } */
212
+ async function detectAllTools() {
213
+ const results = await Promise.all(
214
+ TOOLS.map(async (tool) => {
215
+ const found = await tool.detect();
216
+ return { tool, found };
217
+ }),
218
+ );
219
+ const detected = results.filter((r) => r.found).map((r) => r.tool);
220
+ return { detected, results };
221
+ }
222
+
223
+ /** Print tool detection results in deterministic TOOLS order */
224
+ function printDetectionResults(results) {
225
+ for (const { tool, found } of results) {
226
+ if (found) {
227
+ console.log(` ${green("+")} ${tool.name}`);
228
+ } else {
229
+ console.log(` ${dim("-")} ${dim(tool.name)} ${dim("(not found)")}`);
230
+ }
231
+ }
232
+ }
233
+
205
234
  // ─── Help ────────────────────────────────────────────────────────────────────
206
235
 
207
236
  function showHelp() {
@@ -239,6 +268,8 @@ ${bold("Options:")}
239
268
  // ─── Setup Command ───────────────────────────────────────────────────────────
240
269
 
241
270
  async function runSetup() {
271
+ const setupStart = Date.now();
272
+
242
273
  // Banner
243
274
  console.log();
244
275
  console.log(` ${bold("◇ context-vault")} ${dim(`v${VERSION}`)}`);
@@ -273,16 +304,8 @@ async function runSetup() {
273
304
  // Skip vault setup, just reconfigure tools
274
305
  console.log();
275
306
  console.log(dim(` [1/2]`) + bold(" Detecting tools...\n"));
276
- const detected = [];
277
- for (const tool of TOOLS) {
278
- const found = tool.detect();
279
- if (found) {
280
- detected.push(tool);
281
- console.log(` ${green("+")} ${tool.name}`);
282
- } else {
283
- console.log(` ${dim("-")} ${dim(tool.name)} ${dim("(not found)")}`);
284
- }
285
- }
307
+ const { detected, results: detectionResults } = await detectAllTools();
308
+ printDetectionResults(detectionResults);
286
309
  console.log();
287
310
 
288
311
  if (detected.length === 0) {
@@ -298,12 +321,15 @@ async function runSetup() {
298
321
  console.log();
299
322
  const answer = await prompt(
300
323
  ` Select (${dim("1,2,3")} or ${dim('"all"')}):`,
301
- "all"
324
+ "all",
302
325
  );
303
326
  if (answer === "all" || answer === "") {
304
327
  selected = detected;
305
328
  } else {
306
- const nums = answer.split(/[,\s]+/).map((n) => parseInt(n, 10) - 1).filter((n) => n >= 0 && n < detected.length);
329
+ const nums = answer
330
+ .split(/[,\s]+/)
331
+ .map((n) => parseInt(n, 10) - 1)
332
+ .filter((n) => n >= 0 && n < detected.length);
307
333
  selected = nums.map((n) => detected[n]);
308
334
  if (selected.length === 0) selected = detected;
309
335
  }
@@ -345,22 +371,12 @@ async function runSetup() {
345
371
 
346
372
  // Detect tools
347
373
  console.log(dim(` [1/5]`) + bold(" Detecting tools...\n"));
348
- const detected = [];
349
- for (const tool of TOOLS) {
350
- const found = tool.detect();
351
- if (found) {
352
- detected.push(tool);
353
- console.log(` ${green("+")} ${tool.name}`);
354
- } else {
355
- console.log(` ${dim("-")} ${dim(tool.name)} ${dim("(not found)")}`);
356
- }
357
- }
374
+ const { detected, results: detectionResults } = await detectAllTools();
375
+ printDetectionResults(detectionResults);
358
376
  console.log();
359
377
 
360
378
  if (detected.length === 0) {
361
- console.log(
362
- yellow(" No supported tools detected.\n")
363
- );
379
+ console.log(yellow(" No supported tools detected.\n"));
364
380
  console.log(" To manually configure, add to your tool's MCP config:\n");
365
381
  if (isInstalledPackage()) {
366
382
  console.log(` ${dim("{")}
@@ -381,7 +397,15 @@ async function runSetup() {
381
397
  ${dim("}")}
382
398
  ${dim("}")}\n`);
383
399
  }
384
- return;
400
+
401
+ // In non-interactive mode, continue setup without tools (vault, config, etc.)
402
+ if (isNonInteractive) {
403
+ console.log(
404
+ dim(" Continuing setup without tool configuration (--yes mode).\n"),
405
+ );
406
+ } else {
407
+ return;
408
+ }
385
409
  }
386
410
 
387
411
  // Select tools
@@ -396,7 +420,7 @@ async function runSetup() {
396
420
  console.log();
397
421
  const answer = await prompt(
398
422
  ` Select (${dim("1,2,3")} or ${dim('"all"')}):`,
399
- "all"
423
+ "all",
400
424
  );
401
425
  if (answer === "all" || answer === "") {
402
426
  selected = detected;
@@ -422,13 +446,11 @@ async function runSetup() {
422
446
  if (!existsSync(resolvedVaultDir)) {
423
447
  if (isNonInteractive) {
424
448
  mkdirSync(resolvedVaultDir, { recursive: true });
425
- console.log(
426
- `\n ${green("+")} Created ${resolvedVaultDir}`
427
- );
449
+ console.log(`\n ${green("+")} Created ${resolvedVaultDir}`);
428
450
  } else {
429
451
  const create = await prompt(
430
452
  `\n ${resolvedVaultDir} doesn't exist. Create it? (Y/n):`,
431
- "Y"
453
+ "Y",
432
454
  );
433
455
  if (create.toLowerCase() !== "n") {
434
456
  mkdirSync(resolvedVaultDir, { recursive: true });
@@ -459,11 +481,21 @@ async function runSetup() {
459
481
  // Pre-download embedding model with spinner (skip with --skip-embeddings)
460
482
  const skipEmbeddings = flags.has("--skip-embeddings");
461
483
  if (skipEmbeddings) {
462
- console.log(`\n ${dim("[3/5]")}${bold(" Embedding model")} ${dim("(skipped)")}`);
463
- console.log(dim(" FTS-only mode full-text search works, semantic search disabled."));
464
- console.log(dim(" To enable later: context-vault setup (without --skip-embeddings)"));
484
+ console.log(
485
+ `\n ${dim("[3/5]")}${bold(" Embedding model")} ${dim("(skipped)")}`,
486
+ );
487
+ console.log(
488
+ dim(
489
+ " FTS-only mode — full-text search works, semantic search disabled.",
490
+ ),
491
+ );
492
+ console.log(
493
+ dim(" To enable later: context-vault setup (without --skip-embeddings)"),
494
+ );
465
495
  } else {
466
- console.log(`\n ${dim("[3/5]")}${bold(" Downloading embedding model...")}`);
496
+ console.log(
497
+ `\n ${dim("[3/5]")}${bold(" Downloading embedding model...")}`,
498
+ );
467
499
  console.log(dim(" all-MiniLM-L6-v2 (~22MB, one-time download)\n"));
468
500
  {
469
501
  const spinnerFrames = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
@@ -471,7 +503,9 @@ async function runSetup() {
471
503
  const start = Date.now();
472
504
  const spinner = setInterval(() => {
473
505
  const elapsed = ((Date.now() - start) / 1000).toFixed(0);
474
- process.stdout.write(`\r ${spinnerFrames[frame++ % spinnerFrames.length]} Downloading... ${dim(`${elapsed}s`)}`);
506
+ process.stdout.write(
507
+ `\r ${spinnerFrames[frame++ % spinnerFrames.length]} Downloading... ${dim(`${elapsed}s`)}`,
508
+ );
475
509
  }, 100);
476
510
 
477
511
  try {
@@ -479,12 +513,29 @@ async function runSetup() {
479
513
  await embed("warmup");
480
514
 
481
515
  clearInterval(spinner);
482
- process.stdout.write(`\r ${green("+")} Embedding model ready \n`);
516
+ process.stdout.write(
517
+ `\r ${green("+")} Embedding model ready \n`,
518
+ );
483
519
  } catch (e) {
484
520
  clearInterval(spinner);
485
- process.stdout.write(`\r ${yellow("!")} Model download failed: ${e.message} \n`);
521
+ const code = e.code || e.cause?.code || "";
522
+ const isNetwork = [
523
+ "ENOTFOUND",
524
+ "ETIMEDOUT",
525
+ "ECONNREFUSED",
526
+ "ECONNRESET",
527
+ "ERR_SOCKET_TIMEOUT",
528
+ ].includes(code);
529
+ process.stdout.write(
530
+ `\r ${yellow("!")} Model download failed: ${e.message} \n`,
531
+ );
532
+ if (isNetwork) {
533
+ console.log(dim(` Check your internet connection and try again.`));
534
+ }
486
535
  console.log(dim(` Retry: context-vault setup`));
487
- console.log(dim(` Semantic search disabled — full-text search still works.`));
536
+ console.log(
537
+ dim(` Semantic search disabled — full-text search still works.`),
538
+ );
488
539
  }
489
540
  }
490
541
  }
@@ -502,7 +553,8 @@ async function runSetup() {
502
553
  console.log(`\n ${dim("[4/5]")}${bold(" Configuring tools...\n")}`);
503
554
  const results = [];
504
555
  const defaultVDir = join(HOME, "vault");
505
- const customVaultDir = resolvedVaultDir !== resolve(defaultVDir) ? resolvedVaultDir : null;
556
+ const customVaultDir =
557
+ resolvedVaultDir !== resolve(defaultVDir) ? resolvedVaultDir : null;
506
558
 
507
559
  for (const tool of selected) {
508
560
  try {
@@ -524,16 +576,15 @@ async function runSetup() {
524
576
  // Seed entry
525
577
  const seeded = createSeedEntries(resolvedVaultDir);
526
578
  if (seeded > 0) {
527
- console.log(`\n ${green("+")} Created ${seeded} starter ${seeded === 1 ? "entry" : "entries"} in vault`);
579
+ console.log(
580
+ `\n ${green("+")} Created ${seeded} starter ${seeded === 1 ? "entry" : "entries"} in vault`,
581
+ );
528
582
  }
529
583
 
530
584
  // Offer to launch UI
531
585
  console.log();
532
586
  if (!isNonInteractive) {
533
- const launchUi = await prompt(
534
- ` Launch web dashboard? (y/N):`,
535
- "N"
536
- );
587
+ const launchUi = await prompt(` Launch web dashboard? (y/N):`, "N");
537
588
  if (launchUi.toLowerCase() === "y") {
538
589
  console.log();
539
590
  runUi();
@@ -544,9 +595,21 @@ async function runSetup() {
544
595
  // Health check
545
596
  console.log(`\n ${dim("[5/5]")}${bold(" Health check...")}\n`);
546
597
  const okResults = results.filter((r) => r.ok);
598
+
599
+ // Verify DB is accessible
600
+ let dbAccessible = false;
601
+ try {
602
+ const { initDatabase } = await import("@context-vault/core/index/db");
603
+ const db = await initDatabase(vaultConfig.dbPath);
604
+ db.prepare("SELECT 1").get();
605
+ db.close();
606
+ dbAccessible = true;
607
+ } catch {}
608
+
547
609
  const checks = [
548
610
  { label: "Vault directory exists", pass: existsSync(resolvedVaultDir) },
549
611
  { label: "Config file written", pass: existsSync(configPath) },
612
+ { label: "Database accessible", pass: dbAccessible },
550
613
  { label: "At least one tool configured", pass: okResults.length > 0 },
551
614
  ];
552
615
  const passed = checks.filter((c) => c.pass).length;
@@ -555,9 +618,10 @@ async function runSetup() {
555
618
  }
556
619
 
557
620
  // Completion box
621
+ const elapsed = ((Date.now() - setupStart) / 1000).toFixed(1);
558
622
  const toolName = okResults.length ? okResults[0].tool.name : "your AI tool";
559
623
  const boxLines = [
560
- ` ✓ Setup complete — ${passed}/${checks.length} checks passed`,
624
+ ` ✓ Setup complete — ${passed}/${checks.length} checks passed (${elapsed}s)`,
561
625
  ``,
562
626
  ` ${bold("AI Tools")} — open ${toolName} and try:`,
563
627
  ` "Search my vault for getting started"`,
@@ -599,14 +663,14 @@ async function configureClaude(tool, vaultDir) {
599
663
  if (vaultDir) cmdArgs.push("--vault-dir", `"${vaultDir}"`);
600
664
  execSync(
601
665
  `claude mcp add -s user context-vault -- context-vault ${cmdArgs.join(" ")}`,
602
- { stdio: "pipe", env }
666
+ { stdio: "pipe", env },
603
667
  );
604
668
  } else {
605
669
  const cmdArgs = [`"${SERVER_PATH}"`];
606
670
  if (vaultDir) cmdArgs.push("--vault-dir", `"${vaultDir}"`);
607
671
  execSync(
608
672
  `claude mcp add -s user context-vault -- node ${cmdArgs.join(" ")}`,
609
- { stdio: "pipe", env }
673
+ { stdio: "pipe", env },
610
674
  );
611
675
  }
612
676
  } catch (e) {
@@ -631,15 +695,14 @@ async function configureCodex(tool, vaultDir) {
631
695
  if (vaultDir) cmdArgs.push("--vault-dir", `"${vaultDir}"`);
632
696
  execSync(
633
697
  `codex mcp add context-vault -- context-vault ${cmdArgs.join(" ")}`,
634
- { stdio: "pipe" }
698
+ { stdio: "pipe" },
635
699
  );
636
700
  } else {
637
701
  const cmdArgs = [`"${SERVER_PATH}"`];
638
702
  if (vaultDir) cmdArgs.push("--vault-dir", `"${vaultDir}"`);
639
- execSync(
640
- `codex mcp add context-vault -- node ${cmdArgs.join(" ")}`,
641
- { stdio: "pipe" }
642
- );
703
+ execSync(`codex mcp add context-vault -- node ${cmdArgs.join(" ")}`, {
704
+ stdio: "pipe",
705
+ });
643
706
  }
644
707
  } catch (e) {
645
708
  const stderr = e.stderr?.toString().trim();
@@ -706,7 +769,9 @@ function createSeedEntries(vaultDir) {
706
769
  mkdirSync(insightDir, { recursive: true });
707
770
  const id1 = Date.now().toString(36).toUpperCase().padStart(10, "0");
708
771
  const now = new Date().toISOString();
709
- writeFileSync(insightPath, `---
772
+ writeFileSync(
773
+ insightPath,
774
+ `---
710
775
  id: ${id1}
711
776
  tags: ["getting-started", "vault"]
712
777
  source: context-vault-setup
@@ -725,7 +790,8 @@ AI agents search it using hybrid full-text + semantic search.
725
790
 
726
791
  You can edit or delete this file anytime — it lives at:
727
792
  ${insightPath}
728
- `);
793
+ `,
794
+ );
729
795
  created++;
730
796
  }
731
797
 
@@ -736,7 +802,9 @@ ${insightPath}
736
802
  mkdirSync(decisionDir, { recursive: true });
737
803
  const id2 = (Date.now() + 1).toString(36).toUpperCase().padStart(10, "0");
738
804
  const now = new Date().toISOString();
739
- writeFileSync(decisionPath, `---
805
+ writeFileSync(
806
+ decisionPath,
807
+ `---
740
808
  id: ${id2}
741
809
  tags: ["example", "architecture"]
742
810
  source: context-vault-setup
@@ -754,7 +822,8 @@ source of truth with a SQLite index for fast search.
754
822
  - Con: No built-in sync across devices (use git or Syncthing)
755
823
 
756
824
  This is an example entry showing the decision format. Feel free to delete it.
757
- `);
825
+ `,
826
+ );
758
827
  created++;
759
828
  }
760
829
 
@@ -774,7 +843,9 @@ async function runConnect() {
774
843
  console.log(` context-vault connect --key cv_...\n`);
775
844
  console.log(` Options:`);
776
845
  console.log(` --key <key> API key (required)`);
777
- console.log(` --url <url> Hosted server URL (default: https://api.context-vault.com)`);
846
+ console.log(
847
+ ` --url <url> Hosted server URL (default: https://api.context-vault.com)`,
848
+ );
778
849
  console.log();
779
850
  return;
780
851
  }
@@ -810,10 +881,17 @@ async function runConnect() {
810
881
  user = await response.json();
811
882
  console.log(` ${green("+")} Verified — ${user.email} (${user.tier})\n`);
812
883
  } catch (e) {
813
- if (e.code === "ECONNREFUSED" || e.code === "ENOTFOUND" || e.cause?.code === "ECONNREFUSED" || e.cause?.code === "ENOTFOUND") {
884
+ if (
885
+ e.code === "ECONNREFUSED" ||
886
+ e.code === "ENOTFOUND" ||
887
+ e.cause?.code === "ECONNREFUSED" ||
888
+ e.cause?.code === "ENOTFOUND"
889
+ ) {
814
890
  console.error(`\n ${red("Cannot reach server.")}`);
815
891
  console.error(dim(` URL: ${hostedUrl}`));
816
- console.error(dim(` Check your internet connection or try --url <url>\n`));
892
+ console.error(
893
+ dim(` Check your internet connection or try --url <url>\n`),
894
+ );
817
895
  } else if (e.message?.includes("Invalid or expired")) {
818
896
  // Already handled above
819
897
  } else {
@@ -826,29 +904,31 @@ async function runConnect() {
826
904
 
827
905
  // Detect tools
828
906
  console.log(dim(` [1/2]`) + bold(" Detecting tools...\n"));
829
- const detected = [];
830
- for (const tool of TOOLS) {
831
- const found = tool.detect();
832
- if (found) {
833
- detected.push(tool);
834
- console.log(` ${green("+")} ${tool.name}`);
835
- } else {
836
- console.log(` ${dim("-")} ${dim(tool.name)} ${dim("(not found)")}`);
837
- }
838
- }
907
+ const { detected, results: connectDetectionResults } = await detectAllTools();
908
+ printDetectionResults(connectDetectionResults);
839
909
  console.log();
840
910
 
841
911
  if (detected.length === 0) {
842
912
  console.log(yellow(" No supported tools detected."));
843
913
  console.log(`\n Add this to your tool's MCP config manually:\n`);
844
- console.log(dim(` ${JSON.stringify({
845
- mcpServers: {
846
- "context-vault": {
847
- url: `${hostedUrl}/mcp`,
848
- headers: { Authorization: `Bearer ${apiKey}` },
849
- },
850
- },
851
- }, null, 2).split("\n").join("\n ")}`));
914
+ console.log(
915
+ dim(
916
+ ` ${JSON.stringify(
917
+ {
918
+ mcpServers: {
919
+ "context-vault": {
920
+ url: `${hostedUrl}/mcp`,
921
+ headers: { Authorization: `Bearer ${apiKey}` },
922
+ },
923
+ },
924
+ },
925
+ null,
926
+ 2,
927
+ )
928
+ .split("\n")
929
+ .join("\n ")}`,
930
+ ),
931
+ );
852
932
  console.log();
853
933
  return;
854
934
  }
@@ -865,12 +945,15 @@ async function runConnect() {
865
945
  console.log();
866
946
  const answer = await prompt(
867
947
  ` Select (${dim("1,2,3")} or ${dim('"all"')}):`,
868
- "all"
948
+ "all",
869
949
  );
870
950
  if (answer === "all" || answer === "") {
871
951
  selected = detected;
872
952
  } else {
873
- const nums = answer.split(/[,\s]+/).map((n) => parseInt(n, 10) - 1).filter((n) => n >= 0 && n < detected.length);
953
+ const nums = answer
954
+ .split(/[,\s]+/)
955
+ .map((n) => parseInt(n, 10) - 1)
956
+ .filter((n) => n >= 0 && n < detected.length);
874
957
  selected = nums.map((n) => detected[n]);
875
958
  if (selected.length === 0) selected = detected;
876
959
  }
@@ -894,7 +977,9 @@ async function runConnect() {
894
977
  }
895
978
 
896
979
  console.log();
897
- console.log(green(" ✓ Connected! Your AI tools can now access your hosted vault."));
980
+ console.log(
981
+ green(" ✓ Connected! Your AI tools can now access your hosted vault."),
982
+ );
898
983
  console.log(dim(` Endpoint: ${hostedUrl}/mcp`));
899
984
  console.log();
900
985
  }
@@ -903,13 +988,17 @@ function configureClaudeHosted(apiKey, hostedUrl) {
903
988
  const env = { ...process.env };
904
989
  delete env.CLAUDECODE;
905
990
 
906
- try { execSync("claude mcp remove context-mcp -s user", { stdio: "pipe", env }); } catch {}
907
- try { execSync("claude mcp remove context-vault -s user", { stdio: "pipe", env }); } catch {}
991
+ try {
992
+ execSync("claude mcp remove context-mcp -s user", { stdio: "pipe", env });
993
+ } catch {}
994
+ try {
995
+ execSync("claude mcp remove context-vault -s user", { stdio: "pipe", env });
996
+ } catch {}
908
997
 
909
998
  try {
910
999
  execSync(
911
1000
  `claude mcp add -s user --transport http context-vault ${hostedUrl}/mcp`,
912
- { stdio: "pipe", env }
1001
+ { stdio: "pipe", env },
913
1002
  );
914
1003
  } catch (e) {
915
1004
  const stderr = e.stderr?.toString().trim();
@@ -918,14 +1007,17 @@ function configureClaudeHosted(apiKey, hostedUrl) {
918
1007
  }
919
1008
 
920
1009
  function configureCodexHosted(apiKey, hostedUrl) {
921
- try { execSync("codex mcp remove context-mcp", { stdio: "pipe" }); } catch {}
922
- try { execSync("codex mcp remove context-vault", { stdio: "pipe" }); } catch {}
1010
+ try {
1011
+ execSync("codex mcp remove context-mcp", { stdio: "pipe" });
1012
+ } catch {}
1013
+ try {
1014
+ execSync("codex mcp remove context-vault", { stdio: "pipe" });
1015
+ } catch {}
923
1016
 
924
1017
  try {
925
- execSync(
926
- `codex mcp add --transport http context-vault ${hostedUrl}/mcp`,
927
- { stdio: "pipe" }
928
- );
1018
+ execSync(`codex mcp add --transport http context-vault ${hostedUrl}/mcp`, {
1019
+ stdio: "pipe",
1020
+ });
929
1021
  } catch (e) {
930
1022
  const stderr = e.stderr?.toString().trim();
931
1023
  throw new Error(stderr || e.message);
@@ -975,14 +1067,18 @@ function runUi() {
975
1067
  // Try bundled path first (npm install), then workspace path (local dev)
976
1068
  const bundledDist = resolve(ROOT, "app-dist");
977
1069
  const workspaceDist = resolve(ROOT, "..", "app", "dist");
978
- const appDist = existsSync(join(bundledDist, "index.html")) ? bundledDist
979
- : existsSync(join(workspaceDist, "index.html")) ? workspaceDist
980
- : null;
1070
+ const appDist = existsSync(join(bundledDist, "index.html"))
1071
+ ? bundledDist
1072
+ : existsSync(join(workspaceDist, "index.html"))
1073
+ ? workspaceDist
1074
+ : null;
981
1075
 
982
1076
  if (!appDist) {
983
1077
  console.error(red("Web dashboard not found."));
984
1078
  if (isInstalledPackage()) {
985
- console.error(dim(" Try reinstalling: npm install -g context-vault@latest"));
1079
+ console.error(
1080
+ dim(" Try reinstalling: npm install -g context-vault@latest"),
1081
+ );
986
1082
  } else {
987
1083
  console.error(dim(" From repo: npm run build --workspace=packages/app"));
988
1084
  console.error(dim(" Then run: context-vault ui"));
@@ -1024,7 +1120,12 @@ function launchServer(port, localServer) {
1024
1120
  setTimeout(() => {
1025
1121
  try {
1026
1122
  const url = `http://localhost:${port}`;
1027
- const open = PLATFORM === "darwin" ? "open" : PLATFORM === "win32" ? "start" : "xdg-open";
1123
+ const open =
1124
+ PLATFORM === "darwin"
1125
+ ? "open"
1126
+ : PLATFORM === "win32"
1127
+ ? "start"
1128
+ : "xdg-open";
1028
1129
  execSync(`${open} ${url}`, { stdio: "ignore" });
1029
1130
  } catch {}
1030
1131
  }, 1500);
@@ -1036,15 +1137,14 @@ async function runReindex() {
1036
1137
  console.log(dim("Loading vault..."));
1037
1138
 
1038
1139
  const { resolveConfig } = await import("@context-vault/core/core/config");
1039
- const { initDatabase, prepareStatements, insertVec, deleteVec } = await import("@context-vault/core/index/db");
1140
+ const { initDatabase, prepareStatements, insertVec, deleteVec } =
1141
+ await import("@context-vault/core/index/db");
1040
1142
  const { embed } = await import("@context-vault/core/index/embed");
1041
1143
  const { reindex } = await import("@context-vault/core/index");
1042
1144
 
1043
1145
  const config = resolveConfig();
1044
1146
  if (!config.vaultDirExists) {
1045
- console.error(
1046
- red(`Vault directory not found: ${config.vaultDir}`)
1047
- );
1147
+ console.error(red(`Vault directory not found: ${config.vaultDir}`));
1048
1148
  console.error("Run " + cyan("context-vault setup") + " to configure.");
1049
1149
  process.exit(1);
1050
1150
  }
@@ -1087,11 +1187,15 @@ async function runStatus() {
1087
1187
  console.log();
1088
1188
  console.log(` ${bold("◇ context-vault")} ${dim(`v${VERSION}`)}`);
1089
1189
  console.log();
1090
- console.log(` Vault: ${config.vaultDir} ${dim(`(${config.vaultDirExists ? status.fileCount + " files" : "missing"})`)}`);
1190
+ console.log(
1191
+ ` Vault: ${config.vaultDir} ${dim(`(${config.vaultDirExists ? status.fileCount + " files" : "missing"})`)}`,
1192
+ );
1091
1193
  console.log(` Database: ${config.dbPath} ${dim(`(${status.dbSize})`)}`);
1092
1194
  console.log(` Dev dir: ${config.devDir}`);
1093
1195
  console.log(` Data dir: ${config.dataDir}`);
1094
- console.log(` Config: ${config.configPath} ${dim(`(${existsSync(config.configPath) ? "exists" : "missing"})`)}`);
1196
+ console.log(
1197
+ ` Config: ${config.configPath} ${dim(`(${existsSync(config.configPath) ? "exists" : "missing"})`)}`,
1198
+ );
1095
1199
  console.log(` Resolved: ${status.resolvedFrom}`);
1096
1200
  console.log(` Schema: v7 (teams)`);
1097
1201
 
@@ -1147,9 +1251,14 @@ async function runUpdate() {
1147
1251
 
1148
1252
  let latest;
1149
1253
  try {
1150
- latest = execSync("npm view context-vault version", { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }).trim();
1254
+ latest = execSync("npm view context-vault version", {
1255
+ encoding: "utf-8",
1256
+ stdio: ["pipe", "pipe", "pipe"],
1257
+ }).trim();
1151
1258
  } catch {
1152
- console.error(red(" Could not check for updates. Verify your network connection."));
1259
+ console.error(
1260
+ red(" Could not check for updates. Verify your network connection."),
1261
+ );
1153
1262
  return;
1154
1263
  }
1155
1264
 
@@ -1177,7 +1286,9 @@ async function runUpdate() {
1177
1286
  console.log();
1178
1287
  console.log(green(` ✓ Updated to v${latest}`));
1179
1288
  } catch {
1180
- console.error(red(" Update failed. Try manually: npm install -g context-vault@latest"));
1289
+ console.error(
1290
+ red(" Update failed. Try manually: npm install -g context-vault@latest"),
1291
+ );
1181
1292
  }
1182
1293
  console.log();
1183
1294
  }
@@ -1193,7 +1304,9 @@ async function runUninstall() {
1193
1304
  try {
1194
1305
  const env = { ...process.env };
1195
1306
  delete env.CLAUDECODE;
1196
- try { execSync("claude mcp remove context-mcp -s user", { stdio: "pipe", env }); } catch {}
1307
+ try {
1308
+ execSync("claude mcp remove context-mcp -s user", { stdio: "pipe", env });
1309
+ } catch {}
1197
1310
  execSync("claude mcp remove context-vault -s user", { stdio: "pipe", env });
1198
1311
  console.log(` ${green("+")} Removed from Claude Code`);
1199
1312
  } catch {
@@ -1202,7 +1315,9 @@ async function runUninstall() {
1202
1315
 
1203
1316
  // Remove from Codex (both old and new names)
1204
1317
  try {
1205
- try { execSync("codex mcp remove context-mcp", { stdio: "pipe" }); } catch {}
1318
+ try {
1319
+ execSync("codex mcp remove context-mcp", { stdio: "pipe" });
1320
+ } catch {}
1206
1321
  execSync("codex mcp remove context-vault", { stdio: "pipe" });
1207
1322
  console.log(` ${green("+")} Removed from Codex`);
1208
1323
  } catch {
@@ -1244,7 +1359,9 @@ async function runUninstall() {
1244
1359
  }
1245
1360
 
1246
1361
  console.log();
1247
- console.log(dim(" Vault directory was not touched (your knowledge files are safe)."));
1362
+ console.log(
1363
+ dim(" Vault directory was not touched (your knowledge files are safe)."),
1364
+ );
1248
1365
  console.log(` To fully remove: ${cyan("npm uninstall -g context-vault")}`);
1249
1366
  console.log();
1250
1367
  }
@@ -1252,17 +1369,25 @@ async function runUninstall() {
1252
1369
  // ─── Migrate Command ─────────────────────────────────────────────────────────
1253
1370
 
1254
1371
  async function runMigrate() {
1255
- const direction = args.includes("--to-hosted") ? "to-hosted"
1256
- : args.includes("--to-local") ? "to-local"
1257
- : null;
1372
+ const direction = args.includes("--to-hosted")
1373
+ ? "to-hosted"
1374
+ : args.includes("--to-local")
1375
+ ? "to-local"
1376
+ : null;
1258
1377
 
1259
1378
  if (!direction) {
1260
1379
  console.log(`\n ${bold("context-vault migrate")}\n`);
1261
1380
  console.log(` Usage:`);
1262
- console.log(` context-vault migrate --to-hosted Upload local vault to hosted service`);
1263
- console.log(` context-vault migrate --to-local Download hosted vault to local files`);
1381
+ console.log(
1382
+ ` context-vault migrate --to-hosted Upload local vault to hosted service`,
1383
+ );
1384
+ console.log(
1385
+ ` context-vault migrate --to-local Download hosted vault to local files`,
1386
+ );
1264
1387
  console.log(`\n Options:`);
1265
- console.log(` --url <url> Hosted server URL (default: https://api.context-vault.com)`);
1388
+ console.log(
1389
+ ` --url <url> Hosted server URL (default: https://api.context-vault.com)`,
1390
+ );
1266
1391
  console.log(` --key <key> API key (cv_...)`);
1267
1392
  console.log();
1268
1393
  return;
@@ -1281,7 +1406,8 @@ async function runMigrate() {
1281
1406
  const config = resolveConfig();
1282
1407
 
1283
1408
  if (direction === "to-hosted") {
1284
- const { migrateToHosted } = await import("@context-vault/hosted/migration/migrate");
1409
+ const { migrateToHosted } =
1410
+ await import("@context-vault/hosted/migration/migrate");
1285
1411
  console.log(`\n ${bold("Migrating to hosted")}...`);
1286
1412
  console.log(dim(` Vault: ${config.vaultDir}`));
1287
1413
  console.log(dim(` Target: ${hostedUrl}\n`));
@@ -1302,7 +1428,8 @@ async function runMigrate() {
1302
1428
  }
1303
1429
  console.log(dim("\n Your local vault was not modified (safe backup)."));
1304
1430
  } else {
1305
- const { migrateToLocal } = await import("@context-vault/hosted/migration/migrate");
1431
+ const { migrateToLocal } =
1432
+ await import("@context-vault/hosted/migration/migrate");
1306
1433
  console.log(`\n ${bold("Migrating to local")}...`);
1307
1434
  console.log(dim(` Source: ${hostedUrl}`));
1308
1435
  console.log(dim(` Target: ${config.vaultDir}\n`));
@@ -1318,7 +1445,9 @@ async function runMigrate() {
1318
1445
  if (results.failed > 0) {
1319
1446
  console.log(` ${red("-")} ${results.failed} failed`);
1320
1447
  }
1321
- console.log(dim("\n Run `context-vault reindex` to rebuild the search index."));
1448
+ console.log(
1449
+ dim("\n Run `context-vault reindex` to rebuild the search index."),
1450
+ );
1322
1451
  }
1323
1452
  console.log();
1324
1453
  }
@@ -1340,10 +1469,13 @@ async function runImport() {
1340
1469
  }
1341
1470
 
1342
1471
  const { resolveConfig } = await import("@context-vault/core/core/config");
1343
- const { initDatabase, prepareStatements, insertVec, deleteVec } = await import("@context-vault/core/index/db");
1472
+ const { initDatabase, prepareStatements, insertVec, deleteVec } =
1473
+ await import("@context-vault/core/index/db");
1344
1474
  const { embed } = await import("@context-vault/core/index/embed");
1345
- const { parseFile, parseDirectory } = await import("@context-vault/core/capture/importers");
1346
- const { importEntries } = await import("@context-vault/core/capture/import-pipeline");
1475
+ const { parseFile, parseDirectory } =
1476
+ await import("@context-vault/core/capture/importers");
1477
+ const { importEntries } =
1478
+ await import("@context-vault/core/capture/import-pipeline");
1347
1479
  const { readFileSync, statSync } = await import("node:fs");
1348
1480
 
1349
1481
  const kind = getFlag("--kind") || undefined;
@@ -1376,7 +1508,9 @@ async function runImport() {
1376
1508
  if (dryRun) {
1377
1509
  for (let i = 0; i < Math.min(entries.length, 20); i++) {
1378
1510
  const e = entries[i];
1379
- console.log(` ${dim(`[${i + 1}]`)} ${e.kind} — ${e.title || e.body.slice(0, 60)}${e.tags?.length ? ` ${dim(`[${e.tags.join(", ")}]`)}` : ""}`);
1511
+ console.log(
1512
+ ` ${dim(`[${i + 1}]`)} ${e.kind} — ${e.title || e.body.slice(0, 60)}${e.tags?.length ? ` ${dim(`[${e.tags.join(", ")}]`)}` : ""}`,
1513
+ );
1380
1514
  }
1381
1515
  if (entries.length > 20) {
1382
1516
  console.log(dim(` ... and ${entries.length - 20} more`));
@@ -1395,7 +1529,10 @@ async function runImport() {
1395
1529
  const db = await initDatabase(config.dbPath);
1396
1530
  const stmts = prepareStatements(db);
1397
1531
  const ctx = {
1398
- db, config, stmts, embed,
1532
+ db,
1533
+ config,
1534
+ stmts,
1535
+ embed,
1399
1536
  insertVec: (r, e) => insertVec(stmts, r, e),
1400
1537
  deleteVec: (r) => deleteVec(stmts, r),
1401
1538
  };
@@ -1425,9 +1562,14 @@ async function runImport() {
1425
1562
  async function runExport() {
1426
1563
  const format = getFlag("--format") || "json";
1427
1564
  const output = getFlag("--output");
1565
+ const rawPageSize = getFlag("--page-size");
1566
+ const pageSize = rawPageSize
1567
+ ? Math.max(1, parseInt(rawPageSize, 10) || 100)
1568
+ : null;
1428
1569
 
1429
1570
  const { resolveConfig } = await import("@context-vault/core/core/config");
1430
- const { initDatabase, prepareStatements } = await import("@context-vault/core/index/db");
1571
+ const { initDatabase, prepareStatements } =
1572
+ await import("@context-vault/core/index/db");
1431
1573
  const { writeFileSync } = await import("node:fs");
1432
1574
 
1433
1575
  const config = resolveConfig();
@@ -1438,30 +1580,50 @@ async function runExport() {
1438
1580
 
1439
1581
  const db = await initDatabase(config.dbPath);
1440
1582
 
1441
- const rows = db.prepare(
1442
- "SELECT * FROM vault WHERE (expires_at IS NULL OR expires_at > datetime('now')) ORDER BY created_at DESC"
1443
- ).all();
1583
+ const whereClause =
1584
+ "WHERE (expires_at IS NULL OR expires_at > datetime('now'))";
1444
1585
 
1445
- db.close();
1586
+ let entries;
1587
+ if (pageSize) {
1588
+ // Paginated: fetch in chunks to avoid loading everything into memory
1589
+ entries = [];
1590
+ let offset = 0;
1591
+ const stmt = db.prepare(
1592
+ `SELECT * FROM vault ${whereClause} ORDER BY created_at DESC LIMIT ? OFFSET ?`,
1593
+ );
1594
+ while (true) {
1595
+ const rows = stmt.all(pageSize, offset);
1596
+ if (rows.length === 0) break;
1597
+ for (const row of rows) {
1598
+ entries.push(mapExportRow(row));
1599
+ }
1600
+ offset += rows.length;
1601
+ if (rows.length < pageSize) break;
1602
+ }
1603
+ } else {
1604
+ const rows = db
1605
+ .prepare(`SELECT * FROM vault ${whereClause} ORDER BY created_at DESC`)
1606
+ .all();
1607
+ entries = rows.map(mapExportRow);
1608
+ }
1446
1609
 
1447
- const entries = rows.map((row) => ({
1448
- id: row.id,
1449
- kind: row.kind,
1450
- category: row.category,
1451
- title: row.title || null,
1452
- body: row.body || null,
1453
- tags: row.tags ? JSON.parse(row.tags) : [],
1454
- meta: row.meta ? JSON.parse(row.meta) : {},
1455
- source: row.source || null,
1456
- identity_key: row.identity_key || null,
1457
- expires_at: row.expires_at || null,
1458
- created_at: row.created_at,
1459
- }));
1610
+ db.close();
1460
1611
 
1461
1612
  let content;
1462
1613
 
1463
1614
  if (format === "csv") {
1464
- const headers = ["id", "kind", "category", "title", "body", "tags", "source", "identity_key", "expires_at", "created_at"];
1615
+ const headers = [
1616
+ "id",
1617
+ "kind",
1618
+ "category",
1619
+ "title",
1620
+ "body",
1621
+ "tags",
1622
+ "source",
1623
+ "identity_key",
1624
+ "expires_at",
1625
+ "created_at",
1626
+ ];
1465
1627
  const csvLines = [headers.join(",")];
1466
1628
  for (const e of entries) {
1467
1629
  const row = headers.map((h) => {
@@ -1478,7 +1640,11 @@ async function runExport() {
1478
1640
  }
1479
1641
  content = csvLines.join("\n");
1480
1642
  } else {
1481
- content = JSON.stringify({ entries, total: entries.length, exported_at: new Date().toISOString() }, null, 2);
1643
+ content = JSON.stringify(
1644
+ { entries, total: entries.length, exported_at: new Date().toISOString() },
1645
+ null,
1646
+ 2,
1647
+ );
1482
1648
  }
1483
1649
 
1484
1650
  if (output) {
@@ -1489,6 +1655,22 @@ async function runExport() {
1489
1655
  }
1490
1656
  }
1491
1657
 
1658
+ function mapExportRow(row) {
1659
+ return {
1660
+ id: row.id,
1661
+ kind: row.kind,
1662
+ category: row.category,
1663
+ title: row.title || null,
1664
+ body: row.body || null,
1665
+ tags: row.tags ? JSON.parse(row.tags) : [],
1666
+ meta: row.meta ? JSON.parse(row.meta) : {},
1667
+ source: row.source || null,
1668
+ identity_key: row.identity_key || null,
1669
+ expires_at: row.expires_at || null,
1670
+ created_at: row.created_at,
1671
+ };
1672
+ }
1673
+
1492
1674
  // ─── Ingest Command ─────────────────────────────────────────────────────────
1493
1675
 
1494
1676
  async function runIngest() {
@@ -1521,8 +1703,11 @@ async function runIngest() {
1521
1703
  }
1522
1704
 
1523
1705
  console.log(`\n ${bold(entry.title)}`);
1524
- console.log(` ${dim(`kind: ${entry.kind} | source: ${entry.source} | ${entry.body.length} chars`)}`);
1525
- if (entry.tags?.length) console.log(` ${dim(`tags: ${entry.tags.join(", ")}`)}`);
1706
+ console.log(
1707
+ ` ${dim(`kind: ${entry.kind} | source: ${entry.source} | ${entry.body.length} chars`)}`,
1708
+ );
1709
+ if (entry.tags?.length)
1710
+ console.log(` ${dim(`tags: ${entry.tags.join(", ")}`)}`);
1526
1711
 
1527
1712
  if (dryRun) {
1528
1713
  console.log(`\n${dim(" Preview (first 500 chars):")}`);
@@ -1532,10 +1717,10 @@ async function runIngest() {
1532
1717
  }
1533
1718
 
1534
1719
  const { resolveConfig } = await import("@context-vault/core/core/config");
1535
- const { initDatabase, prepareStatements, insertVec, deleteVec } = await import("@context-vault/core/index/db");
1720
+ const { initDatabase, prepareStatements, insertVec, deleteVec } =
1721
+ await import("@context-vault/core/index/db");
1536
1722
  const { embed } = await import("@context-vault/core/index/embed");
1537
1723
  const { captureAndIndex } = await import("@context-vault/core/capture");
1538
- const { indexEntry } = await import("@context-vault/core/index");
1539
1724
 
1540
1725
  const config = resolveConfig();
1541
1726
  if (!config.vaultDirExists) {
@@ -1546,12 +1731,15 @@ async function runIngest() {
1546
1731
  const db = await initDatabase(config.dbPath);
1547
1732
  const stmts = prepareStatements(db);
1548
1733
  const ctx = {
1549
- db, config, stmts, embed,
1734
+ db,
1735
+ config,
1736
+ stmts,
1737
+ embed,
1550
1738
  insertVec: (r, e) => insertVec(stmts, r, e),
1551
1739
  deleteVec: (r) => deleteVec(stmts, r),
1552
1740
  };
1553
1741
 
1554
- const result = await captureAndIndex(ctx, entry, indexEntry);
1742
+ const result = await captureAndIndex(ctx, entry);
1555
1743
  db.close();
1556
1744
 
1557
1745
  const relPath = result.filePath.replace(config.vaultDir + "/", "");
@@ -1571,7 +1759,9 @@ async function runLink() {
1571
1759
  console.log(` Link your local vault to a hosted Context Vault account.\n`);
1572
1760
  console.log(` Options:`);
1573
1761
  console.log(` --key <key> API key (required)`);
1574
- console.log(` --url <url> Hosted server URL (default: https://api.context-vault.com)`);
1762
+ console.log(
1763
+ ` --url <url> Hosted server URL (default: https://api.context-vault.com)`,
1764
+ );
1575
1765
  console.log();
1576
1766
  return;
1577
1767
  }
@@ -1596,7 +1786,9 @@ async function runLink() {
1596
1786
  const configPath = join(dataDir, "config.json");
1597
1787
  let config = {};
1598
1788
  if (existsSync(configPath)) {
1599
- try { config = JSON.parse(readFileSync(configPath, "utf-8")); } catch {}
1789
+ try {
1790
+ config = JSON.parse(readFileSync(configPath, "utf-8"));
1791
+ } catch {}
1600
1792
  }
1601
1793
 
1602
1794
  config.hostedUrl = hostedUrl;
@@ -1628,21 +1820,34 @@ async function runSync() {
1628
1820
  const configPath = join(dataDir, "config.json");
1629
1821
  let storedConfig = {};
1630
1822
  if (existsSync(configPath)) {
1631
- try { storedConfig = JSON.parse(readFileSync(configPath, "utf-8")); } catch {}
1823
+ try {
1824
+ storedConfig = JSON.parse(readFileSync(configPath, "utf-8"));
1825
+ } catch {}
1632
1826
  }
1633
1827
 
1634
1828
  const apiKey = getFlag("--key") || storedConfig.apiKey;
1635
- const hostedUrl = getFlag("--url") || storedConfig.hostedUrl || "https://api.context-vault.com";
1829
+ const hostedUrl =
1830
+ getFlag("--url") ||
1831
+ storedConfig.hostedUrl ||
1832
+ "https://api.context-vault.com";
1636
1833
 
1637
1834
  if (!apiKey) {
1638
- console.error(red(" Not linked. Run `context-vault link --key cv_...` first."));
1835
+ console.error(
1836
+ red(" Not linked. Run `context-vault link --key cv_...` first."),
1837
+ );
1639
1838
  process.exit(1);
1640
1839
  }
1641
1840
 
1642
1841
  const { resolveConfig } = await import("@context-vault/core/core/config");
1643
- const { initDatabase, prepareStatements, insertVec, deleteVec } = await import("@context-vault/core/index/db");
1842
+ const { initDatabase, prepareStatements, insertVec, deleteVec } =
1843
+ await import("@context-vault/core/index/db");
1644
1844
  const { embed } = await import("@context-vault/core/index/embed");
1645
- const { buildLocalManifest, fetchRemoteManifest, computeSyncPlan, executeSync } = await import("@context-vault/core/sync");
1845
+ const {
1846
+ buildLocalManifest,
1847
+ fetchRemoteManifest,
1848
+ computeSyncPlan,
1849
+ executeSync,
1850
+ } = await import("@context-vault/core/sync");
1646
1851
 
1647
1852
  const config = resolveConfig();
1648
1853
  if (!config.vaultDirExists) {
@@ -1653,7 +1858,10 @@ async function runSync() {
1653
1858
  const db = await initDatabase(config.dbPath);
1654
1859
  const stmts = prepareStatements(db);
1655
1860
  const ctx = {
1656
- db, config, stmts, embed,
1861
+ db,
1862
+ config,
1863
+ stmts,
1864
+ embed,
1657
1865
  insertVec: (r, e) => insertVec(stmts, r, e),
1658
1866
  deleteVec: (r) => deleteVec(stmts, r),
1659
1867
  };
@@ -1703,7 +1911,9 @@ async function runSync() {
1703
1911
  apiKey,
1704
1912
  plan,
1705
1913
  onProgress: (phase, current, total) => {
1706
- process.stdout.write(`\r ${phase === "push" ? "Pushing" : "Pulling"}... ${current}/${total}`);
1914
+ process.stdout.write(
1915
+ `\r ${phase === "push" ? "Pushing" : "Pulling"}... ${current}/${total}`,
1916
+ );
1707
1917
  },
1708
1918
  });
1709
1919