@gzoo/cortex 0.5.11 → 0.5.13

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 (62) hide show
  1. package/dist/cortex.mjs +358 -159
  2. package/package.json +1 -1
  3. package/packages/cli/dist/commands/config.d.ts.map +1 -1
  4. package/packages/cli/dist/commands/config.js +9 -1
  5. package/packages/cli/dist/commands/config.js.map +1 -1
  6. package/packages/cli/dist/commands/ingest.js +3 -1
  7. package/packages/cli/dist/commands/ingest.js.map +1 -1
  8. package/packages/cli/dist/commands/mcp.js +1 -1
  9. package/packages/cli/dist/commands/mcp.js.map +1 -1
  10. package/packages/cli/dist/commands/models.js +2 -1
  11. package/packages/cli/dist/commands/models.js.map +1 -1
  12. package/packages/cli/dist/commands/serve.js +1 -1
  13. package/packages/cli/dist/commands/serve.js.map +1 -1
  14. package/packages/cli/dist/commands/status.d.ts.map +1 -1
  15. package/packages/cli/dist/commands/status.js +15 -4
  16. package/packages/cli/dist/commands/status.js.map +1 -1
  17. package/packages/cli/dist/commands/watch.js +1 -0
  18. package/packages/cli/dist/commands/watch.js.map +1 -1
  19. package/packages/cli/dist/index.js +1 -1
  20. package/packages/cli/dist/index.js.map +1 -1
  21. package/packages/graph/dist/migrations/002-add-indexes.d.ts +4 -0
  22. package/packages/graph/dist/migrations/002-add-indexes.d.ts.map +1 -0
  23. package/packages/graph/dist/migrations/002-add-indexes.js +30 -0
  24. package/packages/graph/dist/migrations/002-add-indexes.js.map +1 -0
  25. package/packages/graph/dist/query-engine.d.ts.map +1 -1
  26. package/packages/graph/dist/query-engine.js +16 -25
  27. package/packages/graph/dist/query-engine.js.map +1 -1
  28. package/packages/graph/dist/sqlite-store.d.ts +5 -1
  29. package/packages/graph/dist/sqlite-store.d.ts.map +1 -1
  30. package/packages/graph/dist/sqlite-store.js +152 -118
  31. package/packages/graph/dist/sqlite-store.js.map +1 -1
  32. package/packages/ingest/dist/parsers/conversation.js +2 -2
  33. package/packages/ingest/dist/parsers/conversation.js.map +1 -1
  34. package/packages/ingest/dist/pipeline.d.ts +7 -0
  35. package/packages/ingest/dist/pipeline.d.ts.map +1 -1
  36. package/packages/ingest/dist/pipeline.js +43 -5
  37. package/packages/ingest/dist/pipeline.js.map +1 -1
  38. package/packages/ingest/dist/watcher.d.ts +1 -0
  39. package/packages/ingest/dist/watcher.d.ts.map +1 -1
  40. package/packages/ingest/dist/watcher.js +22 -11
  41. package/packages/ingest/dist/watcher.js.map +1 -1
  42. package/packages/llm/dist/cache.js +5 -5
  43. package/packages/llm/dist/cache.js.map +1 -1
  44. package/packages/llm/dist/providers/ollama.d.ts +1 -0
  45. package/packages/llm/dist/providers/ollama.d.ts.map +1 -1
  46. package/packages/llm/dist/providers/ollama.js +68 -17
  47. package/packages/llm/dist/providers/ollama.js.map +1 -1
  48. package/packages/llm/dist/providers/openai-compatible.d.ts.map +1 -1
  49. package/packages/llm/dist/providers/openai-compatible.js +7 -1
  50. package/packages/llm/dist/providers/openai-compatible.js.map +1 -1
  51. package/packages/llm/dist/token-tracker.d.ts +1 -0
  52. package/packages/llm/dist/token-tracker.d.ts.map +1 -1
  53. package/packages/llm/dist/token-tracker.js +19 -0
  54. package/packages/llm/dist/token-tracker.js.map +1 -1
  55. package/packages/server/dist/index.d.ts.map +1 -1
  56. package/packages/server/dist/index.js +15 -2
  57. package/packages/server/dist/index.js.map +1 -1
  58. package/packages/server/dist/middleware/auth.d.ts.map +1 -1
  59. package/packages/server/dist/middleware/auth.js +4 -0
  60. package/packages/server/dist/middleware/auth.js.map +1 -1
  61. package/packages/server/dist/routes/status.js +1 -1
  62. package/packages/server/dist/routes/status.js.map +1 -1
@@ -4,6 +4,17 @@ const AVG_CHARS_PER_TOKEN = 4;
4
4
  function estimateTokens(text) {
5
5
  return Math.ceil(text.length / AVG_CHARS_PER_TOKEN);
6
6
  }
7
+ const FTS_STOP_WORDS = new Set([
8
+ 'a', 'an', 'the', 'and', 'or', 'but', 'in', 'on', 'at', 'to', 'for',
9
+ 'of', 'with', 'by', 'from', 'is', 'are', 'was', 'were', 'be', 'been',
10
+ 'being', 'have', 'has', 'had', 'do', 'does', 'did', 'will', 'would',
11
+ 'could', 'should', 'may', 'might', 'shall', 'can', 'need', 'must',
12
+ 'what', 'which', 'who', 'how', 'why', 'when', 'where', 'that', 'this',
13
+ 'these', 'those', 'it', 'its', 'me', 'my', 'you', 'your', 'we', 'our',
14
+ 'they', 'their', 'he', 'she', 'i', 'all', 'any', 'each', 'some', 'no',
15
+ 'not', 'so', 'yet', 'use', 'used', 'using', 'about', 'tell', 'know',
16
+ 'get', 'got', 'make', 'made', 'see', 'give', 'go', 'come', 'take',
17
+ ]);
7
18
  export class QueryEngine {
8
19
  sqliteStore;
9
20
  vectorStore;
@@ -42,19 +53,10 @@ export class QueryEngine {
42
53
  }
43
54
  // Filter entities by project privacy level
44
55
  const privacyFiltered = await this.filterByPrivacy(contextEntities);
45
- // Gather relationships between context entities
56
+ // Gather relationships between context entities (single batch query)
46
57
  const entityIds = new Set(privacyFiltered.map((e) => e.id));
47
- const relationships = [];
48
- for (const entity of privacyFiltered) {
49
- const rels = await this.sqliteStore.getRelationshipsForEntity(entity.id);
50
- for (const rel of rels) {
51
- if (entityIds.has(rel.sourceEntityId) && entityIds.has(rel.targetEntityId)) {
52
- relationships.push(rel);
53
- }
54
- }
55
- }
56
- // Deduplicate relationships
57
- const uniqueRels = [...new Map(relationships.map((r) => [r.id, r])).values()];
58
+ const allRels = await this.sqliteStore.getRelationshipsForEntities([...entityIds]);
59
+ const uniqueRels = allRels.filter((r) => entityIds.has(r.sourceEntityId) && entityIds.has(r.targetEntityId));
58
60
  const relTokens = uniqueRels.reduce((sum, r) => sum + estimateTokens(r.description ?? '') + 20, 0);
59
61
  // Recalculate tokens after privacy filtering (content may have been redacted)
60
62
  const filteredTokens = privacyFiltered.reduce((sum, e) => sum + estimateTokens(e.content) + estimateTokens(e.name), 0);
@@ -110,22 +112,11 @@ export class QueryEngine {
110
112
  * entities matching ANY meaningful keyword are returned.
111
113
  */
112
114
  buildFtsQuery(query) {
113
- const stopWords = new Set([
114
- 'a', 'an', 'the', 'and', 'or', 'but', 'in', 'on', 'at', 'to', 'for',
115
- 'of', 'with', 'by', 'from', 'is', 'are', 'was', 'were', 'be', 'been',
116
- 'being', 'have', 'has', 'had', 'do', 'does', 'did', 'will', 'would',
117
- 'could', 'should', 'may', 'might', 'shall', 'can', 'need', 'must',
118
- 'what', 'which', 'who', 'how', 'why', 'when', 'where', 'that', 'this',
119
- 'these', 'those', 'it', 'its', 'me', 'my', 'you', 'your', 'we', 'our',
120
- 'they', 'their', 'he', 'she', 'i', 'all', 'any', 'each', 'some', 'no',
121
- 'not', 'so', 'yet', 'use', 'used', 'using', 'about', 'tell', 'know',
122
- 'get', 'got', 'make', 'made', 'see', 'give', 'go', 'come', 'take',
123
- ]);
124
115
  const keywords = query
125
- .replace(/[^a-zA-Z0-9\s]/g, ' ') // strip all non-alphanumeric chars (catches ?, !, ., etc.)
116
+ .replace(/[^a-zA-Z0-9\s]/g, ' ')
126
117
  .toLowerCase()
127
118
  .split(/\s+/)
128
- .filter((w) => w.length >= 3 && !stopWords.has(w));
119
+ .filter((w) => w.length >= 3 && !FTS_STOP_WORDS.has(w));
129
120
  if (keywords.length === 0) {
130
121
  // Fallback: sanitize raw query for FTS5 safety
131
122
  return query.replace(/[^a-zA-Z0-9\s]/g, ' ').trim();
@@ -1 +1 @@
1
- {"version":3,"file":"query-engine.js","sourceRoot":"","sources":["../src/query-engine.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"query-engine.js","sourceRoot":"","sources":["../src/query-engine.ts"],"names":[],"mappings":"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"}
@@ -60,14 +60,18 @@ export declare class SQLiteStore implements GraphStore {
60
60
  private migrate;
61
61
  private backupSync;
62
62
  close(): void;
63
+ transaction<T>(fn: () => T): T;
64
+ createEntitySync(entity: Omit<Entity, 'id' | 'createdAt' | 'updatedAt'>): Entity;
63
65
  createEntity(entity: Omit<Entity, 'id' | 'createdAt' | 'updatedAt'>): Promise<Entity>;
66
+ private _createEntity;
64
67
  getEntity(id: string): Promise<Entity | null>;
65
68
  updateEntity(id: string, updates: Partial<Entity>): Promise<Entity>;
66
69
  deleteEntity(id: string, soft?: boolean): Promise<void>;
67
70
  findEntities(query: EntityQuery): Promise<Entity[]>;
68
71
  createRelationship(rel: Omit<Relationship, 'id' | 'createdAt' | 'updatedAt'>): Promise<Relationship>;
69
72
  getRelationship(id: string): Promise<Relationship | null>;
70
- getRelationshipsForEntity(entityId: string, direction?: 'in' | 'out' | 'both'): Promise<Relationship[]>;
73
+ getRelationshipsForEntity(entityId: string, direction?: 'in' | 'out' | 'both', limit?: number): Promise<Relationship[]>;
74
+ getRelationshipsForEntities(entityIds: string[]): Promise<Relationship[]>;
71
75
  deleteRelationship(id: string): Promise<void>;
72
76
  deleteBySourcePath(pathPrefix: string): {
73
77
  deletedEntities: number;
@@ -1 +1 @@
1
- {"version":3,"file":"sqlite-store.d.ts","sourceRoot":"","sources":["../src/sqlite-store.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"sqlite-store.d.ts","sourceRoot":"","sources":["../src/sqlite-store.ts"],"names":[],"mappings":"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"}
@@ -5,6 +5,7 @@ import { dirname } from 'node:path';
5
5
  import { homedir } from 'node:os';
6
6
  import { CortexError, GRAPH_DB_ERROR, GRAPH_ENTITY_NOT_FOUND, } from '@cortex/core';
7
7
  import { up as applyInitialMigration } from './migrations/001-initial.js';
8
+ import { up as applyIndexMigration } from './migrations/002-add-indexes.js';
8
9
  function resolveHomePath(p) {
9
10
  return p.startsWith('~') ? p.replace('~', homedir()) : p;
10
11
  }
@@ -93,11 +94,16 @@ export class SQLiteStore {
93
94
  constructor(options = {}) {
94
95
  const { dbPath = '~/.cortex/cortex.db', walMode = true, backupOnStartup = true, } = options;
95
96
  this.dbPath = resolveHomePath(dbPath);
96
- mkdirSync(dirname(this.dbPath), { recursive: true });
97
+ mkdirSync(dirname(this.dbPath), { recursive: true, mode: 0o700 });
97
98
  if (backupOnStartup) {
98
99
  this.backupSync();
99
100
  }
100
101
  this.db = new Database(this.dbPath);
102
+ // Restrict DB file permissions (owner-only read/write)
103
+ try {
104
+ chmodSync(this.dbPath, 0o600);
105
+ }
106
+ catch { /* Windows — ignore */ }
101
107
  if (walMode) {
102
108
  this.db.pragma('journal_mode = WAL');
103
109
  }
@@ -108,6 +114,7 @@ export class SQLiteStore {
108
114
  migrate() {
109
115
  try {
110
116
  applyInitialMigration(this.db);
117
+ applyIndexMigration(this.db);
111
118
  }
112
119
  catch (err) {
113
120
  throw new CortexError(GRAPH_DB_ERROR, 'critical', 'graph', `Migration failed: ${err instanceof Error ? err.message : String(err)}`, undefined, 'Delete the database and restart.');
@@ -132,28 +139,37 @@ export class SQLiteStore {
132
139
  close() {
133
140
  this.db.close();
134
141
  }
142
+ transaction(fn) {
143
+ return this.db.transaction(fn)();
144
+ }
135
145
  // --- Entities ---
146
+ createEntitySync(entity) {
147
+ return this._createEntity(entity);
148
+ }
136
149
  async createEntity(entity) {
150
+ return this._createEntity(entity);
151
+ }
152
+ _createEntity(entity) {
137
153
  const id = randomUUID();
138
154
  const ts = now();
139
- this.db.prepare(`
140
- INSERT INTO entities (
141
- id, type, name, content, summary, properties, confidence,
142
- source_file, source_start_line, source_end_line,
143
- project_id, extracted_by, tags, status, created_at, updated_at
144
- ) VALUES (
145
- ?, ?, ?, ?, ?, ?, ?,
146
- ?, ?, ?,
147
- ?, ?, ?, ?, ?, ?
148
- )
155
+ this.db.prepare(`
156
+ INSERT INTO entities (
157
+ id, type, name, content, summary, properties, confidence,
158
+ source_file, source_start_line, source_end_line,
159
+ project_id, extracted_by, tags, status, created_at, updated_at
160
+ ) VALUES (
161
+ ?, ?, ?, ?, ?, ?, ?,
162
+ ?, ?, ?,
163
+ ?, ?, ?, ?, ?, ?
164
+ )
149
165
  `).run(id, entity.type, entity.name, entity.content, entity.summary ?? null, JSON.stringify(entity.properties), entity.confidence, entity.sourceFile, entity.sourceRange?.startLine ?? null, entity.sourceRange?.endLine ?? null, entity.projectId, JSON.stringify(entity.extractedBy), JSON.stringify(entity.tags), entity.status, ts, ts);
150
166
  // Sync to FTS
151
- this.db.prepare(`
152
- INSERT INTO entities_fts (rowid, name, content, summary, tags)
153
- VALUES (
154
- (SELECT rowid FROM entities WHERE id = ?),
155
- ?, ?, ?, ?
156
- )
167
+ this.db.prepare(`
168
+ INSERT INTO entities_fts (rowid, name, content, summary, tags)
169
+ VALUES (
170
+ (SELECT rowid FROM entities WHERE id = ?),
171
+ ?, ?, ?, ?
172
+ )
157
173
  `).run(id, entity.name, entity.content, entity.summary ?? '', entity.tags.join(' '));
158
174
  return { ...entity, id, createdAt: ts, updatedAt: ts };
159
175
  }
@@ -167,18 +183,18 @@ export class SQLiteStore {
167
183
  throw new CortexError(GRAPH_ENTITY_NOT_FOUND, 'low', 'graph', `Entity not found: ${id}`, { entityId: id });
168
184
  }
169
185
  const merged = { ...existing, ...updates, updatedAt: now() };
170
- this.db.prepare(`
171
- UPDATE entities SET
172
- type = ?, name = ?, content = ?, summary = ?,
173
- properties = ?, confidence = ?,
174
- source_file = ?, source_start_line = ?, source_end_line = ?,
175
- extracted_by = ?, tags = ?, status = ?, updated_at = ?
176
- WHERE id = ?
186
+ this.db.prepare(`
187
+ UPDATE entities SET
188
+ type = ?, name = ?, content = ?, summary = ?,
189
+ properties = ?, confidence = ?,
190
+ source_file = ?, source_start_line = ?, source_end_line = ?,
191
+ extracted_by = ?, tags = ?, status = ?, updated_at = ?
192
+ WHERE id = ?
177
193
  `).run(merged.type, merged.name, merged.content, merged.summary ?? null, JSON.stringify(merged.properties), merged.confidence, merged.sourceFile, merged.sourceRange?.startLine ?? null, merged.sourceRange?.endLine ?? null, JSON.stringify(merged.extractedBy), JSON.stringify(merged.tags), merged.status, merged.updatedAt, id);
178
194
  // Re-sync FTS
179
- this.db.prepare(`
180
- UPDATE entities_fts SET name = ?, content = ?, summary = ?, tags = ?
181
- WHERE rowid = (SELECT rowid FROM entities WHERE id = ?)
195
+ this.db.prepare(`
196
+ UPDATE entities_fts SET name = ?, content = ?, summary = ?, tags = ?
197
+ WHERE rowid = (SELECT rowid FROM entities WHERE id = ?)
182
198
  `).run(merged.name, merged.content, merged.summary ?? '', merged.tags.join(' '), id);
183
199
  return merged;
184
200
  }
@@ -217,20 +233,25 @@ export class SQLiteStore {
217
233
  }
218
234
  let sql;
219
235
  if (query.search) {
236
+ // Sanitize FTS input: strip operators to prevent FTS5 injection
237
+ const sanitizedSearch = query.search.replace(/[^a-zA-Z0-9\s]/g, ' ').trim();
238
+ if (!sanitizedSearch) {
239
+ return [];
240
+ }
220
241
  // Use FTS for text search
221
- sql = `
222
- SELECT e.* FROM entities e
223
- JOIN entities_fts fts ON fts.rowid = e.rowid
224
- WHERE fts.entities_fts MATCH ? AND ${conditions.join(' AND ')}
225
- ORDER BY rank
242
+ sql = `
243
+ SELECT e.* FROM entities e
244
+ JOIN entities_fts fts ON fts.rowid = e.rowid
245
+ WHERE fts.entities_fts MATCH ? AND ${conditions.join(' AND ')}
246
+ ORDER BY rank
226
247
  `;
227
- params.unshift(query.search);
248
+ params.unshift(sanitizedSearch);
228
249
  }
229
250
  else {
230
- sql = `
231
- SELECT * FROM entities
232
- WHERE ${conditions.join(' AND ')}
233
- ORDER BY created_at DESC
251
+ sql = `
252
+ SELECT * FROM entities
253
+ WHERE ${conditions.join(' AND ')}
254
+ ORDER BY created_at DESC
234
255
  `;
235
256
  }
236
257
  if (query.limit) {
@@ -248,12 +269,12 @@ export class SQLiteStore {
248
269
  async createRelationship(rel) {
249
270
  const id = randomUUID();
250
271
  const ts = now();
251
- this.db.prepare(`
252
- INSERT INTO relationships (
253
- id, type, source_entity_id, target_entity_id,
254
- description, confidence, properties, extracted_by,
255
- created_at, updated_at
256
- ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
272
+ this.db.prepare(`
273
+ INSERT INTO relationships (
274
+ id, type, source_entity_id, target_entity_id,
275
+ description, confidence, properties, extracted_by,
276
+ created_at, updated_at
277
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
257
278
  `).run(id, rel.type, rel.sourceEntityId, rel.targetEntityId, rel.description ?? null, rel.confidence, JSON.stringify(rel.properties), JSON.stringify(rel.extractedBy), ts, ts);
258
279
  return { ...rel, id, createdAt: ts, updatedAt: ts };
259
280
  }
@@ -261,24 +282,37 @@ export class SQLiteStore {
261
282
  const row = this.db.prepare('SELECT * FROM relationships WHERE id = ?').get(id);
262
283
  return row ? rowToRelationship(row) : null;
263
284
  }
264
- async getRelationshipsForEntity(entityId, direction = 'both') {
285
+ async getRelationshipsForEntity(entityId, direction = 'both', limit = 200) {
265
286
  let sql;
266
287
  let params;
267
288
  if (direction === 'out') {
268
- sql = 'SELECT * FROM relationships WHERE source_entity_id = ?';
269
- params = [entityId];
289
+ sql = 'SELECT * FROM relationships WHERE source_entity_id = ? LIMIT ?';
290
+ params = [entityId, limit];
270
291
  }
271
292
  else if (direction === 'in') {
272
- sql = 'SELECT * FROM relationships WHERE target_entity_id = ?';
273
- params = [entityId];
293
+ sql = 'SELECT * FROM relationships WHERE target_entity_id = ? LIMIT ?';
294
+ params = [entityId, limit];
274
295
  }
275
296
  else {
276
- sql = 'SELECT * FROM relationships WHERE source_entity_id = ? OR target_entity_id = ?';
277
- params = [entityId, entityId];
297
+ sql = 'SELECT * FROM relationships WHERE source_entity_id = ? OR target_entity_id = ? LIMIT ?';
298
+ params = [entityId, entityId, limit];
278
299
  }
279
300
  const rows = this.db.prepare(sql).all(...params);
280
301
  return rows.map(rowToRelationship);
281
302
  }
303
+ async getRelationshipsForEntities(entityIds) {
304
+ if (entityIds.length === 0)
305
+ return [];
306
+ const placeholders = entityIds.map(() => '?').join(',');
307
+ const sql = `
308
+ SELECT * FROM relationships
309
+ WHERE source_entity_id IN (${placeholders})
310
+ OR target_entity_id IN (${placeholders})
311
+ LIMIT 2000
312
+ `;
313
+ const rows = this.db.prepare(sql).all(...entityIds, ...entityIds);
314
+ return rows.map(rowToRelationship);
315
+ }
282
316
  async deleteRelationship(id) {
283
317
  this.db.prepare('DELETE FROM relationships WHERE id = ?').run(id);
284
318
  }
@@ -288,14 +322,14 @@ export class SQLiteStore {
288
322
  const escaped = normalized.replace(/[%_\\]/g, '\\$&');
289
323
  const pattern = escaped + '%';
290
324
  return this.db.transaction(() => {
291
- const relResult = this.db.prepare(`
292
- DELETE FROM relationships
293
- WHERE source_entity_id IN (SELECT id FROM entities WHERE source_file LIKE ? ESCAPE '\\')
294
- OR target_entity_id IN (SELECT id FROM entities WHERE source_file LIKE ? ESCAPE '\\')
325
+ const relResult = this.db.prepare(`
326
+ DELETE FROM relationships
327
+ WHERE source_entity_id IN (SELECT id FROM entities WHERE source_file LIKE ? ESCAPE '\\')
328
+ OR target_entity_id IN (SELECT id FROM entities WHERE source_file LIKE ? ESCAPE '\\')
295
329
  `).run(pattern, pattern);
296
- this.db.prepare(`
297
- DELETE FROM entities_fts
298
- WHERE rowid IN (SELECT rowid FROM entities WHERE source_file LIKE ? ESCAPE '\\' AND deleted_at IS NULL)
330
+ this.db.prepare(`
331
+ DELETE FROM entities_fts
332
+ WHERE rowid IN (SELECT rowid FROM entities WHERE source_file LIKE ? ESCAPE '\\' AND deleted_at IS NULL)
299
333
  `).run(pattern);
300
334
  const entityResult = this.db.prepare("DELETE FROM entities WHERE source_file LIKE ? ESCAPE '\\'").run(pattern);
301
335
  const fileResult = this.db.prepare("DELETE FROM files WHERE path LIKE ? ESCAPE '\\'").run(pattern);
@@ -317,14 +351,14 @@ export class SQLiteStore {
317
351
  }
318
352
  pruneSoftDeleted() {
319
353
  return this.db.transaction(() => {
320
- const relResult = this.db.prepare(`
321
- DELETE FROM relationships
322
- WHERE source_entity_id IN (SELECT id FROM entities WHERE deleted_at IS NOT NULL)
323
- OR target_entity_id IN (SELECT id FROM entities WHERE deleted_at IS NOT NULL)
354
+ const relResult = this.db.prepare(`
355
+ DELETE FROM relationships
356
+ WHERE source_entity_id IN (SELECT id FROM entities WHERE deleted_at IS NOT NULL)
357
+ OR target_entity_id IN (SELECT id FROM entities WHERE deleted_at IS NOT NULL)
324
358
  `).run();
325
- this.db.prepare(`
326
- DELETE FROM entities_fts
327
- WHERE rowid IN (SELECT rowid FROM entities WHERE deleted_at IS NOT NULL)
359
+ this.db.prepare(`
360
+ DELETE FROM entities_fts
361
+ WHERE rowid IN (SELECT rowid FROM entities WHERE deleted_at IS NOT NULL)
328
362
  `).run();
329
363
  const entityResult = this.db.prepare('DELETE FROM entities WHERE deleted_at IS NOT NULL').run();
330
364
  return {
@@ -337,22 +371,22 @@ export class SQLiteStore {
337
371
  async upsertFile(file) {
338
372
  const existing = this.db.prepare('SELECT * FROM files WHERE path = ?').get(file.path);
339
373
  if (existing) {
340
- this.db.prepare(`
341
- UPDATE files SET
342
- relative_path = ?, project_id = ?, content_hash = ?,
343
- file_type = ?, size_bytes = ?, last_modified = ?,
344
- last_ingested_at = ?, entity_ids = ?, status = ?, parse_error = ?
345
- WHERE path = ?
374
+ this.db.prepare(`
375
+ UPDATE files SET
376
+ relative_path = ?, project_id = ?, content_hash = ?,
377
+ file_type = ?, size_bytes = ?, last_modified = ?,
378
+ last_ingested_at = ?, entity_ids = ?, status = ?, parse_error = ?
379
+ WHERE path = ?
346
380
  `).run(file.relativePath, file.projectId, file.contentHash, file.fileType, file.sizeBytes, file.lastModified, file.lastIngestedAt ?? null, JSON.stringify(file.entityIds), file.status, file.parseError ?? null, file.path);
347
381
  return { ...file, id: existing.id };
348
382
  }
349
383
  const id = randomUUID();
350
- this.db.prepare(`
351
- INSERT INTO files (
352
- id, path, relative_path, project_id, content_hash,
353
- file_type, size_bytes, last_modified, last_ingested_at,
354
- entity_ids, status, parse_error
355
- ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
384
+ this.db.prepare(`
385
+ INSERT INTO files (
386
+ id, path, relative_path, project_id, content_hash,
387
+ file_type, size_bytes, last_modified, last_ingested_at,
388
+ entity_ids, status, parse_error
389
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
356
390
  `).run(id, file.path, file.relativePath, file.projectId, file.contentHash, file.fileType, file.sizeBytes, file.lastModified, file.lastIngestedAt ?? null, JSON.stringify(file.entityIds), file.status, file.parseError ?? null);
357
391
  return { ...file, id };
358
392
  }
@@ -368,11 +402,11 @@ export class SQLiteStore {
368
402
  async createProject(project) {
369
403
  const id = randomUUID();
370
404
  const ts = now();
371
- this.db.prepare(`
372
- INSERT INTO projects (
373
- id, name, root_path, privacy_level,
374
- file_count, entity_count, last_ingested_at, created_at
375
- ) VALUES (?, ?, ?, ?, ?, ?, ?, ?)
405
+ this.db.prepare(`
406
+ INSERT INTO projects (
407
+ id, name, root_path, privacy_level,
408
+ file_count, entity_count, last_ingested_at, created_at
409
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?)
376
410
  `).run(id, project.name, project.rootPath, project.privacyLevel, project.fileCount, project.entityCount, project.lastIngestedAt ?? null, ts);
377
411
  return { ...project, id, createdAt: ts };
378
412
  }
@@ -387,11 +421,11 @@ export class SQLiteStore {
387
421
  // --- Contradictions ---
388
422
  async createContradiction(contradiction) {
389
423
  const id = randomUUID();
390
- this.db.prepare(`
391
- INSERT INTO contradictions (
392
- id, entity_id_a, entity_id_b, description, severity,
393
- suggested_resolution, status, resolved_action, resolved_at, detected_at
394
- ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
424
+ this.db.prepare(`
425
+ INSERT INTO contradictions (
426
+ id, entity_id_a, entity_id_b, description, severity,
427
+ suggested_resolution, status, resolved_action, resolved_at, detected_at
428
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
395
429
  `).run(id, contradiction.entityIds[0], contradiction.entityIds[1], contradiction.description, contradiction.severity, contradiction.suggestedResolution ?? null, contradiction.status, contradiction.resolvedAction ?? null, contradiction.resolvedAt ?? null, contradiction.detectedAt);
396
430
  return { ...contradiction, id };
397
431
  }
@@ -416,8 +450,8 @@ export class SQLiteStore {
416
450
  return rows.map(rowToContradiction);
417
451
  }
418
452
  async updateContradiction(id, update) {
419
- this.db.prepare(`
420
- UPDATE contradictions SET status = ?, resolved_action = ?, resolved_at = ? WHERE id = ?
453
+ this.db.prepare(`
454
+ UPDATE contradictions SET status = ?, resolved_action = ?, resolved_at = ? WHERE id = ?
421
455
  `).run(update.status, update.resolvedAction ?? null, update.resolvedAt ?? null, id);
422
456
  }
423
457
  // --- Search ---
@@ -426,12 +460,12 @@ export class SQLiteStore {
426
460
  const sanitized = text.replace(/[^a-zA-Z0-9\s]/g, ' ').trim();
427
461
  if (!sanitized)
428
462
  return [];
429
- const rows = this.db.prepare(`
430
- SELECT e.* FROM entities e
431
- JOIN entities_fts fts ON fts.rowid = e.rowid
432
- WHERE fts.entities_fts MATCH ? AND e.deleted_at IS NULL
433
- ORDER BY rank
434
- LIMIT ?
463
+ const rows = this.db.prepare(`
464
+ SELECT e.* FROM entities e
465
+ JOIN entities_fts fts ON fts.rowid = e.rowid
466
+ WHERE fts.entities_fts MATCH ? AND e.deleted_at IS NULL
467
+ ORDER BY rank
468
+ LIMIT ?
435
469
  `).all(sanitized, limit);
436
470
  return rows.map(rowToEntity);
437
471
  }
@@ -476,13 +510,13 @@ export class SQLiteStore {
476
510
  }
477
511
  }
478
512
  // Failed files with error messages
479
- const failedFiles = this.db.prepare(`SELECT path, relative_path, parse_error FROM files
480
- WHERE status = 'failed' AND parse_error IS NOT NULL
513
+ const failedFiles = this.db.prepare(`SELECT path, relative_path, parse_error FROM files
514
+ WHERE status = 'failed' AND parse_error IS NOT NULL
481
515
  ORDER BY path LIMIT 50`).all()
482
516
  .map((r) => ({ path: r.path, relativePath: r.relative_path, parseError: r.parse_error }));
483
517
  // Entity breakdown by type (active only)
484
- const entityRows = this.db.prepare(`SELECT type, COUNT(*) as count, AVG(confidence) as avg_confidence
485
- FROM entities WHERE deleted_at IS NULL AND status = 'active'
518
+ const entityRows = this.db.prepare(`SELECT type, COUNT(*) as count, AVG(confidence) as avg_confidence
519
+ FROM entities WHERE deleted_at IS NULL AND status = 'active'
486
520
  GROUP BY type ORDER BY count DESC`).all();
487
521
  const entityBreakdown = entityRows.map((r) => ({
488
522
  type: r.type, count: r.count, avgConfidence: r.avg_confidence,
@@ -513,14 +547,14 @@ export class SQLiteStore {
513
547
  contradictions.lowSeverity += r.count;
514
548
  }
515
549
  // Top active contradictions (high first, then medium, limit 10)
516
- const topContrRows = this.db.prepare(`SELECT c.id, c.severity, c.description, ea.name as entity_a, eb.name as entity_b
517
- FROM contradictions c
518
- LEFT JOIN entities ea ON c.entity_id_a = ea.id
519
- LEFT JOIN entities eb ON c.entity_id_b = eb.id
520
- WHERE c.status = 'active'
521
- ORDER BY CASE c.severity
522
- WHEN 'critical' THEN 0 WHEN 'high' THEN 1 WHEN 'medium' THEN 2 ELSE 3
523
- END, c.detected_at DESC
550
+ const topContrRows = this.db.prepare(`SELECT c.id, c.severity, c.description, ea.name as entity_a, eb.name as entity_b
551
+ FROM contradictions c
552
+ LEFT JOIN entities ea ON c.entity_id_a = ea.id
553
+ LEFT JOIN entities eb ON c.entity_id_b = eb.id
554
+ WHERE c.status = 'active'
555
+ ORDER BY CASE c.severity
556
+ WHEN 'critical' THEN 0 WHEN 'high' THEN 1 WHEN 'medium' THEN 2 ELSE 3
557
+ END, c.detected_at DESC
524
558
  LIMIT 10`).all();
525
559
  const topContradictions = topContrRows.map((r) => ({
526
560
  id: r.id.slice(0, 8),
@@ -530,9 +564,9 @@ export class SQLiteStore {
530
564
  entityB: r.entity_b ?? 'unknown',
531
565
  }));
532
566
  // Token estimate from entity extracted_by JSON
533
- const tokenRow = this.db.prepare(`SELECT
534
- SUM(CAST(JSON_EXTRACT(extracted_by, '$.tokensUsed.input') AS INTEGER)) as total_input,
535
- SUM(CAST(JSON_EXTRACT(extracted_by, '$.tokensUsed.output') AS INTEGER)) as total_output
567
+ const tokenRow = this.db.prepare(`SELECT
568
+ SUM(CAST(JSON_EXTRACT(extracted_by, '$.tokensUsed.input') AS INTEGER)) as total_input,
569
+ SUM(CAST(JSON_EXTRACT(extracted_by, '$.tokensUsed.output') AS INTEGER)) as total_output
536
570
  FROM entities WHERE deleted_at IS NULL`).get();
537
571
  return {
538
572
  generatedAt: new Date().toISOString(),
@@ -562,18 +596,18 @@ export class SQLiteStore {
562
596
  async integrityCheck() {
563
597
  const details = [];
564
598
  // Check for orphaned relationships
565
- const orphanedRels = this.db.prepare(`
566
- SELECT COUNT(*) as count FROM relationships r
567
- WHERE NOT EXISTS (SELECT 1 FROM entities WHERE id = r.source_entity_id)
568
- OR NOT EXISTS (SELECT 1 FROM entities WHERE id = r.target_entity_id)
599
+ const orphanedRels = this.db.prepare(`
600
+ SELECT COUNT(*) as count FROM relationships r
601
+ WHERE NOT EXISTS (SELECT 1 FROM entities WHERE id = r.source_entity_id)
602
+ OR NOT EXISTS (SELECT 1 FROM entities WHERE id = r.target_entity_id)
569
603
  `).get().count;
570
604
  if (orphanedRels > 0) {
571
605
  details.push(`Found ${orphanedRels} orphaned relationships`);
572
606
  }
573
607
  // Check for files referencing missing projects
574
- const missingProjects = this.db.prepare(`
575
- SELECT COUNT(*) as count FROM files f
576
- WHERE NOT EXISTS (SELECT 1 FROM projects WHERE id = f.project_id)
608
+ const missingProjects = this.db.prepare(`
609
+ SELECT COUNT(*) as count FROM files f
610
+ WHERE NOT EXISTS (SELECT 1 FROM projects WHERE id = f.project_id)
577
611
  `).get().count;
578
612
  if (missingProjects > 0) {
579
613
  details.push(`Found ${missingProjects} files referencing missing projects`);
@@ -604,8 +638,8 @@ export class SQLiteStore {
604
638
  params.push(limit);
605
639
  const entityRows = this.db.prepare(entitySql).all(...params);
606
640
  const entityIds = new Set(entityRows.map(e => e.id));
607
- const relRows = this.db.prepare(`SELECT id, type, source_entity_id, target_entity_id, confidence
608
- FROM relationships
641
+ const relRows = this.db.prepare(`SELECT id, type, source_entity_id, target_entity_id, confidence
642
+ FROM relationships
609
643
  LIMIT ?`).all(limit * 2);
610
644
  // Only include edges where both endpoints are in our node set
611
645
  const edges = relRows