@danielsimonjr/memory-mcp 0.48.0 → 9.8.2

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 (210) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +2000 -194
  3. package/dist/__tests__/file-path.test.js +7 -11
  4. package/dist/__tests__/knowledge-graph.test.js +3 -8
  5. package/dist/core/EntityManager.d.ts +266 -0
  6. package/dist/core/EntityManager.d.ts.map +1 -0
  7. package/dist/core/EntityManager.js +89 -137
  8. package/dist/core/GraphEventEmitter.d.ts +202 -0
  9. package/dist/core/GraphEventEmitter.d.ts.map +1 -0
  10. package/dist/core/GraphEventEmitter.js +346 -0
  11. package/dist/core/GraphStorage.d.ts +395 -0
  12. package/dist/core/GraphStorage.d.ts.map +1 -0
  13. package/dist/core/GraphStorage.js +644 -31
  14. package/dist/core/GraphTraversal.d.ts +141 -0
  15. package/dist/core/GraphTraversal.d.ts.map +1 -0
  16. package/dist/core/GraphTraversal.js +573 -0
  17. package/dist/core/HierarchyManager.d.ts +111 -0
  18. package/dist/core/HierarchyManager.d.ts.map +1 -0
  19. package/dist/{features → core}/HierarchyManager.js +14 -9
  20. package/dist/core/ManagerContext.d.ts +72 -0
  21. package/dist/core/ManagerContext.d.ts.map +1 -0
  22. package/dist/core/ManagerContext.js +118 -0
  23. package/dist/core/ObservationManager.d.ts +85 -0
  24. package/dist/core/ObservationManager.d.ts.map +1 -0
  25. package/dist/core/ObservationManager.js +51 -57
  26. package/dist/core/RelationManager.d.ts +131 -0
  27. package/dist/core/RelationManager.d.ts.map +1 -0
  28. package/dist/core/RelationManager.js +31 -7
  29. package/dist/core/SQLiteStorage.d.ts +354 -0
  30. package/dist/core/SQLiteStorage.d.ts.map +1 -0
  31. package/dist/core/SQLiteStorage.js +918 -0
  32. package/dist/core/StorageFactory.d.ts +45 -0
  33. package/dist/core/StorageFactory.d.ts.map +1 -0
  34. package/dist/core/StorageFactory.js +64 -0
  35. package/dist/core/TransactionManager.d.ts +464 -0
  36. package/dist/core/TransactionManager.d.ts.map +1 -0
  37. package/dist/core/TransactionManager.js +493 -14
  38. package/dist/core/index.d.ts +17 -0
  39. package/dist/core/index.d.ts.map +1 -0
  40. package/dist/core/index.js +12 -2
  41. package/dist/features/AnalyticsManager.d.ts +44 -0
  42. package/dist/features/AnalyticsManager.d.ts.map +1 -0
  43. package/dist/features/AnalyticsManager.js +3 -2
  44. package/dist/features/ArchiveManager.d.ts +133 -0
  45. package/dist/features/ArchiveManager.d.ts.map +1 -0
  46. package/dist/features/ArchiveManager.js +221 -14
  47. package/dist/features/CompressionManager.d.ts +117 -0
  48. package/dist/features/CompressionManager.d.ts.map +1 -0
  49. package/dist/features/CompressionManager.js +189 -20
  50. package/dist/features/IOManager.d.ts +225 -0
  51. package/dist/features/IOManager.d.ts.map +1 -0
  52. package/dist/features/IOManager.js +1092 -0
  53. package/dist/features/StreamingExporter.d.ts +128 -0
  54. package/dist/features/StreamingExporter.d.ts.map +1 -0
  55. package/dist/features/StreamingExporter.js +211 -0
  56. package/dist/features/TagManager.d.ts +147 -0
  57. package/dist/features/TagManager.d.ts.map +1 -0
  58. package/dist/features/index.d.ts +12 -0
  59. package/dist/features/index.d.ts.map +1 -0
  60. package/dist/features/index.js +5 -6
  61. package/dist/index.d.ts +9 -0
  62. package/dist/index.d.ts.map +1 -0
  63. package/dist/index.js +10 -10
  64. package/dist/memory.jsonl +1 -26
  65. package/dist/search/BasicSearch.d.ts +51 -0
  66. package/dist/search/BasicSearch.d.ts.map +1 -0
  67. package/dist/search/BasicSearch.js +9 -3
  68. package/dist/search/BooleanSearch.d.ts +98 -0
  69. package/dist/search/BooleanSearch.d.ts.map +1 -0
  70. package/dist/search/BooleanSearch.js +156 -9
  71. package/dist/search/EmbeddingService.d.ts +178 -0
  72. package/dist/search/EmbeddingService.d.ts.map +1 -0
  73. package/dist/search/EmbeddingService.js +358 -0
  74. package/dist/search/FuzzySearch.d.ts +118 -0
  75. package/dist/search/FuzzySearch.d.ts.map +1 -0
  76. package/dist/search/FuzzySearch.js +241 -25
  77. package/dist/search/QueryCostEstimator.d.ts +111 -0
  78. package/dist/search/QueryCostEstimator.d.ts.map +1 -0
  79. package/dist/search/QueryCostEstimator.js +355 -0
  80. package/dist/search/RankedSearch.d.ts +71 -0
  81. package/dist/search/RankedSearch.d.ts.map +1 -0
  82. package/dist/search/RankedSearch.js +54 -6
  83. package/dist/search/SavedSearchManager.d.ts +79 -0
  84. package/dist/search/SavedSearchManager.d.ts.map +1 -0
  85. package/dist/search/SavedSearchManager.js +3 -2
  86. package/dist/search/SearchFilterChain.d.ts +120 -0
  87. package/dist/search/SearchFilterChain.d.ts.map +1 -0
  88. package/dist/search/SearchFilterChain.js +2 -4
  89. package/dist/search/SearchManager.d.ts +326 -0
  90. package/dist/search/SearchManager.d.ts.map +1 -0
  91. package/dist/search/SearchManager.js +148 -0
  92. package/dist/search/SearchSuggestions.d.ts +27 -0
  93. package/dist/search/SearchSuggestions.d.ts.map +1 -0
  94. package/dist/search/SearchSuggestions.js +1 -1
  95. package/dist/search/SemanticSearch.d.ts +149 -0
  96. package/dist/search/SemanticSearch.d.ts.map +1 -0
  97. package/dist/search/SemanticSearch.js +323 -0
  98. package/dist/search/TFIDFEventSync.d.ts +85 -0
  99. package/dist/search/TFIDFEventSync.d.ts.map +1 -0
  100. package/dist/search/TFIDFEventSync.js +133 -0
  101. package/dist/search/TFIDFIndexManager.d.ts +151 -0
  102. package/dist/search/TFIDFIndexManager.d.ts.map +1 -0
  103. package/dist/search/TFIDFIndexManager.js +232 -17
  104. package/dist/search/VectorStore.d.ts +235 -0
  105. package/dist/search/VectorStore.d.ts.map +1 -0
  106. package/dist/search/VectorStore.js +311 -0
  107. package/dist/search/index.d.ts +21 -0
  108. package/dist/search/index.d.ts.map +1 -0
  109. package/dist/search/index.js +12 -0
  110. package/dist/server/MCPServer.d.ts +21 -0
  111. package/dist/server/MCPServer.d.ts.map +1 -0
  112. package/dist/server/MCPServer.js +4 -4
  113. package/dist/server/responseCompressor.d.ts +94 -0
  114. package/dist/server/responseCompressor.d.ts.map +1 -0
  115. package/dist/server/responseCompressor.js +127 -0
  116. package/dist/server/toolDefinitions.d.ts +27 -0
  117. package/dist/server/toolDefinitions.d.ts.map +1 -0
  118. package/dist/server/toolDefinitions.js +188 -17
  119. package/dist/server/toolHandlers.d.ts +41 -0
  120. package/dist/server/toolHandlers.d.ts.map +1 -0
  121. package/dist/server/toolHandlers.js +469 -75
  122. package/dist/types/index.d.ts +13 -0
  123. package/dist/types/index.d.ts.map +1 -0
  124. package/dist/types/index.js +1 -1
  125. package/dist/types/types.d.ts +1654 -0
  126. package/dist/types/types.d.ts.map +1 -0
  127. package/dist/types/types.js +9 -0
  128. package/dist/utils/compressedCache.d.ts +192 -0
  129. package/dist/utils/compressedCache.d.ts.map +1 -0
  130. package/dist/utils/compressedCache.js +309 -0
  131. package/dist/utils/compressionUtil.d.ts +214 -0
  132. package/dist/utils/compressionUtil.d.ts.map +1 -0
  133. package/dist/utils/compressionUtil.js +247 -0
  134. package/dist/utils/constants.d.ts +245 -0
  135. package/dist/utils/constants.d.ts.map +1 -0
  136. package/dist/utils/constants.js +124 -0
  137. package/dist/utils/entityUtils.d.ts +354 -0
  138. package/dist/utils/entityUtils.d.ts.map +1 -0
  139. package/dist/utils/entityUtils.js +511 -4
  140. package/dist/utils/errors.d.ts +95 -0
  141. package/dist/utils/errors.d.ts.map +1 -0
  142. package/dist/utils/errors.js +24 -0
  143. package/dist/utils/formatters.d.ts +145 -0
  144. package/dist/utils/formatters.d.ts.map +1 -0
  145. package/dist/utils/{paginationUtils.js → formatters.js} +54 -3
  146. package/dist/utils/index.d.ts +23 -0
  147. package/dist/utils/index.d.ts.map +1 -0
  148. package/dist/utils/index.js +71 -31
  149. package/dist/utils/indexes.d.ts +270 -0
  150. package/dist/utils/indexes.d.ts.map +1 -0
  151. package/dist/utils/indexes.js +526 -0
  152. package/dist/utils/logger.d.ts +24 -0
  153. package/dist/utils/logger.d.ts.map +1 -0
  154. package/dist/utils/operationUtils.d.ts +124 -0
  155. package/dist/utils/operationUtils.d.ts.map +1 -0
  156. package/dist/utils/operationUtils.js +175 -0
  157. package/dist/utils/parallelUtils.d.ts +76 -0
  158. package/dist/utils/parallelUtils.d.ts.map +1 -0
  159. package/dist/utils/parallelUtils.js +191 -0
  160. package/dist/utils/schemas.d.ts +374 -0
  161. package/dist/utils/schemas.d.ts.map +1 -0
  162. package/dist/utils/schemas.js +307 -7
  163. package/dist/utils/searchAlgorithms.d.ts +99 -0
  164. package/dist/utils/searchAlgorithms.d.ts.map +1 -0
  165. package/dist/utils/searchAlgorithms.js +167 -0
  166. package/dist/utils/searchCache.d.ts +108 -0
  167. package/dist/utils/searchCache.d.ts.map +1 -0
  168. package/dist/utils/taskScheduler.d.ts +294 -0
  169. package/dist/utils/taskScheduler.d.ts.map +1 -0
  170. package/dist/utils/taskScheduler.js +486 -0
  171. package/dist/workers/index.d.ts +12 -0
  172. package/dist/workers/index.d.ts.map +1 -0
  173. package/dist/workers/index.js +9 -0
  174. package/dist/workers/levenshteinWorker.d.ts +60 -0
  175. package/dist/workers/levenshteinWorker.d.ts.map +1 -0
  176. package/dist/workers/levenshteinWorker.js +98 -0
  177. package/package.json +17 -4
  178. package/dist/__tests__/edge-cases/edge-cases.test.js +0 -406
  179. package/dist/__tests__/integration/workflows.test.js +0 -449
  180. package/dist/__tests__/performance/benchmarks.test.js +0 -413
  181. package/dist/__tests__/unit/core/EntityManager.test.js +0 -334
  182. package/dist/__tests__/unit/core/GraphStorage.test.js +0 -205
  183. package/dist/__tests__/unit/core/RelationManager.test.js +0 -274
  184. package/dist/__tests__/unit/features/CompressionManager.test.js +0 -350
  185. package/dist/__tests__/unit/search/BasicSearch.test.js +0 -311
  186. package/dist/__tests__/unit/search/BooleanSearch.test.js +0 -432
  187. package/dist/__tests__/unit/search/FuzzySearch.test.js +0 -448
  188. package/dist/__tests__/unit/search/RankedSearch.test.js +0 -379
  189. package/dist/__tests__/unit/utils/levenshtein.test.js +0 -77
  190. package/dist/core/KnowledgeGraphManager.js +0 -423
  191. package/dist/features/BackupManager.js +0 -311
  192. package/dist/features/ExportManager.js +0 -305
  193. package/dist/features/ImportExportManager.js +0 -50
  194. package/dist/features/ImportManager.js +0 -328
  195. package/dist/memory-saved-searches.jsonl +0 -0
  196. package/dist/memory-tag-aliases.jsonl +0 -0
  197. package/dist/types/analytics.types.js +0 -6
  198. package/dist/types/entity.types.js +0 -7
  199. package/dist/types/import-export.types.js +0 -7
  200. package/dist/types/search.types.js +0 -7
  201. package/dist/types/tag.types.js +0 -6
  202. package/dist/utils/dateUtils.js +0 -89
  203. package/dist/utils/filterUtils.js +0 -155
  204. package/dist/utils/levenshtein.js +0 -62
  205. package/dist/utils/pathUtils.js +0 -115
  206. package/dist/utils/responseFormatter.js +0 -55
  207. package/dist/utils/tagUtils.js +0 -107
  208. package/dist/utils/tfidf.js +0 -90
  209. package/dist/utils/validationHelper.js +0 -99
  210. package/dist/utils/validationUtils.js +0 -109
@@ -7,8 +7,9 @@
7
7
  *
8
8
  * @module core/TransactionManager
9
9
  */
10
- import { BackupManager } from '../features/BackupManager.js';
10
+ import { IOManager } from '../features/IOManager.js';
11
11
  import { KnowledgeGraphError } from '../utils/errors.js';
12
+ import { checkCancellation, createProgressReporter, createProgress, sanitizeObject } from '../utils/index.js';
12
13
  /**
13
14
  * Types of operations that can be performed in a transaction.
14
15
  */
@@ -52,11 +53,11 @@ export class TransactionManager {
52
53
  storage;
53
54
  operations = [];
54
55
  inTransaction = false;
55
- backupManager;
56
+ ioManager;
56
57
  transactionBackup;
57
58
  constructor(storage) {
58
59
  this.storage = storage;
59
- this.backupManager = new BackupManager(storage);
60
+ this.ioManager = new IOManager(storage);
60
61
  }
61
62
  /**
62
63
  * Begin a new transaction.
@@ -191,7 +192,11 @@ export class TransactionManager {
191
192
  * Creates a backup before applying changes. If any operation fails,
192
193
  * automatically rolls back to the pre-transaction state.
193
194
  *
195
+ * Phase 9B: Supports progress tracking and cancellation via LongRunningOperationOptions.
196
+ *
197
+ * @param options - Optional progress/cancellation options (Phase 9B)
194
198
  * @returns Promise resolving to transaction result
199
+ * @throws {OperationCancelledError} If operation is cancelled via signal (Phase 9B)
195
200
  *
196
201
  * @example
197
202
  * ```typescript
@@ -205,32 +210,63 @@ export class TransactionManager {
205
210
  * } else {
206
211
  * console.error(`Transaction failed: ${result.error}`);
207
212
  * }
213
+ *
214
+ * // With progress tracking (Phase 9B)
215
+ * const result = await txManager.commit({
216
+ * onProgress: (p) => console.log(`${p.percentage}% complete`),
217
+ * });
208
218
  * ```
209
219
  */
210
- async commit() {
220
+ async commit(options) {
211
221
  this.ensureInTransaction();
222
+ // Setup progress reporter
223
+ const reportProgress = createProgressReporter(options?.onProgress);
224
+ const totalOperations = this.operations.length;
225
+ reportProgress?.(createProgress(0, 100, 'commit'));
212
226
  try {
213
- // Create backup for rollback
214
- this.transactionBackup = await this.backupManager.createBackup('Transaction backup (auto-created)');
215
- // Load current graph
216
- const graph = await this.storage.loadGraph();
227
+ // Check for early cancellation (inside try block to handle gracefully)
228
+ checkCancellation(options?.signal, 'commit');
229
+ // Phase 1: Create backup for rollback (0-20% progress)
230
+ reportProgress?.(createProgress(5, 100, 'creating backup'));
231
+ const backupResult = await this.ioManager.createBackup({
232
+ description: 'Transaction backup (auto-created)',
233
+ });
234
+ this.transactionBackup = backupResult.path;
235
+ // Check for cancellation after backup
236
+ checkCancellation(options?.signal, 'commit');
237
+ reportProgress?.(createProgress(20, 100, 'backup created'));
238
+ // Phase 2: Load graph (20-30% progress)
239
+ reportProgress?.(createProgress(25, 100, 'loading graph'));
240
+ const graph = await this.storage.getGraphForMutation();
217
241
  const timestamp = new Date().toISOString();
218
- // Apply all operations
242
+ reportProgress?.(createProgress(30, 100, 'graph loaded'));
243
+ // Phase 3: Apply all operations (30-80% progress)
219
244
  let operationsExecuted = 0;
220
245
  for (const operation of this.operations) {
246
+ // Check for cancellation between operations
247
+ checkCancellation(options?.signal, 'commit');
221
248
  this.applyOperation(graph, operation, timestamp);
222
249
  operationsExecuted++;
250
+ // Map operation progress (0-100%) to overall progress (30-80%)
251
+ const opProgress = totalOperations > 0 ? Math.round(30 + (operationsExecuted / totalOperations) * 50) : 80;
252
+ reportProgress?.(createProgress(opProgress, 100, 'applying operations'));
223
253
  }
224
- // Save the modified graph
254
+ // Check for cancellation before save
255
+ checkCancellation(options?.signal, 'commit');
256
+ // Phase 4: Save the modified graph (80-95% progress)
257
+ reportProgress?.(createProgress(85, 100, 'saving graph'));
225
258
  await this.storage.saveGraph(graph);
259
+ reportProgress?.(createProgress(95, 100, 'graph saved'));
226
260
  // Clean up transaction state
227
261
  this.inTransaction = false;
228
262
  this.operations = [];
229
263
  // Delete the transaction backup (no longer needed)
230
264
  if (this.transactionBackup) {
231
- await this.backupManager.deleteBackup(this.transactionBackup);
265
+ await this.ioManager.deleteBackup(this.transactionBackup);
232
266
  this.transactionBackup = undefined;
233
267
  }
268
+ // Report completion
269
+ reportProgress?.(createProgress(100, 100, 'commit'));
234
270
  return {
235
271
  success: true,
236
272
  operationsExecuted,
@@ -273,10 +309,10 @@ export class TransactionManager {
273
309
  }
274
310
  try {
275
311
  // Restore from backup
276
- await this.backupManager.restoreFromBackup(this.transactionBackup);
312
+ await this.ioManager.restoreFromBackup(this.transactionBackup);
277
313
  // Clean up
278
314
  const backupUsed = this.transactionBackup;
279
- await this.backupManager.deleteBackup(this.transactionBackup);
315
+ await this.ioManager.deleteBackup(this.transactionBackup);
280
316
  this.inTransaction = false;
281
317
  this.operations = [];
282
318
  this.transactionBackup = undefined;
@@ -341,7 +377,8 @@ export class TransactionManager {
341
377
  if (!entity) {
342
378
  throw new KnowledgeGraphError(`Entity "${name}" not found`, 'ENTITY_NOT_FOUND');
343
379
  }
344
- Object.assign(entity, updates);
380
+ // Sanitize updates to prevent prototype pollution
381
+ Object.assign(entity, sanitizeObject(updates));
345
382
  entity.lastModified = timestamp;
346
383
  break;
347
384
  }
@@ -387,3 +424,445 @@ export class TransactionManager {
387
424
  }
388
425
  }
389
426
  }
427
+ // ==================== Phase 10 Sprint 1: BatchTransaction ====================
428
+ /**
429
+ * Phase 10 Sprint 1: Fluent API for building and executing batch transactions.
430
+ *
431
+ * BatchTransaction provides a builder pattern for accumulating multiple
432
+ * graph operations and executing them atomically in a single transaction.
433
+ * This reduces I/O overhead and ensures consistency across related changes.
434
+ *
435
+ * @example
436
+ * ```typescript
437
+ * const storage = new GraphStorage('/data/memory.jsonl');
438
+ * const batch = new BatchTransaction(storage);
439
+ *
440
+ * // Build the batch with fluent API
441
+ * const result = await batch
442
+ * .createEntity({ name: 'Alice', entityType: 'person', observations: ['Developer'] })
443
+ * .createEntity({ name: 'Bob', entityType: 'person', observations: ['Designer'] })
444
+ * .createRelation({ from: 'Alice', to: 'Bob', relationType: 'knows' })
445
+ * .updateEntity('Alice', { importance: 8 })
446
+ * .execute();
447
+ *
448
+ * if (result.success) {
449
+ * console.log(`Batch completed: ${result.operationsExecuted} operations in ${result.executionTimeMs}ms`);
450
+ * }
451
+ * ```
452
+ */
453
+ export class BatchTransaction {
454
+ operations = [];
455
+ storage;
456
+ /**
457
+ * Create a new BatchTransaction instance.
458
+ *
459
+ * @param storage - GraphStorage instance to execute operations against
460
+ */
461
+ constructor(storage) {
462
+ this.storage = storage;
463
+ }
464
+ /**
465
+ * Add a create entity operation to the batch.
466
+ *
467
+ * @param entity - Entity to create (without timestamps)
468
+ * @returns This BatchTransaction for chaining
469
+ *
470
+ * @example
471
+ * ```typescript
472
+ * batch.createEntity({
473
+ * name: 'Alice',
474
+ * entityType: 'person',
475
+ * observations: ['Software engineer'],
476
+ * importance: 8
477
+ * });
478
+ * ```
479
+ */
480
+ createEntity(entity) {
481
+ this.operations.push({ type: 'createEntity', data: entity });
482
+ return this;
483
+ }
484
+ /**
485
+ * Add an update entity operation to the batch.
486
+ *
487
+ * @param name - Name of entity to update
488
+ * @param updates - Partial entity updates
489
+ * @returns This BatchTransaction for chaining
490
+ *
491
+ * @example
492
+ * ```typescript
493
+ * batch.updateEntity('Alice', { importance: 9 });
494
+ * ```
495
+ */
496
+ updateEntity(name, updates) {
497
+ this.operations.push({ type: 'updateEntity', data: { name, updates } });
498
+ return this;
499
+ }
500
+ /**
501
+ * Add a delete entity operation to the batch.
502
+ *
503
+ * @param name - Name of entity to delete
504
+ * @returns This BatchTransaction for chaining
505
+ *
506
+ * @example
507
+ * ```typescript
508
+ * batch.deleteEntity('OldEntity');
509
+ * ```
510
+ */
511
+ deleteEntity(name) {
512
+ this.operations.push({ type: 'deleteEntity', data: { name } });
513
+ return this;
514
+ }
515
+ /**
516
+ * Add a create relation operation to the batch.
517
+ *
518
+ * @param relation - Relation to create (without timestamps)
519
+ * @returns This BatchTransaction for chaining
520
+ *
521
+ * @example
522
+ * ```typescript
523
+ * batch.createRelation({
524
+ * from: 'Alice',
525
+ * to: 'Bob',
526
+ * relationType: 'mentors'
527
+ * });
528
+ * ```
529
+ */
530
+ createRelation(relation) {
531
+ this.operations.push({ type: 'createRelation', data: relation });
532
+ return this;
533
+ }
534
+ /**
535
+ * Add a delete relation operation to the batch.
536
+ *
537
+ * @param from - Source entity name
538
+ * @param to - Target entity name
539
+ * @param relationType - Type of relation
540
+ * @returns This BatchTransaction for chaining
541
+ *
542
+ * @example
543
+ * ```typescript
544
+ * batch.deleteRelation('Alice', 'Bob', 'mentors');
545
+ * ```
546
+ */
547
+ deleteRelation(from, to, relationType) {
548
+ this.operations.push({ type: 'deleteRelation', data: { from, to, relationType } });
549
+ return this;
550
+ }
551
+ /**
552
+ * Add observations to an existing entity.
553
+ *
554
+ * @param name - Name of entity to add observations to
555
+ * @param observations - Observations to add
556
+ * @returns This BatchTransaction for chaining
557
+ *
558
+ * @example
559
+ * ```typescript
560
+ * batch.addObservations('Alice', ['Knows TypeScript', 'Leads team']);
561
+ * ```
562
+ */
563
+ addObservations(name, observations) {
564
+ this.operations.push({ type: 'addObservations', data: { name, observations } });
565
+ return this;
566
+ }
567
+ /**
568
+ * Delete observations from an existing entity.
569
+ *
570
+ * @param name - Name of entity to delete observations from
571
+ * @param observations - Observations to delete
572
+ * @returns This BatchTransaction for chaining
573
+ *
574
+ * @example
575
+ * ```typescript
576
+ * batch.deleteObservations('Alice', ['Old fact']);
577
+ * ```
578
+ */
579
+ deleteObservations(name, observations) {
580
+ this.operations.push({ type: 'deleteObservations', data: { name, observations } });
581
+ return this;
582
+ }
583
+ /**
584
+ * Add multiple operations from an array.
585
+ *
586
+ * @param operations - Array of batch operations
587
+ * @returns This BatchTransaction for chaining
588
+ *
589
+ * @example
590
+ * ```typescript
591
+ * batch.addOperations([
592
+ * { type: 'createEntity', data: { name: 'A', entityType: 'x', observations: [] } },
593
+ * { type: 'createEntity', data: { name: 'B', entityType: 'x', observations: [] } }
594
+ * ]);
595
+ * ```
596
+ */
597
+ addOperations(operations) {
598
+ this.operations.push(...operations);
599
+ return this;
600
+ }
601
+ /**
602
+ * Get the number of operations in this batch.
603
+ *
604
+ * @returns Number of operations queued
605
+ */
606
+ size() {
607
+ return this.operations.length;
608
+ }
609
+ /**
610
+ * Clear all operations from the batch.
611
+ *
612
+ * @returns This BatchTransaction for chaining
613
+ */
614
+ clear() {
615
+ this.operations = [];
616
+ return this;
617
+ }
618
+ /**
619
+ * Get a copy of the operations in this batch.
620
+ *
621
+ * @returns Array of batch operations
622
+ */
623
+ getOperations() {
624
+ return [...this.operations];
625
+ }
626
+ /**
627
+ * Execute all operations in the batch atomically.
628
+ *
629
+ * All operations are applied within a single transaction. If any
630
+ * operation fails, all changes are rolled back (when stopOnError is true).
631
+ *
632
+ * @param options - Batch execution options
633
+ * @returns Promise resolving to batch result
634
+ *
635
+ * @example
636
+ * ```typescript
637
+ * const result = await batch.execute();
638
+ * if (result.success) {
639
+ * console.log(`Created ${result.entitiesCreated} entities`);
640
+ * } else {
641
+ * console.error(`Failed at operation ${result.failedOperationIndex}: ${result.error}`);
642
+ * }
643
+ * ```
644
+ */
645
+ async execute(options = {}) {
646
+ const startTime = Date.now();
647
+ const { stopOnError = true, validateBeforeExecute = true } = options;
648
+ const result = {
649
+ success: true,
650
+ operationsExecuted: 0,
651
+ entitiesCreated: 0,
652
+ entitiesUpdated: 0,
653
+ entitiesDeleted: 0,
654
+ relationsCreated: 0,
655
+ relationsDeleted: 0,
656
+ executionTimeMs: 0,
657
+ };
658
+ if (this.operations.length === 0) {
659
+ result.executionTimeMs = Date.now() - startTime;
660
+ return result;
661
+ }
662
+ // Load graph for mutation
663
+ const graph = await this.storage.getGraphForMutation();
664
+ const timestamp = new Date().toISOString();
665
+ // Optional: Validate all operations before executing
666
+ if (validateBeforeExecute) {
667
+ const validationError = this.validateOperations(graph);
668
+ if (validationError) {
669
+ return {
670
+ ...result,
671
+ success: false,
672
+ error: validationError.message,
673
+ failedOperationIndex: validationError.index,
674
+ executionTimeMs: Date.now() - startTime,
675
+ };
676
+ }
677
+ }
678
+ // Execute operations
679
+ for (let i = 0; i < this.operations.length; i++) {
680
+ const operation = this.operations[i];
681
+ try {
682
+ this.applyBatchOperation(graph, operation, timestamp, result);
683
+ result.operationsExecuted++;
684
+ }
685
+ catch (error) {
686
+ result.success = false;
687
+ result.error = error instanceof Error ? error.message : String(error);
688
+ result.failedOperationIndex = i;
689
+ if (stopOnError) {
690
+ result.executionTimeMs = Date.now() - startTime;
691
+ return result;
692
+ }
693
+ }
694
+ }
695
+ // Save the modified graph if successful (or if stopOnError is false)
696
+ if (result.success || !stopOnError) {
697
+ try {
698
+ await this.storage.saveGraph(graph);
699
+ }
700
+ catch (error) {
701
+ result.success = false;
702
+ result.error = `Failed to save graph: ${error instanceof Error ? error.message : String(error)}`;
703
+ }
704
+ }
705
+ result.executionTimeMs = Date.now() - startTime;
706
+ return result;
707
+ }
708
+ /**
709
+ * Validate all operations before executing.
710
+ * @private
711
+ */
712
+ validateOperations(graph) {
713
+ const entityNames = new Set(graph.entities.map(e => e.name));
714
+ const pendingCreates = new Set();
715
+ const pendingDeletes = new Set();
716
+ for (let i = 0; i < this.operations.length; i++) {
717
+ const op = this.operations[i];
718
+ switch (op.type) {
719
+ case 'createEntity': {
720
+ const name = op.data.name;
721
+ if (entityNames.has(name) && !pendingDeletes.has(name)) {
722
+ return { message: `Entity "${name}" already exists`, index: i };
723
+ }
724
+ if (pendingCreates.has(name)) {
725
+ return { message: `Duplicate create for entity "${name}" in batch`, index: i };
726
+ }
727
+ pendingCreates.add(name);
728
+ break;
729
+ }
730
+ case 'updateEntity':
731
+ case 'addObservations':
732
+ case 'deleteObservations': {
733
+ const name = op.data.name;
734
+ const exists = (entityNames.has(name) || pendingCreates.has(name)) && !pendingDeletes.has(name);
735
+ if (!exists) {
736
+ return { message: `Entity "${name}" not found`, index: i };
737
+ }
738
+ break;
739
+ }
740
+ case 'deleteEntity': {
741
+ const name = op.data.name;
742
+ const exists = (entityNames.has(name) || pendingCreates.has(name)) && !pendingDeletes.has(name);
743
+ if (!exists) {
744
+ return { message: `Entity "${name}" not found for deletion`, index: i };
745
+ }
746
+ pendingDeletes.add(name);
747
+ break;
748
+ }
749
+ case 'createRelation': {
750
+ const { from, to } = op.data;
751
+ const fromExists = (entityNames.has(from) || pendingCreates.has(from)) && !pendingDeletes.has(from);
752
+ const toExists = (entityNames.has(to) || pendingCreates.has(to)) && !pendingDeletes.has(to);
753
+ if (!fromExists) {
754
+ return { message: `Source entity "${from}" not found for relation`, index: i };
755
+ }
756
+ if (!toExists) {
757
+ return { message: `Target entity "${to}" not found for relation`, index: i };
758
+ }
759
+ break;
760
+ }
761
+ case 'deleteRelation': {
762
+ // Relations are validated at execution time
763
+ break;
764
+ }
765
+ }
766
+ }
767
+ return null;
768
+ }
769
+ /**
770
+ * Apply a single batch operation to the graph.
771
+ * @private
772
+ */
773
+ applyBatchOperation(graph, operation, timestamp, result) {
774
+ switch (operation.type) {
775
+ case 'createEntity': {
776
+ const entity = {
777
+ ...operation.data,
778
+ createdAt: timestamp,
779
+ lastModified: timestamp,
780
+ };
781
+ if (graph.entities.some(e => e.name === entity.name)) {
782
+ throw new KnowledgeGraphError(`Entity "${entity.name}" already exists`, 'DUPLICATE_ENTITY');
783
+ }
784
+ graph.entities.push(entity);
785
+ result.entitiesCreated++;
786
+ break;
787
+ }
788
+ case 'updateEntity': {
789
+ const { name, updates } = operation.data;
790
+ const entity = graph.entities.find(e => e.name === name);
791
+ if (!entity) {
792
+ throw new KnowledgeGraphError(`Entity "${name}" not found`, 'ENTITY_NOT_FOUND');
793
+ }
794
+ // Sanitize updates to prevent prototype pollution
795
+ Object.assign(entity, sanitizeObject(updates));
796
+ entity.lastModified = timestamp;
797
+ result.entitiesUpdated++;
798
+ break;
799
+ }
800
+ case 'deleteEntity': {
801
+ const { name } = operation.data;
802
+ const index = graph.entities.findIndex(e => e.name === name);
803
+ if (index === -1) {
804
+ throw new KnowledgeGraphError(`Entity "${name}" not found`, 'ENTITY_NOT_FOUND');
805
+ }
806
+ graph.entities.splice(index, 1);
807
+ // Delete related relations
808
+ graph.relations = graph.relations.filter(r => r.from !== name && r.to !== name);
809
+ result.entitiesDeleted++;
810
+ break;
811
+ }
812
+ case 'createRelation': {
813
+ const relation = {
814
+ ...operation.data,
815
+ createdAt: timestamp,
816
+ lastModified: timestamp,
817
+ };
818
+ const exists = graph.relations.some(r => r.from === relation.from && r.to === relation.to && r.relationType === relation.relationType);
819
+ if (exists) {
820
+ throw new KnowledgeGraphError(`Relation "${relation.from}" -> "${relation.to}" (${relation.relationType}) already exists`, 'DUPLICATE_RELATION');
821
+ }
822
+ graph.relations.push(relation);
823
+ result.relationsCreated++;
824
+ break;
825
+ }
826
+ case 'deleteRelation': {
827
+ const { from, to, relationType } = operation.data;
828
+ const index = graph.relations.findIndex(r => r.from === from && r.to === to && r.relationType === relationType);
829
+ if (index === -1) {
830
+ throw new KnowledgeGraphError(`Relation "${from}" -> "${to}" (${relationType}) not found`, 'RELATION_NOT_FOUND');
831
+ }
832
+ graph.relations.splice(index, 1);
833
+ result.relationsDeleted++;
834
+ break;
835
+ }
836
+ case 'addObservations': {
837
+ const { name, observations } = operation.data;
838
+ const entity = graph.entities.find(e => e.name === name);
839
+ if (!entity) {
840
+ throw new KnowledgeGraphError(`Entity "${name}" not found`, 'ENTITY_NOT_FOUND');
841
+ }
842
+ // Add only new observations
843
+ const existingSet = new Set(entity.observations);
844
+ const newObs = observations.filter((o) => !existingSet.has(o));
845
+ entity.observations.push(...newObs);
846
+ entity.lastModified = timestamp;
847
+ result.entitiesUpdated++;
848
+ break;
849
+ }
850
+ case 'deleteObservations': {
851
+ const { name, observations } = operation.data;
852
+ const entity = graph.entities.find(e => e.name === name);
853
+ if (!entity) {
854
+ throw new KnowledgeGraphError(`Entity "${name}" not found`, 'ENTITY_NOT_FOUND');
855
+ }
856
+ const toDelete = new Set(observations);
857
+ entity.observations = entity.observations.filter((o) => !toDelete.has(o));
858
+ entity.lastModified = timestamp;
859
+ result.entitiesUpdated++;
860
+ break;
861
+ }
862
+ default: {
863
+ const _exhaustiveCheck = operation;
864
+ throw new KnowledgeGraphError(`Unknown batch operation type: ${_exhaustiveCheck.type}`, 'UNKNOWN_OPERATION');
865
+ }
866
+ }
867
+ }
868
+ }
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Core Module Barrel Export
3
+ * Phase 4: Added ObservationManager, HierarchyManager, and GraphTraversal exports
4
+ */
5
+ export { GraphStorage } from './GraphStorage.js';
6
+ export { SQLiteStorage } from './SQLiteStorage.js';
7
+ export { EntityManager } from './EntityManager.js';
8
+ export { RelationManager } from './RelationManager.js';
9
+ export { ObservationManager } from './ObservationManager.js';
10
+ export { HierarchyManager } from './HierarchyManager.js';
11
+ export { ManagerContext } from './ManagerContext.js';
12
+ export { GraphTraversal } from './GraphTraversal.js';
13
+ export { ManagerContext as KnowledgeGraphManager } from './ManagerContext.js';
14
+ export { TransactionManager, OperationType, BatchTransaction, type TransactionOperation, type TransactionResult, } from './TransactionManager.js';
15
+ export { createStorage, createStorageFromPath } from './StorageFactory.js';
16
+ export { GraphEventEmitter } from './GraphEventEmitter.js';
17
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/core/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AACvD,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAC7D,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AACzD,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAErD,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAErD,OAAO,EAAE,cAAc,IAAI,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAC9E,OAAO,EACL,kBAAkB,EAClB,aAAa,EACb,gBAAgB,EAChB,KAAK,oBAAoB,EACzB,KAAK,iBAAiB,GACvB,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAE,aAAa,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAE3E,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC"}
@@ -1,9 +1,19 @@
1
1
  /**
2
2
  * Core Module Barrel Export
3
+ * Phase 4: Added ObservationManager, HierarchyManager, and GraphTraversal exports
3
4
  */
4
5
  export { GraphStorage } from './GraphStorage.js';
6
+ export { SQLiteStorage } from './SQLiteStorage.js';
5
7
  export { EntityManager } from './EntityManager.js';
6
8
  export { RelationManager } from './RelationManager.js';
7
9
  export { ObservationManager } from './ObservationManager.js';
8
- export { KnowledgeGraphManager } from './KnowledgeGraphManager.js';
9
- export { TransactionManager, OperationType, } from './TransactionManager.js';
10
+ export { HierarchyManager } from './HierarchyManager.js';
11
+ export { ManagerContext } from './ManagerContext.js';
12
+ // Phase 4 Sprint 6-8: Graph traversal algorithms
13
+ export { GraphTraversal } from './GraphTraversal.js';
14
+ // Backward compatibility alias
15
+ export { ManagerContext as KnowledgeGraphManager } from './ManagerContext.js';
16
+ export { TransactionManager, OperationType, BatchTransaction, } from './TransactionManager.js';
17
+ export { createStorage, createStorageFromPath } from './StorageFactory.js';
18
+ // Phase 10 Sprint 2: Graph change events
19
+ export { GraphEventEmitter } from './GraphEventEmitter.js';
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Analytics Manager
3
+ *
4
+ * Handles graph statistics and validation operations.
5
+ * Extracted from SearchManager (Phase 4: Consolidate God Objects).
6
+ *
7
+ * @module features/AnalyticsManager
8
+ */
9
+ import type { GraphStorage } from '../core/GraphStorage.js';
10
+ import type { GraphStats, ValidationReport } from '../types/index.js';
11
+ /**
12
+ * Manages analytics operations for the knowledge graph.
13
+ */
14
+ export declare class AnalyticsManager {
15
+ private storage;
16
+ constructor(storage: GraphStorage);
17
+ /**
18
+ * Validate the knowledge graph structure and data integrity.
19
+ *
20
+ * Checks for:
21
+ * - Orphaned relations (pointing to non-existent entities)
22
+ * - Duplicate entity names
23
+ * - Invalid entity data (missing name/type, invalid observations)
24
+ * - Isolated entities (no relations)
25
+ * - Empty observations
26
+ * - Missing metadata (createdAt, lastModified)
27
+ *
28
+ * @returns Validation report with errors, warnings, and summary
29
+ */
30
+ validateGraph(): Promise<ValidationReport>;
31
+ /**
32
+ * Get comprehensive statistics about the knowledge graph.
33
+ *
34
+ * Provides metrics including:
35
+ * - Total counts of entities and relations
36
+ * - Entity and relation type distributions
37
+ * - Oldest and newest entities/relations
38
+ * - Date ranges for entities and relations
39
+ *
40
+ * @returns Graph statistics object
41
+ */
42
+ getGraphStats(): Promise<GraphStats>;
43
+ }
44
+ //# sourceMappingURL=AnalyticsManager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AnalyticsManager.d.ts","sourceRoot":"","sources":["../../src/features/AnalyticsManager.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,KAAK,EAAE,UAAU,EAAE,gBAAgB,EAAsC,MAAM,mBAAmB,CAAC;AAE1G;;GAEG;AACH,qBAAa,gBAAgB;IACf,OAAO,CAAC,OAAO;gBAAP,OAAO,EAAE,YAAY;IAEzC;;;;;;;;;;;;OAYG;IACG,aAAa,IAAI,OAAO,CAAC,gBAAgB,CAAC;IAmIhD;;;;;;;;;;OAUG;IACG,aAAa,IAAI,OAAO,CAAC,UAAU,CAAC;CAsE3C"}
@@ -1,12 +1,13 @@
1
1
  /**
2
2
  * Analytics Manager
3
3
  *
4
- * Provides graph validation and analytics capabilities.
4
+ * Handles graph statistics and validation operations.
5
+ * Extracted from SearchManager (Phase 4: Consolidate God Objects).
5
6
  *
6
7
  * @module features/AnalyticsManager
7
8
  */
8
9
  /**
9
- * Performs validation and analytics on the knowledge graph.
10
+ * Manages analytics operations for the knowledge graph.
10
11
  */
11
12
  export class AnalyticsManager {
12
13
  storage;