@context-vault/core 2.17.1 → 3.0.3

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 (101) hide show
  1. package/dist/capture.d.ts +21 -0
  2. package/dist/capture.d.ts.map +1 -0
  3. package/dist/capture.js +269 -0
  4. package/dist/capture.js.map +1 -0
  5. package/dist/categories.d.ts +6 -0
  6. package/dist/categories.d.ts.map +1 -0
  7. package/dist/categories.js +50 -0
  8. package/dist/categories.js.map +1 -0
  9. package/dist/config.d.ts +4 -0
  10. package/dist/config.d.ts.map +1 -0
  11. package/dist/config.js +190 -0
  12. package/dist/config.js.map +1 -0
  13. package/dist/constants.d.ts +33 -0
  14. package/dist/constants.d.ts.map +1 -0
  15. package/dist/constants.js +23 -0
  16. package/dist/constants.js.map +1 -0
  17. package/dist/db.d.ts +13 -0
  18. package/dist/db.d.ts.map +1 -0
  19. package/dist/db.js +191 -0
  20. package/dist/db.js.map +1 -0
  21. package/dist/embed.d.ts +5 -0
  22. package/dist/embed.d.ts.map +1 -0
  23. package/dist/embed.js +78 -0
  24. package/dist/embed.js.map +1 -0
  25. package/dist/files.d.ts +13 -0
  26. package/dist/files.d.ts.map +1 -0
  27. package/dist/files.js +66 -0
  28. package/dist/files.js.map +1 -0
  29. package/dist/formatters.d.ts +8 -0
  30. package/dist/formatters.d.ts.map +1 -0
  31. package/dist/formatters.js +18 -0
  32. package/dist/formatters.js.map +1 -0
  33. package/dist/frontmatter.d.ts +12 -0
  34. package/dist/frontmatter.d.ts.map +1 -0
  35. package/dist/frontmatter.js +101 -0
  36. package/dist/frontmatter.js.map +1 -0
  37. package/dist/index.d.ts +10 -0
  38. package/dist/index.d.ts.map +1 -0
  39. package/dist/index.js +297 -0
  40. package/dist/index.js.map +1 -0
  41. package/dist/ingest-url.d.ts +20 -0
  42. package/dist/ingest-url.d.ts.map +1 -0
  43. package/dist/ingest-url.js +113 -0
  44. package/dist/ingest-url.js.map +1 -0
  45. package/dist/main.d.ts +14 -0
  46. package/dist/main.d.ts.map +1 -0
  47. package/dist/main.js +25 -0
  48. package/dist/main.js.map +1 -0
  49. package/dist/search.d.ts +18 -0
  50. package/dist/search.d.ts.map +1 -0
  51. package/dist/search.js +238 -0
  52. package/dist/search.js.map +1 -0
  53. package/dist/types.d.ts +176 -0
  54. package/dist/types.d.ts.map +1 -0
  55. package/dist/types.js +2 -0
  56. package/dist/types.js.map +1 -0
  57. package/package.json +66 -16
  58. package/src/capture.ts +308 -0
  59. package/src/categories.ts +54 -0
  60. package/src/{core/config.js → config.ts} +34 -33
  61. package/src/{constants.js → constants.ts} +6 -3
  62. package/src/db.ts +229 -0
  63. package/src/{index/embed.js → embed.ts} +10 -35
  64. package/src/{core/files.js → files.ts} +15 -20
  65. package/src/{capture/formatters.js → formatters.ts} +13 -11
  66. package/src/{core/frontmatter.js → frontmatter.ts} +26 -33
  67. package/src/index.ts +353 -0
  68. package/src/ingest-url.ts +99 -0
  69. package/src/main.ts +111 -0
  70. package/src/{retrieve/index.js → search.ts} +62 -150
  71. package/src/types.ts +166 -0
  72. package/src/capture/file-ops.js +0 -99
  73. package/src/capture/import-pipeline.js +0 -46
  74. package/src/capture/importers.js +0 -387
  75. package/src/capture/index.js +0 -250
  76. package/src/capture/ingest-url.js +0 -252
  77. package/src/consolidation/index.js +0 -112
  78. package/src/core/categories.js +0 -73
  79. package/src/core/error-log.js +0 -54
  80. package/src/core/linking.js +0 -161
  81. package/src/core/migrate-dirs.js +0 -196
  82. package/src/core/status.js +0 -350
  83. package/src/core/telemetry.js +0 -90
  84. package/src/core/temporal.js +0 -146
  85. package/src/index/db.js +0 -586
  86. package/src/index/index.js +0 -583
  87. package/src/index.js +0 -71
  88. package/src/server/helpers.js +0 -44
  89. package/src/server/tools/clear-context.js +0 -47
  90. package/src/server/tools/context-status.js +0 -182
  91. package/src/server/tools/create-snapshot.js +0 -200
  92. package/src/server/tools/delete-context.js +0 -60
  93. package/src/server/tools/get-context.js +0 -765
  94. package/src/server/tools/ingest-project.js +0 -244
  95. package/src/server/tools/ingest-url.js +0 -88
  96. package/src/server/tools/list-buckets.js +0 -116
  97. package/src/server/tools/list-context.js +0 -163
  98. package/src/server/tools/save-context.js +0 -632
  99. package/src/server/tools/session-start.js +0 -285
  100. package/src/server/tools.js +0 -172
  101. package/src/sync/sync.js +0 -235
package/src/capture.ts ADDED
@@ -0,0 +1,308 @@
1
+ import { existsSync, readFileSync, unlinkSync, writeFileSync, mkdirSync } from "node:fs";
2
+ import { resolve, relative } from "node:path";
3
+ import { ulid, slugify, kindToPath } from "./files.js";
4
+ import { categoryFor, defaultTierFor } from "./categories.js";
5
+ import { parseFrontmatter, formatFrontmatter } from "./frontmatter.js";
6
+ import { formatBody } from "./formatters.js";
7
+ import type { BaseCtx, CaptureInput, CaptureResult, IndexEntryInput } from "./types.js";
8
+ import { indexEntry } from "./index.js";
9
+
10
+ function safeFolderPath(vaultDir: string, kind: string, folder?: string | null): string {
11
+ const base = resolve(vaultDir, kindToPath(kind));
12
+ if (!folder) return base;
13
+ const resolved = resolve(base, folder);
14
+ const rel = relative(base, resolved);
15
+ if (rel.startsWith("..") || resolve(base, rel) !== resolved) {
16
+ throw new Error(`Folder path escapes vault: "${folder}"`);
17
+ }
18
+ return resolved;
19
+ }
20
+
21
+ function writeEntryFile(
22
+ vaultDir: string,
23
+ kind: string,
24
+ params: {
25
+ id: string;
26
+ title?: string | null;
27
+ body: string;
28
+ meta?: Record<string, unknown> | null;
29
+ tags?: string[] | null;
30
+ source?: string | null;
31
+ createdAt: string;
32
+ updatedAt: string;
33
+ folder?: string | null;
34
+ category: string;
35
+ identity_key?: string | null;
36
+ expires_at?: string | null;
37
+ supersedes?: string[] | null;
38
+ related_to?: string[] | null;
39
+ },
40
+ ): string {
41
+ const resolvedFolder = params.folder || (params.meta?.folder as string) || "";
42
+ const dir = safeFolderPath(vaultDir, kind, resolvedFolder);
43
+
44
+ try {
45
+ mkdirSync(dir, { recursive: true });
46
+ } catch (e) {
47
+ throw new Error(`Failed to create directory "${dir}": ${(e as Error).message}`);
48
+ }
49
+
50
+ const created = params.createdAt || new Date().toISOString();
51
+ const fmFields: Record<string, unknown> = { id: params.id };
52
+
53
+ if (params.meta) {
54
+ for (const [k, v] of Object.entries(params.meta)) {
55
+ if (k === "folder") continue;
56
+ if (v !== null && v !== undefined) fmFields[k] = v;
57
+ }
58
+ }
59
+
60
+ if (params.identity_key) fmFields.identity_key = params.identity_key;
61
+ if (params.expires_at) fmFields.expires_at = params.expires_at;
62
+ if (params.supersedes?.length) fmFields.supersedes = params.supersedes;
63
+ if (params.related_to?.length) fmFields.related_to = params.related_to;
64
+ fmFields.tags = params.tags || [];
65
+ fmFields.source = params.source || "claude-code";
66
+ fmFields.created = created;
67
+ if (params.updatedAt && params.updatedAt !== created)
68
+ fmFields.updated = params.updatedAt;
69
+
70
+ const mdBody = formatBody(kind, {
71
+ title: params.title || undefined,
72
+ body: params.body,
73
+ meta: params.meta || undefined,
74
+ });
75
+
76
+ let filename: string;
77
+ if (params.category === "entity" && params.identity_key) {
78
+ const identitySlug = slugify(params.identity_key);
79
+ filename = identitySlug
80
+ ? `${identitySlug}.md`
81
+ : `${params.id.slice(-8).toLowerCase()}.md`;
82
+ } else {
83
+ const slug = slugify((params.title || params.body).slice(0, 40));
84
+ const shortId = params.id.slice(-8).toLowerCase();
85
+ filename = slug ? `${slug}-${shortId}.md` : `${shortId}.md`;
86
+ }
87
+
88
+ const filePath = resolve(dir, filename);
89
+ const md = formatFrontmatter(fmFields) + mdBody;
90
+
91
+ try {
92
+ writeFileSync(filePath, md);
93
+ } catch (e) {
94
+ throw new Error(`Failed to write entry file "${filePath}": ${(e as Error).message}`);
95
+ }
96
+
97
+ return filePath;
98
+ }
99
+
100
+ export function writeEntry(ctx: BaseCtx, data: CaptureInput): CaptureResult {
101
+ if (!data.kind || typeof data.kind !== "string") {
102
+ throw new Error("writeEntry: kind is required (non-empty string)");
103
+ }
104
+ if (!data.body || typeof data.body !== "string" || !data.body.trim()) {
105
+ throw new Error("writeEntry: body is required (non-empty string)");
106
+ }
107
+ if (data.tags != null && !Array.isArray(data.tags)) {
108
+ throw new Error("writeEntry: tags must be an array if provided");
109
+ }
110
+ if (data.meta != null && typeof data.meta !== "object") {
111
+ throw new Error("writeEntry: meta must be an object if provided");
112
+ }
113
+
114
+ const category = categoryFor(data.kind);
115
+
116
+ let id: string;
117
+ let createdAt: string;
118
+ let updatedAt: string;
119
+ if (category === "entity" && data.identity_key) {
120
+ const identitySlug = slugify(data.identity_key);
121
+ const dir = resolve(ctx.config.vaultDir, kindToPath(data.kind));
122
+ const existingPath = resolve(dir, `${identitySlug}.md`);
123
+
124
+ if (existsSync(existingPath)) {
125
+ const raw = readFileSync(existingPath, "utf-8");
126
+ const { meta: fmMeta } = parseFrontmatter(raw);
127
+ id = (fmMeta.id as string) || ulid();
128
+ createdAt = (fmMeta.created as string) || new Date().toISOString();
129
+ updatedAt = new Date().toISOString();
130
+ } else {
131
+ id = ulid();
132
+ createdAt = new Date().toISOString();
133
+ updatedAt = createdAt;
134
+ }
135
+ } else {
136
+ id = ulid();
137
+ createdAt = new Date().toISOString();
138
+ updatedAt = createdAt;
139
+ }
140
+
141
+ const filePath = writeEntryFile(ctx.config.vaultDir, data.kind, {
142
+ id,
143
+ title: data.title,
144
+ body: data.body,
145
+ meta: data.meta,
146
+ tags: data.tags,
147
+ source: data.source,
148
+ createdAt,
149
+ updatedAt,
150
+ folder: data.folder,
151
+ category,
152
+ identity_key: data.identity_key,
153
+ expires_at: data.expires_at,
154
+ supersedes: data.supersedes,
155
+ related_to: data.related_to,
156
+ });
157
+
158
+ return {
159
+ id,
160
+ filePath,
161
+ kind: data.kind,
162
+ category,
163
+ title: data.title || null,
164
+ body: data.body,
165
+ meta: data.meta || undefined,
166
+ tags: data.tags || null,
167
+ source: data.source || null,
168
+ createdAt,
169
+ updatedAt,
170
+ identity_key: data.identity_key || null,
171
+ expires_at: data.expires_at || null,
172
+ supersedes: data.supersedes || null,
173
+ related_to: data.related_to || null,
174
+ source_files: data.source_files || null,
175
+ tier: data.tier || null,
176
+ };
177
+ }
178
+
179
+ export function updateEntryFile(
180
+ ctx: BaseCtx,
181
+ existing: Record<string, unknown>,
182
+ updates: {
183
+ title?: string | null;
184
+ body?: string | null;
185
+ tags?: string[] | null;
186
+ meta?: Record<string, unknown> | null;
187
+ source?: string | null;
188
+ expires_at?: string | null;
189
+ supersedes?: string[] | null;
190
+ related_to?: string[] | null;
191
+ source_files?: Array<{ path: string; hash: string }> | null;
192
+ },
193
+ ): IndexEntryInput & { supersedes?: string[] | null; related_to?: string[] | null } {
194
+ const raw = readFileSync(existing.file_path as string, "utf-8");
195
+ const { meta: fmMeta } = parseFrontmatter(raw);
196
+
197
+ const existingMeta = existing.meta ? JSON.parse(existing.meta as string) : {};
198
+ const existingTags = existing.tags ? JSON.parse(existing.tags as string) : [];
199
+ const existingRelatedTo = existing.related_to
200
+ ? JSON.parse(existing.related_to as string)
201
+ : (fmMeta.related_to as string[]) || null;
202
+
203
+ const title = updates.title !== undefined ? updates.title : (existing.title as string | null);
204
+ const body = updates.body !== undefined ? (updates.body as string) : (existing.body as string);
205
+ const tags = updates.tags !== undefined ? updates.tags : existingTags;
206
+ const source = updates.source !== undefined ? updates.source : (existing.source as string | null);
207
+ const expires_at = updates.expires_at !== undefined ? updates.expires_at : (existing.expires_at as string | null);
208
+ const supersedes = updates.supersedes !== undefined ? updates.supersedes : (fmMeta.supersedes as string[] || null);
209
+ const related_to = updates.related_to !== undefined ? updates.related_to : existingRelatedTo;
210
+ const source_files = updates.source_files !== undefined
211
+ ? updates.source_files
212
+ : existing.source_files
213
+ ? JSON.parse(existing.source_files as string)
214
+ : null;
215
+
216
+ let mergedMeta: Record<string, unknown>;
217
+ if (updates.meta !== undefined) {
218
+ mergedMeta = { ...existingMeta, ...(updates.meta || {}) };
219
+ } else {
220
+ mergedMeta = { ...existingMeta };
221
+ }
222
+
223
+ const now = new Date().toISOString();
224
+ const fmFields: Record<string, unknown> = { id: existing.id };
225
+ for (const [k, v] of Object.entries(mergedMeta)) {
226
+ if (k === "folder") continue;
227
+ if (v !== null && v !== undefined) fmFields[k] = v;
228
+ }
229
+ if (existing.identity_key) fmFields.identity_key = existing.identity_key;
230
+ if (expires_at) fmFields.expires_at = expires_at;
231
+ if (supersedes?.length) fmFields.supersedes = supersedes;
232
+ if (related_to?.length) fmFields.related_to = related_to;
233
+ fmFields.tags = tags;
234
+ fmFields.source = source || "claude-code";
235
+ fmFields.created = (fmMeta.created as string) || (existing.created_at as string);
236
+ if (now !== fmFields.created) fmFields.updated = now;
237
+
238
+ const mdBody = formatBody(existing.kind as string, {
239
+ title: title || undefined,
240
+ body,
241
+ meta: mergedMeta,
242
+ });
243
+ const md = formatFrontmatter(fmFields) + mdBody;
244
+
245
+ writeFileSync(existing.file_path as string, md);
246
+
247
+ const finalMeta = Object.keys(mergedMeta).length ? mergedMeta : undefined;
248
+
249
+ return {
250
+ id: existing.id as string,
251
+ filePath: existing.file_path as string,
252
+ kind: existing.kind as string,
253
+ category: existing.category as string,
254
+ title: title || null,
255
+ body,
256
+ meta: finalMeta,
257
+ tags,
258
+ source,
259
+ createdAt: (fmMeta.created as string) || (existing.created_at as string),
260
+ identity_key: (existing.identity_key as string) || null,
261
+ expires_at: expires_at || null,
262
+ supersedes,
263
+ related_to: related_to || null,
264
+ source_files: source_files || null,
265
+ tier: (existing.tier as string) || null,
266
+ };
267
+ }
268
+
269
+ export async function captureAndIndex(ctx: BaseCtx, data: CaptureInput, precomputedEmbedding?: Float32Array | null): Promise<CaptureResult> {
270
+ let previousContent: string | null = null;
271
+ if (categoryFor(data.kind) === "entity" && data.identity_key) {
272
+ const identitySlug = slugify(data.identity_key);
273
+ const dir = resolve(ctx.config.vaultDir, kindToPath(data.kind));
274
+ const existingPath = resolve(dir, `${identitySlug}.md`);
275
+ if (existsSync(existingPath)) {
276
+ previousContent = readFileSync(existingPath, "utf-8");
277
+ }
278
+ }
279
+
280
+ const entry = writeEntry(ctx, data);
281
+ try {
282
+ await indexEntry(ctx, entry, precomputedEmbedding);
283
+ if (entry.supersedes?.length && ctx.stmts.updateSupersededBy) {
284
+ for (const supersededId of entry.supersedes) {
285
+ if (typeof supersededId === "string" && supersededId.trim()) {
286
+ ctx.stmts.updateSupersededBy.run(entry.id, supersededId.trim());
287
+ }
288
+ }
289
+ }
290
+ if (entry.related_to?.length && ctx.stmts.updateRelatedTo) {
291
+ ctx.stmts.updateRelatedTo.run(JSON.stringify(entry.related_to), entry.id);
292
+ }
293
+ return entry;
294
+ } catch (err) {
295
+ if (previousContent) {
296
+ try {
297
+ writeFileSync(entry.filePath, previousContent);
298
+ } catch {}
299
+ } else {
300
+ try {
301
+ unlinkSync(entry.filePath);
302
+ } catch {}
303
+ }
304
+ throw new Error(
305
+ `Capture succeeded but indexing failed — file rolled back. ${(err as Error).message}`,
306
+ );
307
+ }
308
+ }
@@ -0,0 +1,54 @@
1
+ const KIND_CATEGORY: Record<string, string> = {
2
+ insight: "knowledge",
3
+ decision: "knowledge",
4
+ pattern: "knowledge",
5
+ prompt: "knowledge",
6
+ note: "knowledge",
7
+ document: "knowledge",
8
+ reference: "knowledge",
9
+ contact: "entity",
10
+ project: "entity",
11
+ tool: "entity",
12
+ source: "entity",
13
+ bucket: "entity",
14
+ event: "event",
15
+ conversation: "event",
16
+ message: "event",
17
+ session: "event",
18
+ task: "event",
19
+ log: "event",
20
+ feedback: "event",
21
+ inbox: "event",
22
+ };
23
+
24
+ const CATEGORY_DIR_NAMES: Record<string, string> = {
25
+ knowledge: "knowledge",
26
+ entity: "entities",
27
+ event: "events",
28
+ };
29
+
30
+ export const CATEGORY_DIRS = new Set(Object.values(CATEGORY_DIR_NAMES));
31
+
32
+ export const KIND_STALENESS_DAYS: Record<string, number> = {
33
+ pattern: 180,
34
+ decision: 365,
35
+ reference: 90,
36
+ };
37
+
38
+ const DURABLE_KINDS = new Set(["decision", "architecture", "pattern"]);
39
+ const EPHEMERAL_KINDS = new Set(["session", "observation"]);
40
+
41
+ export function categoryFor(kind: string): string {
42
+ return KIND_CATEGORY[kind] || "knowledge";
43
+ }
44
+
45
+ export function defaultTierFor(kind: string): string {
46
+ if (DURABLE_KINDS.has(kind)) return "durable";
47
+ if (EPHEMERAL_KINDS.has(kind)) return "ephemeral";
48
+ return "working";
49
+ }
50
+
51
+ export function categoryDirFor(kind: string): string {
52
+ const cat = categoryFor(kind);
53
+ return CATEGORY_DIR_NAMES[cat] || "knowledge";
54
+ }
@@ -1,32 +1,37 @@
1
1
  import { existsSync, readFileSync } from "node:fs";
2
2
  import { join, resolve } from "node:path";
3
3
  import { homedir } from "node:os";
4
- import { DEFAULT_GROWTH_THRESHOLDS, DEFAULT_LIFECYCLE } from "../constants.js";
4
+ import { DEFAULT_GROWTH_THRESHOLDS, DEFAULT_LIFECYCLE } from "./constants.js";
5
+ import type { VaultConfig } from "./types.js";
5
6
 
6
- export function parseArgs(argv) {
7
- const args = {};
7
+ export function parseArgs(argv: string[]): Record<string, string | number> {
8
+ const args: Record<string, string | number> = {};
8
9
  for (let i = 2; i < argv.length; i++) {
9
- if (argv[i] === "--vault-dir" && argv[i + 1]) args.vaultDir = argv[++i];
10
- else if (argv[i] === "--data-dir" && argv[i + 1]) args.dataDir = argv[++i];
11
- else if (argv[i] === "--db-path" && argv[i + 1]) args.dbPath = argv[++i];
12
- else if (argv[i] === "--dev-dir" && argv[i + 1]) args.devDir = argv[++i];
10
+ if (argv[i] === "--vault-dir" && argv[i + 1])
11
+ args.vaultDir = argv[++i];
12
+ else if (argv[i] === "--data-dir" && argv[i + 1])
13
+ args.dataDir = argv[++i];
14
+ else if (argv[i] === "--db-path" && argv[i + 1])
15
+ args.dbPath = argv[++i];
16
+ else if (argv[i] === "--dev-dir" && argv[i + 1])
17
+ args.devDir = argv[++i];
13
18
  else if (argv[i] === "--event-decay-days" && argv[i + 1])
14
19
  args.eventDecayDays = Number(argv[++i]);
15
20
  }
16
21
  return args;
17
22
  }
18
23
 
19
- export function resolveConfig() {
24
+ export function resolveConfig(): VaultConfig {
20
25
  const HOME = homedir();
21
26
  const cliArgs = parseArgs(process.argv);
22
27
 
23
28
  const dataDir = resolve(
24
- cliArgs.dataDir ||
29
+ (cliArgs.dataDir as string) ||
25
30
  process.env.CONTEXT_VAULT_DATA_DIR ||
26
31
  process.env.CONTEXT_MCP_DATA_DIR ||
27
32
  join(HOME, ".context-mcp"),
28
33
  );
29
- const config = {
34
+ const config: VaultConfig = {
30
35
  vaultDir: join(HOME, ".vault"),
31
36
  dataDir,
32
37
  dbPath: join(dataDir, "vault.db"),
@@ -117,16 +122,21 @@ export function resolveConfig() {
117
122
  if (c.autoConsolidate != null)
118
123
  config.consolidation.autoConsolidate = c.autoConsolidate === true;
119
124
  }
120
- // Hosted account linking (Phase 4)
121
- if (fc.hostedUrl) config.hostedUrl = fc.hostedUrl;
122
- if (fc.apiKey) config.apiKey = fc.apiKey;
123
- if (fc.userId) config.userId = fc.userId;
124
- if (fc.email) config.email = fc.email;
125
- if (fc.linkedAt) config.linkedAt = fc.linkedAt;
125
+ if (fc.lifecycle && typeof fc.lifecycle === "object") {
126
+ for (const [tier, rules] of Object.entries(fc.lifecycle)) {
127
+ if (rules && typeof rules === "object") {
128
+ if (!config.lifecycle[tier]) config.lifecycle[tier] = {};
129
+ if ((rules as Record<string, unknown>).archiveAfterDays != null)
130
+ config.lifecycle[tier].archiveAfterDays = Number(
131
+ (rules as Record<string, unknown>).archiveAfterDays,
132
+ );
133
+ }
134
+ }
135
+ }
126
136
  config.resolvedFrom = "config file";
127
137
  } catch (e) {
128
138
  throw new Error(
129
- `[context-vault] Invalid config at ${configPath}: ${e.message}`,
139
+ `[context-vault] Invalid config at ${configPath}: ${(e as Error).message}`,
130
140
  );
131
141
  }
132
142
  }
@@ -137,17 +147,17 @@ export function resolveConfig() {
137
147
  process.env.CONTEXT_MCP_VAULT_DIR
138
148
  ) {
139
149
  config.vaultDir =
140
- process.env.CONTEXT_VAULT_VAULT_DIR || process.env.CONTEXT_MCP_VAULT_DIR;
150
+ process.env.CONTEXT_VAULT_VAULT_DIR || process.env.CONTEXT_MCP_VAULT_DIR!;
141
151
  config.resolvedFrom = "env";
142
152
  }
143
153
  if (process.env.CONTEXT_VAULT_DB_PATH || process.env.CONTEXT_MCP_DB_PATH) {
144
154
  config.dbPath =
145
- process.env.CONTEXT_VAULT_DB_PATH || process.env.CONTEXT_MCP_DB_PATH;
155
+ process.env.CONTEXT_VAULT_DB_PATH || process.env.CONTEXT_MCP_DB_PATH!;
146
156
  config.resolvedFrom = "env";
147
157
  }
148
158
  if (process.env.CONTEXT_VAULT_DEV_DIR || process.env.CONTEXT_MCP_DEV_DIR) {
149
159
  config.devDir =
150
- process.env.CONTEXT_VAULT_DEV_DIR || process.env.CONTEXT_MCP_DEV_DIR;
160
+ process.env.CONTEXT_VAULT_DEV_DIR || process.env.CONTEXT_MCP_DEV_DIR!;
151
161
  config.resolvedFrom = "env";
152
162
  }
153
163
  if (
@@ -161,12 +171,6 @@ export function resolveConfig() {
161
171
  config.resolvedFrom = "env";
162
172
  }
163
173
 
164
- if (process.env.CONTEXT_VAULT_API_KEY) {
165
- config.apiKey = process.env.CONTEXT_VAULT_API_KEY;
166
- }
167
- if (process.env.CONTEXT_VAULT_HOSTED_URL) {
168
- config.hostedUrl = process.env.CONTEXT_VAULT_HOSTED_URL;
169
- }
170
174
  if (process.env.CONTEXT_VAULT_TELEMETRY !== undefined) {
171
175
  config.telemetry =
172
176
  process.env.CONTEXT_VAULT_TELEMETRY === "1" ||
@@ -174,29 +178,26 @@ export function resolveConfig() {
174
178
  }
175
179
 
176
180
  if (cliArgs.vaultDir) {
177
- config.vaultDir = cliArgs.vaultDir;
181
+ config.vaultDir = cliArgs.vaultDir as string;
178
182
  config.resolvedFrom = "CLI args";
179
183
  }
180
184
  if (cliArgs.dbPath) {
181
- config.dbPath = cliArgs.dbPath;
185
+ config.dbPath = cliArgs.dbPath as string;
182
186
  config.resolvedFrom = "CLI args";
183
187
  }
184
188
  if (cliArgs.devDir) {
185
- config.devDir = cliArgs.devDir;
189
+ config.devDir = cliArgs.devDir as string;
186
190
  config.resolvedFrom = "CLI args";
187
191
  }
188
192
  if (cliArgs.eventDecayDays != null) {
189
- config.eventDecayDays = cliArgs.eventDecayDays;
193
+ config.eventDecayDays = cliArgs.eventDecayDays as number;
190
194
  config.resolvedFrom = "CLI args";
191
195
  }
192
196
 
193
- // Resolve all paths to absolute
194
197
  config.vaultDir = resolve(config.vaultDir);
195
198
  config.dataDir = resolve(config.dataDir);
196
199
  config.dbPath = resolve(config.dbPath);
197
200
  config.devDir = resolve(config.devDir);
198
-
199
- // Check existence
200
201
  config.vaultDirExists = existsSync(config.vaultDir);
201
202
 
202
203
  return config;
@@ -4,12 +4,12 @@ export const MARKETING_URL = "https://contextvault.dev";
4
4
  export const GITHUB_ISSUES_URL =
5
5
  "https://github.com/fellanH/context-vault/issues";
6
6
 
7
- export const MAX_BODY_LENGTH = 100 * 1024; // 100KB
7
+ export const MAX_BODY_LENGTH = 100 * 1024;
8
8
  export const MAX_TITLE_LENGTH = 500;
9
9
  export const MAX_KIND_LENGTH = 64;
10
10
  export const MAX_TAG_LENGTH = 100;
11
11
  export const MAX_TAGS_COUNT = 20;
12
- export const MAX_META_LENGTH = 10 * 1024; // 10KB
12
+ export const MAX_META_LENGTH = 10 * 1024;
13
13
  export const MAX_SOURCE_LENGTH = 200;
14
14
  export const MAX_IDENTITY_KEY_LENGTH = 200;
15
15
 
@@ -20,7 +20,10 @@ export const DEFAULT_GROWTH_THRESHOLDS = {
20
20
  eventsWithoutTtl: { warn: 200 },
21
21
  };
22
22
 
23
- export const DEFAULT_LIFECYCLE = {
23
+ export const DEFAULT_LIFECYCLE: Record<
24
+ string,
25
+ { archiveAfterDays?: number }
26
+ > = {
24
27
  event: { archiveAfterDays: 90 },
25
28
  ephemeral: { archiveAfterDays: 30 },
26
29
  };