context-vault 2.17.1 → 3.0.1

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.
Files changed (110) hide show
  1. package/bin/cli.js +644 -65
  2. package/node_modules/@context-vault/core/dist/capture.d.ts +21 -0
  3. package/node_modules/@context-vault/core/dist/capture.d.ts.map +1 -0
  4. package/node_modules/@context-vault/core/dist/capture.js +269 -0
  5. package/node_modules/@context-vault/core/dist/capture.js.map +1 -0
  6. package/node_modules/@context-vault/core/dist/categories.d.ts +6 -0
  7. package/node_modules/@context-vault/core/dist/categories.d.ts.map +1 -0
  8. package/node_modules/@context-vault/core/dist/categories.js +50 -0
  9. package/node_modules/@context-vault/core/dist/categories.js.map +1 -0
  10. package/node_modules/@context-vault/core/dist/config.d.ts +4 -0
  11. package/node_modules/@context-vault/core/dist/config.d.ts.map +1 -0
  12. package/node_modules/@context-vault/core/dist/config.js +190 -0
  13. package/node_modules/@context-vault/core/dist/config.js.map +1 -0
  14. package/node_modules/@context-vault/core/dist/constants.d.ts +33 -0
  15. package/node_modules/@context-vault/core/dist/constants.d.ts.map +1 -0
  16. package/node_modules/@context-vault/core/dist/constants.js +23 -0
  17. package/node_modules/@context-vault/core/dist/constants.js.map +1 -0
  18. package/node_modules/@context-vault/core/dist/db.d.ts +13 -0
  19. package/node_modules/@context-vault/core/dist/db.d.ts.map +1 -0
  20. package/node_modules/@context-vault/core/dist/db.js +191 -0
  21. package/node_modules/@context-vault/core/dist/db.js.map +1 -0
  22. package/node_modules/@context-vault/core/dist/embed.d.ts +5 -0
  23. package/node_modules/@context-vault/core/dist/embed.d.ts.map +1 -0
  24. package/node_modules/@context-vault/core/dist/embed.js +78 -0
  25. package/node_modules/@context-vault/core/dist/embed.js.map +1 -0
  26. package/node_modules/@context-vault/core/dist/files.d.ts +13 -0
  27. package/node_modules/@context-vault/core/dist/files.d.ts.map +1 -0
  28. package/node_modules/@context-vault/core/dist/files.js +66 -0
  29. package/node_modules/@context-vault/core/dist/files.js.map +1 -0
  30. package/node_modules/@context-vault/core/dist/formatters.d.ts +8 -0
  31. package/node_modules/@context-vault/core/dist/formatters.d.ts.map +1 -0
  32. package/node_modules/@context-vault/core/dist/formatters.js +18 -0
  33. package/node_modules/@context-vault/core/dist/formatters.js.map +1 -0
  34. package/node_modules/@context-vault/core/dist/frontmatter.d.ts +12 -0
  35. package/node_modules/@context-vault/core/dist/frontmatter.d.ts.map +1 -0
  36. package/node_modules/@context-vault/core/dist/frontmatter.js +101 -0
  37. package/node_modules/@context-vault/core/dist/frontmatter.js.map +1 -0
  38. package/node_modules/@context-vault/core/dist/index.d.ts +10 -0
  39. package/node_modules/@context-vault/core/dist/index.d.ts.map +1 -0
  40. package/node_modules/@context-vault/core/dist/index.js +297 -0
  41. package/node_modules/@context-vault/core/dist/index.js.map +1 -0
  42. package/node_modules/@context-vault/core/dist/ingest-url.d.ts +20 -0
  43. package/node_modules/@context-vault/core/dist/ingest-url.d.ts.map +1 -0
  44. package/node_modules/@context-vault/core/dist/ingest-url.js +113 -0
  45. package/node_modules/@context-vault/core/dist/ingest-url.js.map +1 -0
  46. package/node_modules/@context-vault/core/dist/main.d.ts +14 -0
  47. package/node_modules/@context-vault/core/dist/main.d.ts.map +1 -0
  48. package/node_modules/@context-vault/core/dist/main.js +25 -0
  49. package/node_modules/@context-vault/core/dist/main.js.map +1 -0
  50. package/node_modules/@context-vault/core/dist/search.d.ts +18 -0
  51. package/node_modules/@context-vault/core/dist/search.d.ts.map +1 -0
  52. package/node_modules/@context-vault/core/dist/search.js +238 -0
  53. package/node_modules/@context-vault/core/dist/search.js.map +1 -0
  54. package/node_modules/@context-vault/core/dist/types.d.ts +176 -0
  55. package/node_modules/@context-vault/core/dist/types.d.ts.map +1 -0
  56. package/node_modules/@context-vault/core/dist/types.js +2 -0
  57. package/node_modules/@context-vault/core/dist/types.js.map +1 -0
  58. package/node_modules/@context-vault/core/package.json +66 -16
  59. package/node_modules/@context-vault/core/src/capture.ts +308 -0
  60. package/node_modules/@context-vault/core/src/categories.ts +54 -0
  61. package/node_modules/@context-vault/core/src/{core/config.js → config.ts} +34 -33
  62. package/node_modules/@context-vault/core/src/{constants.js → constants.ts} +6 -3
  63. package/node_modules/@context-vault/core/src/db.ts +229 -0
  64. package/node_modules/@context-vault/core/src/{index/embed.js → embed.ts} +10 -35
  65. package/node_modules/@context-vault/core/src/{core/files.js → files.ts} +15 -20
  66. package/node_modules/@context-vault/core/src/{capture/formatters.js → formatters.ts} +13 -11
  67. package/node_modules/@context-vault/core/src/{core/frontmatter.js → frontmatter.ts} +26 -33
  68. package/node_modules/@context-vault/core/src/index.ts +351 -0
  69. package/node_modules/@context-vault/core/src/ingest-url.ts +99 -0
  70. package/node_modules/@context-vault/core/src/main.ts +111 -0
  71. package/node_modules/@context-vault/core/src/{retrieve/index.js → search.ts} +62 -150
  72. package/node_modules/@context-vault/core/src/types.ts +166 -0
  73. package/package.json +12 -7
  74. package/scripts/postinstall.js +1 -1
  75. package/{node_modules/@context-vault/core/src/core → src}/error-log.js +1 -15
  76. package/{node_modules/@context-vault/core/src/server → src}/helpers.js +9 -4
  77. package/src/linking.js +100 -0
  78. package/{node_modules/@context-vault/core/src/server/tools.js → src/register-tools.js} +14 -13
  79. package/src/{server/index.js → server.js} +10 -38
  80. package/src/status.js +235 -0
  81. package/{node_modules/@context-vault/core/src/core → src}/telemetry.js +9 -19
  82. package/src/temporal.js +97 -0
  83. package/{node_modules/@context-vault/core/src/server → src}/tools/context-status.js +3 -4
  84. package/{node_modules/@context-vault/core/src/server → src}/tools/create-snapshot.js +6 -7
  85. package/{node_modules/@context-vault/core/src/server → src}/tools/delete-context.js +0 -2
  86. package/{node_modules/@context-vault/core/src/server → src}/tools/get-context.js +17 -21
  87. package/{node_modules/@context-vault/core/src/server → src}/tools/ingest-project.js +5 -6
  88. package/{node_modules/@context-vault/core/src/server → src}/tools/ingest-url.js +3 -4
  89. package/{node_modules/@context-vault/core/src/server → src}/tools/list-buckets.js +4 -5
  90. package/{node_modules/@context-vault/core/src/server → src}/tools/list-context.js +3 -6
  91. package/{node_modules/@context-vault/core/src/server → src}/tools/save-context.js +17 -20
  92. package/{node_modules/@context-vault/core/src/server → src}/tools/session-start.js +9 -16
  93. package/node_modules/@context-vault/core/src/capture/file-ops.js +0 -99
  94. package/node_modules/@context-vault/core/src/capture/import-pipeline.js +0 -46
  95. package/node_modules/@context-vault/core/src/capture/importers.js +0 -387
  96. package/node_modules/@context-vault/core/src/capture/index.js +0 -250
  97. package/node_modules/@context-vault/core/src/capture/ingest-url.js +0 -252
  98. package/node_modules/@context-vault/core/src/consolidation/index.js +0 -112
  99. package/node_modules/@context-vault/core/src/core/categories.js +0 -73
  100. package/node_modules/@context-vault/core/src/core/linking.js +0 -161
  101. package/node_modules/@context-vault/core/src/core/migrate-dirs.js +0 -196
  102. package/node_modules/@context-vault/core/src/core/status.js +0 -350
  103. package/node_modules/@context-vault/core/src/core/temporal.js +0 -146
  104. package/node_modules/@context-vault/core/src/index/db.js +0 -586
  105. package/node_modules/@context-vault/core/src/index/index.js +0 -583
  106. package/node_modules/@context-vault/core/src/index.js +0 -71
  107. package/node_modules/@context-vault/core/src/sync/sync.js +0 -235
  108. package/src/hooks/post-tool-call.mjs +0 -62
  109. package/src/hooks/session-end.mjs +0 -492
  110. /package/{node_modules/@context-vault/core/src/server → src}/tools/clear-context.js +0 -0
package/bin/cli.js CHANGED
@@ -34,7 +34,7 @@ const HOME = homedir();
34
34
 
35
35
  const pkg = JSON.parse(readFileSync(join(ROOT, "package.json"), "utf-8"));
36
36
  const VERSION = pkg.version;
37
- const SERVER_PATH = resolve(ROOT, "src", "server", "index.js");
37
+ const SERVER_PATH = resolve(ROOT, "src", "server.js");
38
38
 
39
39
  /** Detect if running as an npm-installed package (global or local) vs local dev clone */
40
40
  function isInstalledPackage() {
@@ -306,12 +306,14 @@ ${bold("Commands:")}
306
306
  ${cyan("restart")} Stop running MCP server processes (client auto-restarts)
307
307
  ${cyan("search")} Search vault entries from CLI
308
308
  ${cyan("save")} Save an entry to the vault from CLI
309
- ${cyan("import")} <path> Import entries from file or directory
310
- ${cyan("export")} Export vault to JSON or CSV
309
+ ${cyan("import")} <path> Import entries from file, directory, or .zip archive
310
+ ${cyan("export")} Export vault entries (JSON, CSV, or portable ZIP)
311
311
  ${cyan("ingest")} <url> Fetch URL and save as vault entry
312
312
  ${cyan("ingest-project")} <path> Scan project directory and register as project entity
313
313
  ${cyan("reindex")} Rebuild search index from knowledge files
314
314
  ${cyan("migrate-dirs")} [--dry-run] Rename plural vault dirs to singular (post-2.18.0)
315
+ ${cyan("archive")} Archive old ephemeral/event entries (use --dry-run to preview)
316
+ ${cyan("restore")} <id> Restore an archived entry back into the vault
315
317
  ${cyan("prune")} Remove expired entries (use --dry-run to preview)
316
318
  ${cyan("update")} Check for and install updates
317
319
  ${cyan("uninstall")} Remove MCP configs and optionally data
@@ -372,6 +374,26 @@ async function runSetup() {
372
374
  } catch {}
373
375
 
374
376
  if (latestVersion === VERSION) {
377
+ // Even when "up to date", ensure the launcher points to a valid server
378
+ const dataDir = join(HOME, ".context-mcp");
379
+ const launcherPath = join(dataDir, "server.mjs");
380
+ let launcherOk = false;
381
+ if (existsSync(launcherPath)) {
382
+ const content = readFileSync(launcherPath, "utf-8");
383
+ const m = content.match(/import "(.+?)"/);
384
+ if (m && existsSync(m[1])) launcherOk = true;
385
+ }
386
+ if (!launcherOk && !isNpx()) {
387
+ mkdirSync(dataDir, { recursive: true });
388
+ writeFileSync(launcherPath, `import "${SERVER_PATH}";\n`);
389
+ console.log(
390
+ green(` ✓ context-vault v${VERSION} is up to date`) +
391
+ dim(` (vault: ${existingVault})`),
392
+ );
393
+ console.log(dim(` ↳ Repaired server launcher → ${SERVER_PATH}`));
394
+ console.log();
395
+ return;
396
+ }
375
397
  console.log(
376
398
  green(` ✓ context-vault v${VERSION} is up to date`) +
377
399
  dim(` (vault: ${existingVault})`),
@@ -799,7 +821,7 @@ async function runSetup() {
799
821
  }, 100);
800
822
 
801
823
  try {
802
- const { embed } = await import("@context-vault/core/index/embed");
824
+ const { embed } = await import("@context-vault/core/embed");
803
825
  let timeoutHandle;
804
826
  const timeout = new Promise((_, reject) => {
805
827
  timeoutHandle = setTimeout(
@@ -1034,7 +1056,7 @@ async function runSetup() {
1034
1056
  // Verify DB is accessible
1035
1057
  let dbAccessible = false;
1036
1058
  try {
1037
- const { initDatabase } = await import("@context-vault/core/index/db");
1059
+ const { initDatabase } = await import("@context-vault/core/db");
1038
1060
  const db = await initDatabase(vaultConfig.dbPath);
1039
1061
  db.prepare("SELECT 1").get();
1040
1062
  db.close();
@@ -1577,7 +1599,7 @@ async function runSwitch() {
1577
1599
  if (target === "local") {
1578
1600
  const launcherPath = join(dataDir, "server.mjs");
1579
1601
  if (!existsSync(launcherPath)) {
1580
- const serverAbs = resolve(ROOT, "src", "server", "index.js");
1602
+ const serverAbs = resolve(ROOT, "src", "server.js");
1581
1603
  mkdirSync(dataDir, { recursive: true });
1582
1604
  writeFileSync(launcherPath, `import "${serverAbs}";\n`);
1583
1605
  }
@@ -1673,10 +1695,10 @@ async function runSwitch() {
1673
1695
  async function runReindex() {
1674
1696
  console.log(dim("Loading vault..."));
1675
1697
 
1676
- const { resolveConfig } = await import("@context-vault/core/core/config");
1698
+ const { resolveConfig } = await import("@context-vault/core/config");
1677
1699
  const { initDatabase, prepareStatements, insertVec, deleteVec } =
1678
- await import("@context-vault/core/index/db");
1679
- const { embed } = await import("@context-vault/core/index/embed");
1700
+ await import("@context-vault/core/db");
1701
+ const { embed } = await import("@context-vault/core/embed");
1680
1702
  const { reindex } = await import("@context-vault/core/index");
1681
1703
 
1682
1704
  const config = resolveConfig();
@@ -1715,7 +1737,7 @@ async function runMigrateDirs() {
1715
1737
  let vaultDir = positional;
1716
1738
 
1717
1739
  if (!vaultDir) {
1718
- const { resolveConfig } = await import("@context-vault/core/core/config");
1740
+ const { resolveConfig } = await import("@context-vault/core/config");
1719
1741
  const config = resolveConfig();
1720
1742
  if (!config.vaultDirExists) {
1721
1743
  console.error(red(`Vault directory not found: ${config.vaultDir}`));
@@ -1731,7 +1753,7 @@ async function runMigrateDirs() {
1731
1753
  }
1732
1754
 
1733
1755
  const { planMigration, executeMigration } =
1734
- await import("@context-vault/core/core/migrate-dirs");
1756
+ await import("@context-vault/core/migrate-dirs");
1735
1757
 
1736
1758
  const ops = planMigration(vaultDir);
1737
1759
 
@@ -1784,9 +1806,9 @@ async function runMigrateDirs() {
1784
1806
  async function runPrune() {
1785
1807
  const dryRun = flags.has("--dry-run");
1786
1808
 
1787
- const { resolveConfig } = await import("@context-vault/core/core/config");
1809
+ const { resolveConfig } = await import("@context-vault/core/config");
1788
1810
  const { initDatabase, prepareStatements, insertVec, deleteVec } =
1789
- await import("@context-vault/core/index/db");
1811
+ await import("@context-vault/core/db");
1790
1812
  const { pruneExpired } = await import("@context-vault/core/index");
1791
1813
 
1792
1814
  const config = resolveConfig();
@@ -1844,12 +1866,169 @@ async function runPrune() {
1844
1866
  }
1845
1867
  }
1846
1868
 
1869
+ async function runArchive() {
1870
+ const dryRun = flags.has("--dry-run");
1871
+
1872
+ const { resolveConfig } = await import("@context-vault/core/config");
1873
+ const { initDatabase, prepareStatements, insertVec, deleteVec } =
1874
+ await import("@context-vault/core/db");
1875
+ const { findArchiveCandidates, archiveEntries } =
1876
+ await import("@context-vault/core/archive");
1877
+
1878
+ const config = resolveConfig();
1879
+ if (!config.vaultDirExists) {
1880
+ console.error(red(`Vault directory not found: ${config.vaultDir}`));
1881
+ console.error("Run " + cyan("context-vault setup") + " to configure.");
1882
+ process.exit(1);
1883
+ }
1884
+
1885
+ const db = await initDatabase(config.dbPath);
1886
+
1887
+ if (dryRun) {
1888
+ const ctx = {
1889
+ db,
1890
+ config,
1891
+ stmts: prepareStatements(db),
1892
+ embed: async () => null,
1893
+ insertVec: () => {},
1894
+ deleteVec: () => {},
1895
+ };
1896
+ const candidates = findArchiveCandidates(ctx);
1897
+ db.close();
1898
+
1899
+ if (candidates.length === 0) {
1900
+ console.log(green(" No entries eligible for archiving."));
1901
+ const lifecycle = config.lifecycle || {};
1902
+ console.log(dim("\n Retention windows:"));
1903
+ for (const [tier, rules] of Object.entries(lifecycle)) {
1904
+ if (rules?.archiveAfterDays) {
1905
+ console.log(dim(` ${tier}: archive after ${rules.archiveAfterDays} days`));
1906
+ }
1907
+ }
1908
+ return;
1909
+ }
1910
+
1911
+ console.log(
1912
+ `\n ${bold(String(candidates.length))} ${candidates.length === 1 ? "entry" : "entries"} eligible for archiving:\n`,
1913
+ );
1914
+ for (const e of candidates) {
1915
+ const label = e.title ? `${e.kind}: ${e.title}` : `${e.kind} (${e.id})`;
1916
+ const age = e.updated_at || e.created_at;
1917
+ console.log(
1918
+ ` ${dim("-")} ${label} ${dim(`(tier=${e.tier}, last updated ${age})`)}`,
1919
+ );
1920
+ }
1921
+ console.log(dim("\n Dry run — no entries were archived."));
1922
+ console.log(dim(" Remove --dry-run to archive."));
1923
+ return;
1924
+ }
1925
+
1926
+ const stmts = prepareStatements(db);
1927
+ const ctx = {
1928
+ db,
1929
+ config,
1930
+ stmts,
1931
+ embed: async () => null,
1932
+ insertVec: (r, e) => insertVec(stmts, r, e),
1933
+ deleteVec: (r) => deleteVec(stmts, r),
1934
+ };
1935
+
1936
+ const result = await archiveEntries(ctx);
1937
+ db.close();
1938
+
1939
+ if (result.count === 0) {
1940
+ console.log(green(" No entries eligible for archiving."));
1941
+ } else {
1942
+ console.log(
1943
+ green(
1944
+ ` ✓ Archived ${result.count} ${result.count === 1 ? "entry" : "entries"} to _archive/`,
1945
+ ),
1946
+ );
1947
+ console.log(
1948
+ dim(` Files moved to: ${join(config.vaultDir, "_archive")}`),
1949
+ );
1950
+ console.log(
1951
+ dim(" Restore with: context-vault restore <id>"),
1952
+ );
1953
+ }
1954
+ }
1955
+
1956
+ async function runRestore() {
1957
+ const entryId = args[1];
1958
+
1959
+ if (!entryId || entryId.startsWith("--")) {
1960
+ const { resolveConfig } = await import("@context-vault/core/config");
1961
+ const { listArchivedEntries } =
1962
+ await import("@context-vault/core/archive");
1963
+
1964
+ const config = resolveConfig();
1965
+
1966
+ console.log(`\n ${bold("context-vault restore")} <id>\n`);
1967
+ console.log(` Restore an archived entry back into the active vault.\n`);
1968
+
1969
+ if (config.vaultDirExists) {
1970
+ const entries = listArchivedEntries(config.vaultDir);
1971
+ if (entries.length > 0) {
1972
+ console.log(` ${bold("Archived entries")} (${entries.length}):\n`);
1973
+ for (const e of entries.slice(0, 20)) {
1974
+ const label = e.title
1975
+ ? `${e.kind}: ${e.title.slice(0, 60)}`
1976
+ : `${e.kind} (${e.id})`;
1977
+ console.log(` ${dim(e.id || "?")} ${label}`);
1978
+ }
1979
+ if (entries.length > 20) {
1980
+ console.log(dim(`\n ... and ${entries.length - 20} more`));
1981
+ }
1982
+ } else {
1983
+ console.log(dim(" No archived entries found."));
1984
+ }
1985
+ }
1986
+ console.log();
1987
+ return;
1988
+ }
1989
+
1990
+ const { resolveConfig } = await import("@context-vault/core/config");
1991
+ const { initDatabase, prepareStatements, insertVec, deleteVec } =
1992
+ await import("@context-vault/core/db");
1993
+ const { embed } = await import("@context-vault/core/embed");
1994
+ const { restoreEntry } = await import("@context-vault/core/archive");
1995
+
1996
+ const config = resolveConfig();
1997
+ if (!config.vaultDirExists) {
1998
+ console.error(red(`Vault directory not found: ${config.vaultDir}`));
1999
+ console.error("Run " + cyan("context-vault setup") + " to configure.");
2000
+ process.exit(1);
2001
+ }
2002
+
2003
+ const db = await initDatabase(config.dbPath);
2004
+ const stmts = prepareStatements(db);
2005
+ const ctx = {
2006
+ db,
2007
+ config,
2008
+ stmts,
2009
+ embed,
2010
+ insertVec: (r, e) => insertVec(stmts, r, e),
2011
+ deleteVec: (r) => deleteVec(stmts, r),
2012
+ };
2013
+
2014
+ const result = await restoreEntry(ctx, entryId);
2015
+ db.close();
2016
+
2017
+ if (result.restored) {
2018
+ console.log(green(` ✓ Restored ${result.kind} entry: ${result.id}`));
2019
+ console.log(dim(` File: ${result.filePath}`));
2020
+ } else {
2021
+ console.error(red(` ✗ ${result.reason}`));
2022
+ process.exit(1);
2023
+ }
2024
+ }
2025
+
1847
2026
  async function runStatus() {
1848
- const { resolveConfig } = await import("@context-vault/core/core/config");
1849
- const { initDatabase } = await import("@context-vault/core/index/db");
1850
- const { gatherVaultStatus } = await import("@context-vault/core/core/status");
2027
+ const { resolveConfig } = await import("@context-vault/core/config");
2028
+ const { initDatabase } = await import("@context-vault/core/db");
2029
+ const { gatherVaultStatus } = await import("../src/status.js");
1851
2030
  const { errorLogPath, errorLogCount } =
1852
- await import("@context-vault/core/core/error-log");
2031
+ await import("../src/error-log.js");
1853
2032
 
1854
2033
  const config = resolveConfig();
1855
2034
 
@@ -1938,6 +2117,15 @@ async function runStatus() {
1938
2117
  }
1939
2118
  }
1940
2119
 
2120
+ if (status.archivedCount > 0) {
2121
+ console.log();
2122
+ console.log(
2123
+ dim(
2124
+ ` ${status.archivedCount} archived ${status.archivedCount === 1 ? "entry" : "entries"} in _archive/ (excluded from search)`,
2125
+ ),
2126
+ );
2127
+ }
2128
+
1941
2129
  if (status.stalePaths) {
1942
2130
  console.log();
1943
2131
  console.log(yellow(" Stale paths detected in DB."));
@@ -2129,7 +2317,7 @@ async function runMigrate() {
2129
2317
  return;
2130
2318
  }
2131
2319
 
2132
- const { resolveConfig } = await import("@context-vault/core/core/config");
2320
+ const { resolveConfig } = await import("@context-vault/core/config");
2133
2321
  const config = resolveConfig();
2134
2322
 
2135
2323
  if (direction === "to-hosted") {
@@ -2183,20 +2371,33 @@ async function runImport() {
2183
2371
  const target = args[1];
2184
2372
  if (!target) {
2185
2373
  console.log(`\n ${bold("context-vault import")} <path>\n`);
2186
- console.log(` Import entries from a file or directory.\n`);
2187
- console.log(` Supported formats: .md, .csv, .tsv, .json, .txt\n`);
2374
+ console.log(` Import entries from a file, directory, or portable archive.\n`);
2375
+ console.log(` Supported formats: .md, .csv, .tsv, .json, .txt, .zip\n`);
2188
2376
  console.log(` Options:`);
2189
2377
  console.log(` --kind <kind> Default kind (default: insight)`);
2190
2378
  console.log(` --source <src> Default source (default: cli-import)`);
2191
2379
  console.log(` --dry-run Show parsed entries without importing`);
2380
+ console.log(` --vault <path> Target vault directory (default: configured vault)`);
2192
2381
  console.log();
2193
2382
  return;
2194
2383
  }
2195
2384
 
2196
- const { resolveConfig } = await import("@context-vault/core/core/config");
2385
+ const dryRun = flags.has("--dry-run");
2386
+ const targetPath = resolve(target);
2387
+
2388
+ if (!existsSync(targetPath)) {
2389
+ console.error(red(` Path not found: ${targetPath}`));
2390
+ process.exit(1);
2391
+ }
2392
+
2393
+ if (targetPath.endsWith(".zip")) {
2394
+ return runImportZip(targetPath, dryRun);
2395
+ }
2396
+
2397
+ const { resolveConfig } = await import("@context-vault/core/config");
2197
2398
  const { initDatabase, prepareStatements, insertVec, deleteVec } =
2198
- await import("@context-vault/core/index/db");
2199
- const { embed } = await import("@context-vault/core/index/embed");
2399
+ await import("@context-vault/core/db");
2400
+ const { embed } = await import("@context-vault/core/embed");
2200
2401
  const { parseFile, parseDirectory } =
2201
2402
  await import("@context-vault/core/capture/importers");
2202
2403
  const { importEntries } =
@@ -2205,13 +2406,6 @@ async function runImport() {
2205
2406
 
2206
2407
  const kind = getFlag("--kind") || undefined;
2207
2408
  const source = getFlag("--source") || "cli-import";
2208
- const dryRun = flags.has("--dry-run");
2209
-
2210
- const targetPath = resolve(target);
2211
- if (!existsSync(targetPath)) {
2212
- console.error(red(` Path not found: ${targetPath}`));
2213
- process.exit(1);
2214
- }
2215
2409
 
2216
2410
  const stat = statSync(targetPath);
2217
2411
  let entries;
@@ -2282,17 +2476,215 @@ async function runImport() {
2282
2476
  console.log();
2283
2477
  }
2284
2478
 
2479
+ async function runImportZip(zipPath, dryRun) {
2480
+ const AdmZip = (await import("adm-zip")).default;
2481
+ const { resolveConfig } = await import("@context-vault/core/config");
2482
+ const { initDatabase, prepareStatements, insertVec, deleteVec } =
2483
+ await import("@context-vault/core/db");
2484
+ const { embed } = await import("@context-vault/core/embed");
2485
+ const { indexEntry } = await import("@context-vault/core/index");
2486
+ const { parseFrontmatter } = await import("@context-vault/core/frontmatter");
2487
+ const { categoryDirFor } = await import("@context-vault/core/categories");
2488
+ const { mkdirSync, writeFileSync, existsSync: existsFn } = await import("node:fs");
2489
+ const { join: joinPath, basename: baseName } = await import("node:path");
2490
+
2491
+ let zip;
2492
+ try {
2493
+ zip = new AdmZip(zipPath);
2494
+ } catch (e) {
2495
+ console.error(red(`\n Failed to open archive: ${e.message}\n`));
2496
+ process.exit(1);
2497
+ }
2498
+
2499
+ const manifestEntry = zip.getEntry("manifest.json");
2500
+ if (!manifestEntry) {
2501
+ console.error(red("\n Invalid archive: missing manifest.json\n"));
2502
+ process.exit(1);
2503
+ }
2504
+
2505
+ let manifest;
2506
+ try {
2507
+ manifest = JSON.parse(zip.readAsText("manifest.json"));
2508
+ } catch {
2509
+ console.error(red("\n Invalid archive: corrupt manifest.json\n"));
2510
+ process.exit(1);
2511
+ }
2512
+
2513
+ const indexEntry_ = zip.getEntry("index.json");
2514
+ if (!indexEntry_) {
2515
+ console.error(red("\n Invalid archive: missing index.json\n"));
2516
+ process.exit(1);
2517
+ }
2518
+
2519
+ let index;
2520
+ try {
2521
+ index = JSON.parse(zip.readAsText("index.json"));
2522
+ } catch {
2523
+ console.error(red("\n Invalid archive: corrupt index.json\n"));
2524
+ process.exit(1);
2525
+ }
2526
+
2527
+ const entries = index.entries || [];
2528
+ if (entries.length === 0) {
2529
+ console.log(yellow("\n Archive contains no entries.\n"));
2530
+ return;
2531
+ }
2532
+
2533
+ console.log(`\n ${bold("◇ context-vault import")} ${dim(baseName(zipPath))}`);
2534
+ console.log(dim(` Archive: v${manifest.version} · ${manifest.entry_count} entries · ${manifest.context_vault_version || "?"}`));
2535
+
2536
+ const kindCounts = {};
2537
+ for (const e of entries) {
2538
+ kindCounts[e.kind] = (kindCounts[e.kind] || 0) + 1;
2539
+ }
2540
+ console.log();
2541
+ for (const [k, count] of Object.entries(kindCounts).sort((a, b) => b[1] - a[1])) {
2542
+ console.log(` ${k}: ${count}`);
2543
+ }
2544
+
2545
+ const vaultDirOverride = getFlag("--vault");
2546
+ const config = (await import("@context-vault/core/config")).resolveConfig();
2547
+ const targetVaultDir = vaultDirOverride ? resolve(vaultDirOverride) : config.vaultDir;
2548
+
2549
+ if (!existsFn(targetVaultDir)) {
2550
+ console.error(red(`\n Vault directory not found: ${targetVaultDir}`));
2551
+ console.error(` Run ${cyan("context-vault setup")} to configure.`);
2552
+ process.exit(1);
2553
+ }
2554
+
2555
+ const db = await initDatabase(config.dbPath);
2556
+ const stmts = prepareStatements(db);
2557
+ const ctx = {
2558
+ db,
2559
+ config: { ...config, vaultDir: targetVaultDir },
2560
+ stmts,
2561
+ embed,
2562
+ insertVec: (r, e) => insertVec(stmts, r, e),
2563
+ deleteVec: (r) => deleteVec(stmts, r),
2564
+ };
2565
+
2566
+ const existingIds = new Set();
2567
+ const allIds = db.prepare("SELECT id FROM vault").all();
2568
+ for (const row of allIds) existingIds.add(row.id);
2569
+
2570
+ let imported = 0;
2571
+ let skippedDuplicate = 0;
2572
+ let skippedMissing = 0;
2573
+ let failed = 0;
2574
+ const errors = [];
2575
+
2576
+ if (dryRun) {
2577
+ for (let i = 0; i < Math.min(entries.length, 25); i++) {
2578
+ const e = entries[i];
2579
+ const isDuplicate = existingIds.has(e.id);
2580
+ const tagStr = e.tags?.length ? ` ${dim(`[${e.tags.join(", ")}]`)}` : "";
2581
+ const statusIcon = isDuplicate ? yellow("~") : green("+");
2582
+ const statusText = isDuplicate ? dim(" (duplicate, would skip)") : "";
2583
+ console.log(`\n ${statusIcon} ${dim(`[${i + 1}]`)} ${e.kind} — ${e.title || e.id}${tagStr}${statusText}`);
2584
+ }
2585
+ if (entries.length > 25) {
2586
+ console.log(dim(`\n ... and ${entries.length - 25} more`));
2587
+ }
2588
+ const wouldSkip = entries.filter((e) => existingIds.has(e.id)).length;
2589
+ console.log(`\n ${dim(`Would import ${entries.length - wouldSkip}, skip ${wouldSkip} duplicates.`)}`);
2590
+ console.log(dim(" Dry run — no entries were imported.\n"));
2591
+ db.close();
2592
+ return;
2593
+ }
2594
+
2595
+ for (let i = 0; i < entries.length; i++) {
2596
+ const entryMeta = entries[i];
2597
+ process.stdout.write(`\r Importing... ${i + 1}/${entries.length}`);
2598
+
2599
+ if (existingIds.has(entryMeta.id)) {
2600
+ skippedDuplicate++;
2601
+ continue;
2602
+ }
2603
+
2604
+ const zipEntry = zip.getEntry(entryMeta.file);
2605
+ if (!zipEntry) {
2606
+ skippedMissing++;
2607
+ continue;
2608
+ }
2609
+
2610
+ const mdContent = zip.readAsText(entryMeta.file);
2611
+ const { meta: fmMeta, body: rawBody } = parseFrontmatter(mdContent);
2612
+
2613
+ const kind = entryMeta.kind || fmMeta.kind || "insight";
2614
+ const categoryDir = categoryDirFor(kind);
2615
+ const targetDir = joinPath(targetVaultDir, categoryDir, kind);
2616
+
2617
+ try {
2618
+ mkdirSync(targetDir, { recursive: true });
2619
+
2620
+ const fileName = baseName(entryMeta.file);
2621
+ const filePath = joinPath(targetDir, fileName);
2622
+ writeFileSync(filePath, mdContent);
2623
+
2624
+ const id = fmMeta.id || entryMeta.id;
2625
+ const tags = Array.isArray(fmMeta.tags) ? fmMeta.tags : entryMeta.tags || [];
2626
+ const title = fmMeta.title || entryMeta.title || null;
2627
+ const source = fmMeta.source || entryMeta.source || "archive-import";
2628
+ const identity_key = fmMeta.identity_key || entryMeta.identity_key || null;
2629
+ const expires_at = fmMeta.expires_at || entryMeta.expires_at || null;
2630
+ const createdAt = fmMeta.created || entryMeta.created_at || new Date().toISOString();
2631
+
2632
+ await indexEntry(ctx, {
2633
+ id,
2634
+ kind,
2635
+ category: entryMeta.category || undefined,
2636
+ title,
2637
+ body: rawBody,
2638
+ meta: null,
2639
+ tags,
2640
+ source,
2641
+ filePath,
2642
+ createdAt,
2643
+ identity_key,
2644
+ expires_at,
2645
+ });
2646
+
2647
+ imported++;
2648
+ } catch (e) {
2649
+ failed++;
2650
+ errors.push({ id: entryMeta.id, error: e.message });
2651
+ }
2652
+ }
2653
+
2654
+ db.close();
2655
+
2656
+ console.log(`\r ${green("✓")} Import complete `);
2657
+ console.log(` ${green("+")} ${imported} imported`);
2658
+ if (skippedDuplicate > 0) {
2659
+ console.log(` ${dim("~")} ${skippedDuplicate} skipped (already exist)`);
2660
+ }
2661
+ if (skippedMissing > 0) {
2662
+ console.log(` ${yellow("!")} ${skippedMissing} skipped (file missing in archive)`);
2663
+ }
2664
+ if (failed > 0) {
2665
+ console.log(` ${red("x")} ${failed} failed`);
2666
+ for (const e of errors.slice(0, 5)) {
2667
+ console.log(` ${dim(e.error)}`);
2668
+ }
2669
+ }
2670
+ console.log();
2671
+ }
2672
+
2285
2673
  async function runExport() {
2286
2674
  const format = getFlag("--format") || "json";
2287
- const output = getFlag("--output");
2675
+ const output = getFlag("--output") || getFlag("-o");
2288
2676
  const rawPageSize = getFlag("--page-size");
2289
2677
  const pageSize = rawPageSize
2290
2678
  ? Math.max(1, parseInt(rawPageSize, 10) || 100)
2291
2679
  : null;
2292
2680
 
2293
- const { resolveConfig } = await import("@context-vault/core/core/config");
2681
+ if (format === "zip") {
2682
+ return runExportZip();
2683
+ }
2684
+
2685
+ const { resolveConfig } = await import("@context-vault/core/config");
2294
2686
  const { initDatabase, prepareStatements } =
2295
- await import("@context-vault/core/index/db");
2687
+ await import("@context-vault/core/db");
2296
2688
  const { writeFileSync } = await import("node:fs");
2297
2689
 
2298
2690
  const config = resolveConfig();
@@ -2308,7 +2700,6 @@ async function runExport() {
2308
2700
 
2309
2701
  let entries;
2310
2702
  if (pageSize) {
2311
- // Paginated: fetch in chunks to avoid loading everything into memory
2312
2703
  entries = [];
2313
2704
  let offset = 0;
2314
2705
  const stmt = db.prepare(
@@ -2378,6 +2769,188 @@ async function runExport() {
2378
2769
  }
2379
2770
  }
2380
2771
 
2772
+ async function runExportZip() {
2773
+ const output = getFlag("--output") || getFlag("-o");
2774
+ const dryRun = flags.has("--dry-run");
2775
+ const tagsRaw = getFlag("--tags");
2776
+ const kindRaw = getFlag("--kind");
2777
+ const since = getFlag("--since");
2778
+ const until = getFlag("--until");
2779
+ const exportAll = flags.has("--all");
2780
+
2781
+ const tagsFilter = tagsRaw
2782
+ ? tagsRaw.split(",").map((t) => t.trim()).filter(Boolean)
2783
+ : null;
2784
+ const kindFilter = kindRaw
2785
+ ? kindRaw.split(",").map((k) => k.trim()).filter(Boolean)
2786
+ : null;
2787
+
2788
+ if (!exportAll && !tagsFilter && !kindFilter && !since && !until) {
2789
+ console.log(`\n ${bold("context-vault export --format zip")} [options]\n`);
2790
+ console.log(` Export vault entries as a portable ZIP archive.\n`);
2791
+ console.log(` ${bold("Filters (at least one required, or use --all):")}`);
2792
+ console.log(` --tags <t1,t2> Filter by tags (comma-separated)`);
2793
+ console.log(` --kind <k1,k2> Filter by kind (comma-separated)`);
2794
+ console.log(` --since <YYYY-MM-DD> Entries created on or after date`);
2795
+ console.log(` --until <YYYY-MM-DD> Entries created on or before date`);
2796
+ console.log(` --all Export all entries\n`);
2797
+ console.log(` ${bold("Options:")}`);
2798
+ console.log(` --output, -o <path> Output file path`);
2799
+ console.log(` --dry-run Show what would be exported\n`);
2800
+ console.log(` ${bold("Examples:")}`);
2801
+ console.log(` context-vault export --tags stormfors --format zip -o stormfors.zip`);
2802
+ console.log(` context-vault export --kind decision,pattern --format zip`);
2803
+ console.log(` context-vault export --since 2026-01-01 --until 2026-02-28 --format zip`);
2804
+ console.log(` context-vault export --all --format zip --dry-run\n`);
2805
+ return;
2806
+ }
2807
+
2808
+ const { resolveConfig } = await import("@context-vault/core/config");
2809
+ const { initDatabase } = await import("@context-vault/core/db");
2810
+ const { readFileSync: readFs, existsSync: existsFn } = await import("node:fs");
2811
+ const { basename } = await import("node:path");
2812
+
2813
+ const config = resolveConfig();
2814
+ if (!config.vaultDirExists) {
2815
+ console.error(red(` Vault directory not found: ${config.vaultDir}`));
2816
+ process.exit(1);
2817
+ }
2818
+
2819
+ const db = await initDatabase(config.dbPath);
2820
+
2821
+ const conditions = ["(expires_at IS NULL OR expires_at > datetime('now'))"];
2822
+ const params = [];
2823
+
2824
+ if (tagsFilter) {
2825
+ const tagClauses = tagsFilter.map(() =>
2826
+ "EXISTS (SELECT 1 FROM json_each(vault.tags) WHERE json_each.value = ?)"
2827
+ );
2828
+ conditions.push(`(${tagClauses.join(" OR ")})`);
2829
+ params.push(...tagsFilter);
2830
+ }
2831
+
2832
+ if (kindFilter) {
2833
+ const placeholders = kindFilter.map(() => "?").join(", ");
2834
+ conditions.push(`kind IN (${placeholders})`);
2835
+ params.push(...kindFilter);
2836
+ }
2837
+
2838
+ if (since) {
2839
+ conditions.push("created_at >= ?");
2840
+ params.push(since.includes("T") ? since : `${since}T00:00:00.000Z`);
2841
+ }
2842
+
2843
+ if (until) {
2844
+ conditions.push("created_at <= ?");
2845
+ params.push(until.includes("T") ? until : `${until}T23:59:59.999Z`);
2846
+ }
2847
+
2848
+ const sql = `SELECT * FROM vault WHERE ${conditions.join(" AND ")} ORDER BY created_at DESC`;
2849
+ const rows = db.prepare(sql).all(...params);
2850
+ db.close();
2851
+
2852
+ if (rows.length === 0) {
2853
+ console.log(yellow("\n No entries match the given filters.\n"));
2854
+ return;
2855
+ }
2856
+
2857
+ const kindCounts = {};
2858
+ for (const row of rows) {
2859
+ kindCounts[row.kind] = (kindCounts[row.kind] || 0) + 1;
2860
+ }
2861
+
2862
+ console.log(`\n ${bold(String(rows.length))} entries match filters:\n`);
2863
+ for (const [k, count] of Object.entries(kindCounts).sort((a, b) => b[1] - a[1])) {
2864
+ console.log(` ${k}: ${count}`);
2865
+ }
2866
+
2867
+ const earliest = rows[rows.length - 1]?.created_at;
2868
+ const latest = rows[0]?.created_at;
2869
+ console.log(dim(`\n Date range: ${earliest?.slice(0, 10) || "?"} → ${latest?.slice(0, 10) || "?"}`));
2870
+
2871
+ if (dryRun) {
2872
+ console.log();
2873
+ for (let i = 0; i < Math.min(rows.length, 25); i++) {
2874
+ const r = rows[i];
2875
+ const tags = safeJsonParse(r.tags, []);
2876
+ const tagStr = tags.length ? ` ${dim(`[${tags.join(", ")}]`)}` : "";
2877
+ console.log(` ${dim(`[${i + 1}]`)} ${r.kind} — ${r.title || (r.body || "").slice(0, 60)}${tagStr}`);
2878
+ }
2879
+ if (rows.length > 25) {
2880
+ console.log(dim(` ... and ${rows.length - 25} more`));
2881
+ }
2882
+ console.log(dim("\n Dry run — no archive created.\n"));
2883
+ return;
2884
+ }
2885
+
2886
+ const AdmZip = (await import("adm-zip")).default;
2887
+ const zip = new AdmZip();
2888
+
2889
+ const indexEntries = [];
2890
+ let filesSkipped = 0;
2891
+
2892
+ for (const row of rows) {
2893
+ const entryPath = `entries/${row.kind}/${basename(row.file_path || `${row.id}.md`)}`;
2894
+
2895
+ let fileContent = null;
2896
+ if (row.file_path && existsFn(row.file_path)) {
2897
+ fileContent = readFs(row.file_path);
2898
+ }
2899
+
2900
+ if (!fileContent) {
2901
+ filesSkipped++;
2902
+ continue;
2903
+ }
2904
+
2905
+ zip.addFile(entryPath, fileContent);
2906
+
2907
+ indexEntries.push({
2908
+ id: row.id,
2909
+ kind: row.kind,
2910
+ category: row.category,
2911
+ title: row.title || null,
2912
+ tags: safeJsonParse(row.tags, []),
2913
+ source: row.source || null,
2914
+ identity_key: row.identity_key || null,
2915
+ expires_at: row.expires_at || null,
2916
+ created_at: row.created_at,
2917
+ file: entryPath,
2918
+ });
2919
+ }
2920
+
2921
+ const manifest = {
2922
+ version: 1,
2923
+ created_at: new Date().toISOString(),
2924
+ context_vault_version: VERSION,
2925
+ entry_count: indexEntries.length,
2926
+ date_range: { earliest, latest },
2927
+ filters: {
2928
+ tags: tagsFilter || null,
2929
+ kind: kindFilter || null,
2930
+ since: since || null,
2931
+ until: until || null,
2932
+ all: exportAll || false,
2933
+ },
2934
+ };
2935
+
2936
+ zip.addFile("manifest.json", Buffer.from(JSON.stringify(manifest, null, 2)));
2937
+ zip.addFile("index.json", Buffer.from(JSON.stringify({ entries: indexEntries }, null, 2)));
2938
+
2939
+ const today = new Date().toISOString().slice(0, 10);
2940
+ const defaultName = tagsFilter
2941
+ ? `vault-${tagsFilter[0]}-${today}.zip`
2942
+ : `vault-export-${today}.zip`;
2943
+ const outputPath = resolve(output || defaultName);
2944
+
2945
+ zip.writeZip(outputPath);
2946
+
2947
+ console.log(`\n ${green("✓")} Exported ${indexEntries.length} entries to ${outputPath}`);
2948
+ if (filesSkipped > 0) {
2949
+ console.log(yellow(` ⚠ ${filesSkipped} entries skipped (file not found on disk)`));
2950
+ }
2951
+ console.log();
2952
+ }
2953
+
2381
2954
  function safeJsonParse(str, fallback) {
2382
2955
  if (!str) return fallback;
2383
2956
  try {
@@ -2446,10 +3019,10 @@ async function runIngest() {
2446
3019
  return;
2447
3020
  }
2448
3021
 
2449
- const { resolveConfig } = await import("@context-vault/core/core/config");
3022
+ const { resolveConfig } = await import("@context-vault/core/config");
2450
3023
  const { initDatabase, prepareStatements, insertVec, deleteVec } =
2451
- await import("@context-vault/core/index/db");
2452
- const { embed } = await import("@context-vault/core/index/embed");
3024
+ await import("@context-vault/core/db");
3025
+ const { embed } = await import("@context-vault/core/embed");
2453
3026
  const { captureAndIndex } = await import("@context-vault/core/capture");
2454
3027
 
2455
3028
  const config = resolveConfig();
@@ -2513,10 +3086,10 @@ async function runIngestProject() {
2513
3086
 
2514
3087
  console.log(dim(` Scanning ${projectPath}...`));
2515
3088
 
2516
- const { resolveConfig } = await import("@context-vault/core/core/config");
3089
+ const { resolveConfig } = await import("@context-vault/core/config");
2517
3090
  const { initDatabase, prepareStatements, insertVec, deleteVec } =
2518
- await import("@context-vault/core/index/db");
2519
- const { embed } = await import("@context-vault/core/index/embed");
3091
+ await import("@context-vault/core/db");
3092
+ const { embed } = await import("@context-vault/core/embed");
2520
3093
  const { captureAndIndex } = await import("@context-vault/core/capture");
2521
3094
  const { existsSync: fsExists, readFileSync: fsRead } =
2522
3095
  await import("node:fs");
@@ -2727,21 +3300,21 @@ async function runRecall() {
2727
3300
 
2728
3301
  let db;
2729
3302
  try {
2730
- const { resolveConfig } = await import("@context-vault/core/core/config");
3303
+ const { resolveConfig } = await import("@context-vault/core/config");
2731
3304
  const config = resolveConfig();
2732
3305
 
2733
3306
  if (!config.vaultDirExists) return;
2734
3307
 
2735
3308
  const { initDatabase, prepareStatements } =
2736
- await import("@context-vault/core/index/db");
2737
- const { embed } = await import("@context-vault/core/index/embed");
3309
+ await import("@context-vault/core/db");
3310
+ const { embed } = await import("@context-vault/core/embed");
2738
3311
  const { hybridSearch } = await import("@context-vault/core/retrieve/index");
2739
3312
 
2740
3313
  db = await initDatabase(config.dbPath);
2741
3314
  const stmts = prepareStatements(db);
2742
3315
  const ctx = { db, config, stmts, embed };
2743
3316
 
2744
- const { categoryFor } = await import("@context-vault/core/core/categories");
3317
+ const { categoryFor } = await import("@context-vault/core/categories");
2745
3318
  const recall = config.recall;
2746
3319
 
2747
3320
  const results = await hybridSearch(ctx, query, {
@@ -2781,8 +3354,8 @@ async function runRecall() {
2781
3354
  }
2782
3355
 
2783
3356
  async function runFlush() {
2784
- const { resolveConfig } = await import("@context-vault/core/core/config");
2785
- const { initDatabase } = await import("@context-vault/core/index/db");
3357
+ const { resolveConfig } = await import("@context-vault/core/config");
3358
+ const { initDatabase } = await import("@context-vault/core/db");
2786
3359
 
2787
3360
  let db;
2788
3361
  try {
@@ -2828,12 +3401,12 @@ async function runSessionCapture() {
2828
3401
  }
2829
3402
  const { kind, title, body, tags, source } = payload;
2830
3403
  if (!kind || !body) return;
2831
- const { resolveConfig } = await import("@context-vault/core/core/config");
3404
+ const { resolveConfig } = await import("@context-vault/core/config");
2832
3405
  const config = resolveConfig();
2833
3406
  if (!config.vaultDirExists) return;
2834
3407
  const { initDatabase, prepareStatements, insertVec, deleteVec } =
2835
- await import("@context-vault/core/index/db");
2836
- const { embed } = await import("@context-vault/core/index/embed");
3408
+ await import("@context-vault/core/db");
3409
+ const { embed } = await import("@context-vault/core/embed");
2837
3410
  const { captureAndIndex } = await import("@context-vault/core/capture");
2838
3411
  db = await initDatabase(config.dbPath);
2839
3412
  const stmts = prepareStatements(db);
@@ -2912,7 +3485,7 @@ async function runSave() {
2912
3485
 
2913
3486
  let db;
2914
3487
  try {
2915
- const { resolveConfig } = await import("@context-vault/core/core/config");
3488
+ const { resolveConfig } = await import("@context-vault/core/config");
2916
3489
  const config = resolveConfig();
2917
3490
  if (!config.vaultDirExists) {
2918
3491
  console.error(
@@ -2921,8 +3494,8 @@ async function runSave() {
2921
3494
  process.exit(1);
2922
3495
  }
2923
3496
  const { initDatabase, prepareStatements, insertVec, deleteVec } =
2924
- await import("@context-vault/core/index/db");
2925
- const { embed } = await import("@context-vault/core/index/embed");
3497
+ await import("@context-vault/core/db");
3498
+ const { embed } = await import("@context-vault/core/embed");
2926
3499
  const { captureAndIndex } = await import("@context-vault/core/capture");
2927
3500
  db = await initDatabase(config.dbPath);
2928
3501
  const stmts = prepareStatements(db);
@@ -2996,7 +3569,7 @@ async function runSearch() {
2996
3569
 
2997
3570
  let db;
2998
3571
  try {
2999
- const { resolveConfig } = await import("@context-vault/core/core/config");
3572
+ const { resolveConfig } = await import("@context-vault/core/config");
3000
3573
  const config = resolveConfig();
3001
3574
  if (!config.vaultDirExists) {
3002
3575
  console.error(red("No vault found. Run: context-vault setup"));
@@ -3004,8 +3577,8 @@ async function runSearch() {
3004
3577
  }
3005
3578
 
3006
3579
  const { initDatabase, prepareStatements } =
3007
- await import("@context-vault/core/index/db");
3008
- const { embed } = await import("@context-vault/core/index/embed");
3580
+ await import("@context-vault/core/db");
3581
+ const { embed } = await import("@context-vault/core/embed");
3009
3582
  const { hybridSearch } = await import("@context-vault/core/retrieve/index");
3010
3583
 
3011
3584
  db = await initDatabase(config.dbPath);
@@ -3763,9 +4336,9 @@ ${bold("Commands:")}
3763
4336
  }
3764
4337
 
3765
4338
  async function runDoctor() {
3766
- const { resolveConfig } = await import("@context-vault/core/core/config");
4339
+ const { resolveConfig } = await import("@context-vault/core/config");
3767
4340
  const { errorLogPath, errorLogCount } =
3768
- await import("@context-vault/core/core/error-log");
4341
+ await import("../src/error-log.js");
3769
4342
 
3770
4343
  console.log();
3771
4344
  console.log(` ${bold("◇ context-vault doctor")} ${dim(`v${VERSION}`)}`);
@@ -3839,7 +4412,7 @@ async function runDoctor() {
3839
4412
  let db;
3840
4413
  if (existsSync(config.dbPath)) {
3841
4414
  try {
3842
- const { initDatabase } = await import("@context-vault/core/index/db");
4415
+ const { initDatabase } = await import("@context-vault/core/db");
3843
4416
  db = await initDatabase(config.dbPath);
3844
4417
  const schemaRow = db.prepare("PRAGMA user_version").get();
3845
4418
  const schemaVersion = schemaRow?.user_version ?? "unknown";
@@ -3861,7 +4434,7 @@ async function runDoctor() {
3861
4434
 
3862
4435
  // ── Embedding model ──────────────────────────────────────────────────
3863
4436
  try {
3864
- const { embed } = await import("@context-vault/core/index/embed");
4437
+ const { embed } = await import("@context-vault/core/embed");
3865
4438
  const vec = await embed("doctor check");
3866
4439
  if (vec && vec.length > 0) {
3867
4440
  console.log(
@@ -4227,9 +4800,9 @@ async function runDoctor() {
4227
4800
  }
4228
4801
 
4229
4802
  async function runHealth() {
4230
- const { resolveConfig } = await import("@context-vault/core/core/config");
4803
+ const { resolveConfig } = await import("@context-vault/core/config");
4231
4804
  const { initDatabase, testConnection } =
4232
- await import("@context-vault/core/index/db");
4805
+ await import("@context-vault/core/db");
4233
4806
 
4234
4807
  let config;
4235
4808
  let healthy = true;
@@ -4418,8 +4991,8 @@ async function runConsolidate() {
4418
4991
  const dryRun = flags.has("--dry-run");
4419
4992
  const tagArg = getFlag("--tag");
4420
4993
 
4421
- const { resolveConfig } = await import("@context-vault/core/core/config");
4422
- const { initDatabase } = await import("@context-vault/core/index/db");
4994
+ const { resolveConfig } = await import("@context-vault/core/config");
4995
+ const { initDatabase } = await import("@context-vault/core/db");
4423
4996
  const { findHotTags, findColdEntries } =
4424
4997
  await import("@context-vault/core/consolidation/index");
4425
4998
 
@@ -4538,7 +5111,7 @@ async function runConsolidate() {
4538
5111
  );
4539
5112
  console.log(
4540
5113
  dim(
4541
- ` To archive: use context-vault search --kind <kind> and review manually.`,
5114
+ ` To archive: run context-vault archive (or --dry-run to preview).`,
4542
5115
  ),
4543
5116
  );
4544
5117
  }
@@ -4548,7 +5121,7 @@ async function runConsolidate() {
4548
5121
  }
4549
5122
 
4550
5123
  async function runServe() {
4551
- await import("../src/server/index.js");
5124
+ await import("../src/server.js");
4552
5125
  }
4553
5126
 
4554
5127
  async function main() {
@@ -4633,6 +5206,12 @@ async function main() {
4633
5206
  case "migrate-dirs":
4634
5207
  await runMigrateDirs();
4635
5208
  break;
5209
+ case "archive":
5210
+ await runArchive();
5211
+ break;
5212
+ case "restore":
5213
+ await runRestore();
5214
+ break;
4636
5215
  case "prune":
4637
5216
  await runPrune();
4638
5217
  break;