context-vault 3.1.3 → 3.1.5

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 (56) hide show
  1. package/bin/cli.js +146 -65
  2. package/node_modules/@context-vault/core/dist/capture.d.ts +1 -1
  3. package/node_modules/@context-vault/core/dist/capture.d.ts.map +1 -1
  4. package/node_modules/@context-vault/core/dist/capture.js +20 -9
  5. package/node_modules/@context-vault/core/dist/capture.js.map +1 -1
  6. package/node_modules/@context-vault/core/dist/config.d.ts.map +1 -1
  7. package/node_modules/@context-vault/core/dist/config.js.map +1 -1
  8. package/node_modules/@context-vault/core/dist/constants.d.ts.map +1 -1
  9. package/node_modules/@context-vault/core/dist/constants.js.map +1 -1
  10. package/node_modules/@context-vault/core/dist/db.d.ts.map +1 -1
  11. package/node_modules/@context-vault/core/dist/db.js +10 -0
  12. package/node_modules/@context-vault/core/dist/db.js.map +1 -1
  13. package/node_modules/@context-vault/core/dist/embed.d.ts.map +1 -1
  14. package/node_modules/@context-vault/core/dist/embed.js.map +1 -1
  15. package/node_modules/@context-vault/core/dist/formatters.d.ts.map +1 -1
  16. package/node_modules/@context-vault/core/dist/formatters.js.map +1 -1
  17. package/node_modules/@context-vault/core/dist/frontmatter.d.ts.map +1 -1
  18. package/node_modules/@context-vault/core/dist/frontmatter.js.map +1 -1
  19. package/node_modules/@context-vault/core/dist/index.d.ts +1 -1
  20. package/node_modules/@context-vault/core/dist/index.d.ts.map +1 -1
  21. package/node_modules/@context-vault/core/dist/index.js +27 -6
  22. package/node_modules/@context-vault/core/dist/index.js.map +1 -1
  23. package/node_modules/@context-vault/core/dist/ingest-url.d.ts.map +1 -1
  24. package/node_modules/@context-vault/core/dist/ingest-url.js +32 -9
  25. package/node_modules/@context-vault/core/dist/ingest-url.js.map +1 -1
  26. package/node_modules/@context-vault/core/dist/main.d.ts +3 -3
  27. package/node_modules/@context-vault/core/dist/main.d.ts.map +1 -1
  28. package/node_modules/@context-vault/core/dist/main.js +3 -3
  29. package/node_modules/@context-vault/core/dist/main.js.map +1 -1
  30. package/node_modules/@context-vault/core/dist/search.d.ts +1 -1
  31. package/node_modules/@context-vault/core/dist/search.d.ts.map +1 -1
  32. package/node_modules/@context-vault/core/dist/search.js +3 -2
  33. package/node_modules/@context-vault/core/dist/search.js.map +1 -1
  34. package/node_modules/@context-vault/core/package.json +1 -1
  35. package/node_modules/@context-vault/core/src/capture.ts +63 -19
  36. package/node_modules/@context-vault/core/src/config.ts +4 -8
  37. package/node_modules/@context-vault/core/src/constants.ts +5 -7
  38. package/node_modules/@context-vault/core/src/db.ts +11 -7
  39. package/node_modules/@context-vault/core/src/embed.ts +3 -1
  40. package/node_modules/@context-vault/core/src/formatters.ts +1 -4
  41. package/node_modules/@context-vault/core/src/frontmatter.ts +6 -4
  42. package/node_modules/@context-vault/core/src/index.ts +155 -46
  43. package/node_modules/@context-vault/core/src/ingest-url.ts +153 -40
  44. package/node_modules/@context-vault/core/src/main.ts +8 -11
  45. package/node_modules/@context-vault/core/src/search.ts +29 -10
  46. package/package.json +2 -2
  47. package/src/register-tools.js +1 -1
  48. package/src/server.js +1 -1
  49. package/src/status.js +111 -28
  50. package/src/telemetry.js +5 -1
  51. package/src/tools/context-status.js +145 -142
  52. package/src/tools/get-context.js +13 -13
  53. package/src/tools/ingest-project.js +39 -10
  54. package/src/tools/list-buckets.js +3 -5
  55. package/src/tools/save-context.js +34 -22
  56. package/src/tools/session-start.js +9 -3
@@ -1,13 +1,28 @@
1
- import { existsSync, readFileSync, unlinkSync, writeFileSync, mkdirSync } from "node:fs";
1
+ import {
2
+ existsSync,
3
+ readFileSync,
4
+ unlinkSync,
5
+ writeFileSync,
6
+ mkdirSync,
7
+ } from "node:fs";
2
8
  import { resolve, relative } from "node:path";
3
9
  import { ulid, slugify, kindToPath } from "./files.js";
4
10
  import { categoryFor, defaultTierFor } from "./categories.js";
5
11
  import { parseFrontmatter, formatFrontmatter } from "./frontmatter.js";
6
12
  import { formatBody } from "./formatters.js";
7
- import type { BaseCtx, CaptureInput, CaptureResult, IndexEntryInput } from "./types.js";
13
+ import type {
14
+ BaseCtx,
15
+ CaptureInput,
16
+ CaptureResult,
17
+ IndexEntryInput,
18
+ } from "./types.js";
8
19
  import { indexEntry } from "./index.js";
9
20
 
10
- function safeFolderPath(vaultDir: string, kind: string, folder?: string | null): string {
21
+ function safeFolderPath(
22
+ vaultDir: string,
23
+ kind: string,
24
+ folder?: string | null,
25
+ ): string {
11
26
  const base = resolve(vaultDir, kindToPath(kind));
12
27
  if (!folder) return base;
13
28
  const resolved = resolve(base, folder);
@@ -44,7 +59,9 @@ function writeEntryFile(
44
59
  try {
45
60
  mkdirSync(dir, { recursive: true });
46
61
  } catch (e) {
47
- throw new Error(`Failed to create directory "${dir}": ${(e as Error).message}`);
62
+ throw new Error(
63
+ `Failed to create directory "${dir}": ${(e as Error).message}`,
64
+ );
48
65
  }
49
66
 
50
67
  const created = params.createdAt || new Date().toISOString();
@@ -91,7 +108,9 @@ function writeEntryFile(
91
108
  try {
92
109
  writeFileSync(filePath, md);
93
110
  } catch (e) {
94
- throw new Error(`Failed to write entry file "${filePath}": ${(e as Error).message}`);
111
+ throw new Error(
112
+ `Failed to write entry file "${filePath}": ${(e as Error).message}`,
113
+ );
95
114
  }
96
115
 
97
116
  return filePath;
@@ -190,7 +209,10 @@ export function updateEntryFile(
190
209
  related_to?: string[] | null;
191
210
  source_files?: Array<{ path: string; hash: string }> | null;
192
211
  },
193
- ): IndexEntryInput & { supersedes?: string[] | null; related_to?: string[] | null } {
212
+ ): IndexEntryInput & {
213
+ supersedes?: string[] | null;
214
+ related_to?: string[] | null;
215
+ } {
194
216
  const raw = readFileSync(existing.file_path as string, "utf-8");
195
217
  const { meta: fmMeta } = parseFrontmatter(raw);
196
218
 
@@ -200,18 +222,35 @@ export function updateEntryFile(
200
222
  ? JSON.parse(existing.related_to as string)
201
223
  : (fmMeta.related_to as string[]) || null;
202
224
 
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);
225
+ const title =
226
+ updates.title !== undefined
227
+ ? updates.title
228
+ : (existing.title as string | null);
229
+ const body =
230
+ updates.body !== undefined
231
+ ? (updates.body as string)
232
+ : (existing.body as string);
205
233
  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;
234
+ const source =
235
+ updates.source !== undefined
236
+ ? updates.source
237
+ : (existing.source as string | null);
238
+ const expires_at =
239
+ updates.expires_at !== undefined
240
+ ? updates.expires_at
241
+ : (existing.expires_at as string | null);
242
+ const supersedes =
243
+ updates.supersedes !== undefined
244
+ ? updates.supersedes
245
+ : (fmMeta.supersedes as string[]) || null;
246
+ const related_to =
247
+ updates.related_to !== undefined ? updates.related_to : existingRelatedTo;
248
+ const source_files =
249
+ updates.source_files !== undefined
250
+ ? updates.source_files
251
+ : existing.source_files
252
+ ? JSON.parse(existing.source_files as string)
253
+ : null;
215
254
 
216
255
  let mergedMeta: Record<string, unknown>;
217
256
  if (updates.meta !== undefined) {
@@ -232,7 +271,8 @@ export function updateEntryFile(
232
271
  if (related_to?.length) fmFields.related_to = related_to;
233
272
  fmFields.tags = tags;
234
273
  fmFields.source = source || "claude-code";
235
- fmFields.created = (fmMeta.created as string) || (existing.created_at as string);
274
+ fmFields.created =
275
+ (fmMeta.created as string) || (existing.created_at as string);
236
276
  if (now !== fmFields.created) fmFields.updated = now;
237
277
 
238
278
  const mdBody = formatBody(existing.kind as string, {
@@ -266,7 +306,11 @@ export function updateEntryFile(
266
306
  };
267
307
  }
268
308
 
269
- export async function captureAndIndex(ctx: BaseCtx, data: CaptureInput, precomputedEmbedding?: Float32Array | null): Promise<CaptureResult> {
309
+ export async function captureAndIndex(
310
+ ctx: BaseCtx,
311
+ data: CaptureInput,
312
+ precomputedEmbedding?: Float32Array | null,
313
+ ): Promise<CaptureResult> {
270
314
  let previousContent: string | null = null;
271
315
  if (categoryFor(data.kind) === "entity" && data.identity_key) {
272
316
  const identitySlug = slugify(data.identity_key);
@@ -7,14 +7,10 @@ import type { VaultConfig } from "./types.js";
7
7
  export function parseArgs(argv: string[]): Record<string, string | number> {
8
8
  const args: Record<string, string | number> = {};
9
9
  for (let i = 2; i < argv.length; 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];
10
+ if (argv[i] === "--vault-dir" && argv[i + 1]) args.vaultDir = argv[++i];
11
+ else if (argv[i] === "--data-dir" && argv[i + 1]) args.dataDir = argv[++i];
12
+ else if (argv[i] === "--db-path" && argv[i + 1]) args.dbPath = argv[++i];
13
+ else if (argv[i] === "--dev-dir" && argv[i + 1]) args.devDir = argv[++i];
18
14
  else if (argv[i] === "--event-decay-days" && argv[i + 1])
19
15
  args.eventDecayDays = Number(argv[++i]);
20
16
  }
@@ -20,10 +20,8 @@ export const DEFAULT_GROWTH_THRESHOLDS = {
20
20
  eventsWithoutTtl: { warn: 200 },
21
21
  };
22
22
 
23
- export const DEFAULT_LIFECYCLE: Record<
24
- string,
25
- { archiveAfterDays?: number }
26
- > = {
27
- event: { archiveAfterDays: 90 },
28
- ephemeral: { archiveAfterDays: 30 },
29
- };
23
+ export const DEFAULT_LIFECYCLE: Record<string, { archiveAfterDays?: number }> =
24
+ {
25
+ event: { archiveAfterDays: 90 },
26
+ ephemeral: { archiveAfterDays: 30 },
27
+ };
@@ -117,7 +117,9 @@ export async function initDatabase(dbPath: string): Promise<DatabaseSync> {
117
117
  }
118
118
 
119
119
  const db = createDb(dbPath);
120
- const version = (db.prepare("PRAGMA user_version").get() as { user_version: number }).user_version;
120
+ const version = (
121
+ db.prepare("PRAGMA user_version").get() as { user_version: number }
122
+ ).user_version;
121
123
 
122
124
  if (version > 0 && version < 15) {
123
125
  console.error(
@@ -146,13 +148,17 @@ export async function initDatabase(dbPath: string): Promise<DatabaseSync> {
146
148
  if (!backupSucceeded) {
147
149
  throw new Error(
148
150
  `[context-vault] Aborting schema migration: backup failed for ${dbPath}. ` +
149
- `Fix the backup issue or manually back up the file before upgrading.`,
151
+ `Fix the backup issue or manually back up the file before upgrading.`,
150
152
  );
151
153
  }
152
154
 
153
155
  unlinkSync(dbPath);
154
- try { unlinkSync(dbPath + "-wal"); } catch {}
155
- try { unlinkSync(dbPath + "-shm"); } catch {}
156
+ try {
157
+ unlinkSync(dbPath + "-wal");
158
+ } catch {}
159
+ try {
160
+ unlinkSync(dbPath + "-shm");
161
+ } catch {}
156
162
 
157
163
  const freshDb = createDb(dbPath);
158
164
  freshDb.exec(SCHEMA_DDL);
@@ -179,9 +185,7 @@ export function prepareStatements(db: DatabaseSync): PreparedStatements {
179
185
  ),
180
186
  deleteEntry: db.prepare(`DELETE FROM vault WHERE id = ?`),
181
187
  getRowid: db.prepare(`SELECT rowid FROM vault WHERE id = ?`),
182
- getRowidByPath: db.prepare(
183
- `SELECT rowid FROM vault WHERE file_path = ?`,
184
- ),
188
+ getRowidByPath: db.prepare(`SELECT rowid FROM vault WHERE file_path = ?`),
185
189
  getEntryById: db.prepare(`SELECT * FROM vault WHERE id = ?`),
186
190
  getByIdentityKey: db.prepare(
187
191
  `SELECT * FROM vault WHERE kind = ? AND identity_key = ?`,
@@ -60,7 +60,9 @@ export async function embed(text: string): Promise<Float32Array | null> {
60
60
  return new Float32Array(result.data);
61
61
  }
62
62
 
63
- export async function embedBatch(texts: string[]): Promise<(Float32Array | null)[]> {
63
+ export async function embedBatch(
64
+ texts: string[],
65
+ ): Promise<(Float32Array | null)[]> {
64
66
  if (!texts.length) return [];
65
67
  const ext = await ensurePipeline();
66
68
  if (!ext) return texts.map(() => null);
@@ -22,10 +22,7 @@ const FORMATTERS: Record<string, (input: FormatInput) => string> = {
22
22
  const DEFAULT_FORMATTER = ({ title, body }: FormatInput): string =>
23
23
  title ? "\n# " + title + "\n\n" + body + "\n" : "\n" + body + "\n";
24
24
 
25
- export function formatBody(
26
- kind: string,
27
- input: FormatInput,
28
- ): string {
25
+ export function formatBody(kind: string, input: FormatInput): string {
29
26
  const fn = FORMATTERS[kind] || DEFAULT_FORMATTER;
30
27
  return fn(input);
31
28
  }
@@ -84,15 +84,17 @@ export function parseEntryFromMarkdown(
84
84
  kind: string,
85
85
  body: string,
86
86
  fmMeta: Record<string, unknown>,
87
- ): { title: string | null; body: string; meta: Record<string, unknown> | null } {
87
+ ): {
88
+ title: string | null;
89
+ body: string;
90
+ meta: Record<string, unknown> | null;
91
+ } {
88
92
  if (kind === "insight") {
89
93
  return { title: null, body, meta: extractCustomMeta(fmMeta) };
90
94
  }
91
95
 
92
96
  if (kind === "decision") {
93
- const titleMatch = body.match(
94
- /^## Decision\s*\n+([\s\S]*?)(?=\n## |\n*$)/,
95
- );
97
+ const titleMatch = body.match(/^## Decision\s*\n+([\s\S]*?)(?=\n## |\n*$)/);
96
98
  const rationaleMatch = body.match(/## Rationale\s*\n+([\s\S]*?)$/);
97
99
  const title = titleMatch ? titleMatch[1].trim() : body.slice(0, 100);
98
100
  const rationale = rationaleMatch ? rationaleMatch[1].trim() : body;
@@ -12,12 +12,27 @@ const EMBED_BATCH_SIZE = 32;
12
12
 
13
13
  export async function indexEntry(
14
14
  ctx: BaseCtx,
15
- entry: IndexEntryInput & { supersedes?: string[] | null; related_to?: string[] | null },
15
+ entry: IndexEntryInput & {
16
+ supersedes?: string[] | null;
17
+ related_to?: string[] | null;
18
+ },
16
19
  precomputedEmbedding?: Float32Array | null,
17
20
  ): Promise<void> {
18
21
  const {
19
- id, kind, category, title, body, meta, tags, source,
20
- filePath, createdAt, identity_key, expires_at, source_files, tier,
22
+ id,
23
+ kind,
24
+ category,
25
+ title,
26
+ body,
27
+ meta,
28
+ tags,
29
+ source,
30
+ filePath,
31
+ createdAt,
32
+ identity_key,
33
+ expires_at,
34
+ source_files,
35
+ tier,
21
36
  } = entry;
22
37
 
23
38
  if (expires_at && new Date(expires_at) <= new Date()) return;
@@ -31,13 +46,22 @@ export async function indexEntry(
31
46
  let wasUpdate = false;
32
47
 
33
48
  if (cat === "entity" && identity_key) {
34
- const existing = ctx.stmts.getByIdentityKey.get(kind, identity_key) as Record<string, unknown> | undefined;
49
+ const existing = ctx.stmts.getByIdentityKey.get(kind, identity_key) as
50
+ | Record<string, unknown>
51
+ | undefined;
35
52
  if (existing) {
36
53
  ctx.stmts.upsertByIdentityKey.run(
37
- title || null, body, metaJson, tagsJson,
38
- source || "claude-code", cat, filePath,
39
- expires_at || null, sourceFilesJson,
40
- kind, identity_key,
54
+ title || null,
55
+ body,
56
+ metaJson,
57
+ tagsJson,
58
+ source || "claude-code",
59
+ cat,
60
+ filePath,
61
+ expires_at || null,
62
+ sourceFilesJson,
63
+ kind,
64
+ identity_key,
41
65
  );
42
66
  wasUpdate = true;
43
67
  }
@@ -46,20 +70,39 @@ export async function indexEntry(
46
70
  if (!wasUpdate) {
47
71
  try {
48
72
  ctx.stmts.insertEntry.run(
49
- id, kind, cat, title || null, body, metaJson, tagsJson,
50
- source || "claude-code", filePath,
51
- identity_key || null, expires_at || null,
52
- createdAt, createdAt, sourceFilesJson, effectiveTier,
73
+ id,
74
+ kind,
75
+ cat,
76
+ title || null,
77
+ body,
78
+ metaJson,
79
+ tagsJson,
80
+ source || "claude-code",
81
+ filePath,
82
+ identity_key || null,
83
+ expires_at || null,
84
+ createdAt,
85
+ createdAt,
86
+ sourceFilesJson,
87
+ effectiveTier,
53
88
  );
54
89
  } catch (e) {
55
90
  if ((e as Error).message.includes("UNIQUE constraint")) {
56
91
  ctx.stmts.updateEntry.run(
57
- title || null, body, metaJson, tagsJson,
58
- source || "claude-code", cat,
59
- identity_key || null, expires_at || null, filePath,
92
+ title || null,
93
+ body,
94
+ metaJson,
95
+ tagsJson,
96
+ source || "claude-code",
97
+ cat,
98
+ identity_key || null,
99
+ expires_at || null,
100
+ filePath,
60
101
  );
61
102
  if (sourceFilesJson !== null && ctx.stmts.updateSourceFiles) {
62
- const entryRow = ctx.stmts.getRowidByPath.get(filePath) as { rowid: number } | undefined;
103
+ const entryRow = ctx.stmts.getRowidByPath.get(filePath) as
104
+ | { rowid: number }
105
+ | undefined;
63
106
  if (entryRow) {
64
107
  const idRow = ctx.db
65
108
  .prepare("SELECT id FROM vault WHERE file_path = ?")
@@ -76,8 +119,8 @@ export async function indexEntry(
76
119
  }
77
120
 
78
121
  const rowidResult = wasUpdate
79
- ? ctx.stmts.getRowidByPath.get(filePath) as { rowid: number } | undefined
80
- : ctx.stmts.getRowid.get(id) as { rowid: number } | undefined;
122
+ ? (ctx.stmts.getRowidByPath.get(filePath) as { rowid: number } | undefined)
123
+ : (ctx.stmts.getRowid.get(id) as { rowid: number } | undefined);
81
124
 
82
125
  if (!rowidResult || rowidResult.rowid == null) {
83
126
  throw new Error(
@@ -100,12 +143,18 @@ export async function indexEntry(
100
143
  try {
101
144
  embedding = await ctx.embed([title, body].filter(Boolean).join(" "));
102
145
  } catch (embedErr) {
103
- console.warn(`[context-vault] embed() failed for entry ${id} — skipping vec insert: ${(embedErr as Error).message}`);
146
+ console.warn(
147
+ `[context-vault] embed() failed for entry ${id} — skipping vec insert: ${(embedErr as Error).message}`,
148
+ );
104
149
  }
105
150
  }
106
151
 
107
152
  if (embedding) {
108
- try { ctx.deleteVec(rowid); } catch { /* no-op */ }
153
+ try {
154
+ ctx.deleteVec(rowid);
155
+ } catch {
156
+ /* no-op */
157
+ }
109
158
  ctx.insertVec(rowid, embedding);
110
159
  }
111
160
  }
@@ -120,11 +169,17 @@ export async function pruneExpired(ctx: BaseCtx): Promise<number> {
120
169
 
121
170
  for (const row of expired) {
122
171
  if (row.file_path) {
123
- try { unlinkSync(row.file_path); } catch {}
172
+ try {
173
+ unlinkSync(row.file_path);
174
+ } catch {}
124
175
  }
125
- const vRowid = (ctx.stmts.getRowid.get(row.id) as { rowid: number } | undefined)?.rowid;
176
+ const vRowid = (
177
+ ctx.stmts.getRowid.get(row.id) as { rowid: number } | undefined
178
+ )?.rowid;
126
179
  if (vRowid) {
127
- try { ctx.deleteVec(Number(vRowid)); } catch {}
180
+ try {
181
+ ctx.deleteVec(Number(vRowid));
182
+ } catch {}
128
183
  }
129
184
  ctx.stmts.deleteEntry.run(row.id);
130
185
  }
@@ -137,7 +192,12 @@ export async function reindex(
137
192
  opts: { fullSync?: boolean } = {},
138
193
  ): Promise<ReindexStats> {
139
194
  const { fullSync = true } = opts;
140
- const stats: ReindexStats = { added: 0, updated: 0, removed: 0, unchanged: 0 };
195
+ const stats: ReindexStats = {
196
+ added: 0,
197
+ updated: 0,
198
+ removed: 0,
199
+ unchanged: 0,
200
+ };
141
201
 
142
202
  if (!existsSync(ctx.config.vaultDir)) return stats;
143
203
 
@@ -224,20 +284,32 @@ export async function reindex(
224
284
  if (!existing) {
225
285
  const id = (fmMeta.id as string) || ulid();
226
286
  const tagsJson = fmMeta.tags ? JSON.stringify(fmMeta.tags) : null;
227
- const created = (fmMeta.created as string) || new Date().toISOString();
287
+ const created =
288
+ (fmMeta.created as string) || new Date().toISOString();
228
289
 
229
290
  const result = upsertEntry.run(
230
- id, kind, category, parsed.title || null, parsed.body,
231
- metaJson, tagsJson, (fmMeta.source as string) || "file",
232
- filePath, identity_key, expires_at,
233
- created, (fmMeta.updated as string) || created,
291
+ id,
292
+ kind,
293
+ category,
294
+ parsed.title || null,
295
+ parsed.body,
296
+ metaJson,
297
+ tagsJson,
298
+ (fmMeta.source as string) || "file",
299
+ filePath,
300
+ identity_key,
301
+ expires_at,
302
+ created,
303
+ (fmMeta.updated as string) || created,
234
304
  );
235
305
  if ((result as { changes: number }).changes > 0) {
236
306
  if (relatedToJson && ctx.stmts.updateRelatedTo) {
237
307
  ctx.stmts.updateRelatedTo.run(relatedToJson, id);
238
308
  }
239
309
  if (category !== "event") {
240
- const rowidResult = ctx.stmts.getRowid.get(id) as { rowid: number } | undefined;
310
+ const rowidResult = ctx.stmts.getRowid.get(id) as
311
+ | { rowid: number }
312
+ | undefined;
241
313
  if (rowidResult?.rowid) {
242
314
  const embeddingText = [parsed.title, parsed.body]
243
315
  .filter(Boolean)
@@ -254,24 +326,45 @@ export async function reindex(
254
326
  }
255
327
  } else if (fullSync) {
256
328
  const tagsJson = fmMeta.tags ? JSON.stringify(fmMeta.tags) : null;
257
- const titleChanged = (parsed.title || null) !== ((existing.title as string) || null);
329
+ const titleChanged =
330
+ (parsed.title || null) !== ((existing.title as string) || null);
258
331
  const bodyChanged = (existing.body as string) !== parsed.body;
259
332
  const tagsChanged = tagsJson !== ((existing.tags as string) || null);
260
333
  const metaChanged = metaJson !== ((existing.meta as string) || null);
261
- const relatedToChanged = relatedToJson !== ((existing.related_to as string) || null);
262
-
263
- if (bodyChanged || titleChanged || tagsChanged || metaChanged || relatedToChanged) {
334
+ const relatedToChanged =
335
+ relatedToJson !== ((existing.related_to as string) || null);
336
+
337
+ if (
338
+ bodyChanged ||
339
+ titleChanged ||
340
+ tagsChanged ||
341
+ metaChanged ||
342
+ relatedToChanged
343
+ ) {
264
344
  ctx.stmts.updateEntry.run(
265
- parsed.title || null, parsed.body, metaJson, tagsJson,
266
- (fmMeta.source as string) || "file", category,
267
- identity_key, expires_at, filePath,
345
+ parsed.title || null,
346
+ parsed.body,
347
+ metaJson,
348
+ tagsJson,
349
+ (fmMeta.source as string) || "file",
350
+ category,
351
+ identity_key,
352
+ expires_at,
353
+ filePath,
268
354
  );
269
355
  if (relatedToChanged && ctx.stmts.updateRelatedTo) {
270
- ctx.stmts.updateRelatedTo.run(relatedToJson, existing.id as string);
356
+ ctx.stmts.updateRelatedTo.run(
357
+ relatedToJson,
358
+ existing.id as string,
359
+ );
271
360
  }
272
361
 
273
362
  if ((bodyChanged || titleChanged) && category !== "event") {
274
- const rowid = (ctx.stmts.getRowid.get(existing.id as string) as { rowid: number } | undefined)?.rowid;
363
+ const rowid = (
364
+ ctx.stmts.getRowid.get(existing.id as string) as
365
+ | { rowid: number }
366
+ | undefined
367
+ )?.rowid;
275
368
  if (rowid) {
276
369
  const embeddingText = [parsed.title, parsed.body]
277
370
  .filter(Boolean)
@@ -291,9 +384,15 @@ export async function reindex(
291
384
  if (fullSync) {
292
385
  for (const [dbPath, row] of dbByPath) {
293
386
  if (!diskPaths.has(dbPath)) {
294
- const vRowid = (ctx.stmts.getRowid.get(row.id as string) as { rowid: number } | undefined)?.rowid;
387
+ const vRowid = (
388
+ ctx.stmts.getRowid.get(row.id as string) as
389
+ | { rowid: number }
390
+ | undefined
391
+ )?.rowid;
295
392
  if (vRowid) {
296
- try { ctx.deleteVec(vRowid); } catch {}
393
+ try {
394
+ ctx.deleteVec(vRowid);
395
+ } catch {}
297
396
  }
298
397
  ctx.stmts.deleteEntry.run(row.id as string);
299
398
  stats.removed++;
@@ -313,7 +412,9 @@ export async function reindex(
313
412
  .prepare("SELECT id, rowid FROM vault WHERE kind = ?")
314
413
  .all(kind) as { id: string; rowid: number }[];
315
414
  for (const row of orphaned) {
316
- try { ctx.deleteVec(row.rowid); } catch {}
415
+ try {
416
+ ctx.deleteVec(row.rowid);
417
+ } catch {}
317
418
  ctx.stmts.deleteEntry.run(row.id);
318
419
  stats.removed++;
319
420
  }
@@ -329,11 +430,17 @@ export async function reindex(
329
430
 
330
431
  for (const row of expired) {
331
432
  if (row.file_path) {
332
- try { unlinkSync(row.file_path); } catch {}
433
+ try {
434
+ unlinkSync(row.file_path);
435
+ } catch {}
333
436
  }
334
- const vRowid = (ctx.stmts.getRowid.get(row.id) as { rowid: number } | undefined)?.rowid;
437
+ const vRowid = (
438
+ ctx.stmts.getRowid.get(row.id) as { rowid: number } | undefined
439
+ )?.rowid;
335
440
  if (vRowid) {
336
- try { ctx.deleteVec(Number(vRowid)); } catch {}
441
+ try {
442
+ ctx.deleteVec(Number(vRowid));
443
+ } catch {}
337
444
  }
338
445
  ctx.stmts.deleteEntry.run(row.id);
339
446
  stats.removed++;
@@ -350,7 +457,9 @@ export async function reindex(
350
457
  const embeddings = await embedBatch(batch.map((e) => e.text));
351
458
  for (let j = 0; j < batch.length; j++) {
352
459
  if (embeddings[j]) {
353
- try { ctx.deleteVec(batch[j].rowid); } catch {}
460
+ try {
461
+ ctx.deleteVec(batch[j].rowid);
462
+ } catch {}
354
463
  ctx.insertVec(batch[j].rowid, embeddings[j]!);
355
464
  }
356
465
  }