@danielsimonjr/memory-mcp 0.7.2 → 0.41.0

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 (61) hide show
  1. package/dist/__tests__/edge-cases/edge-cases.test.js +406 -0
  2. package/dist/__tests__/file-path.test.js +5 -5
  3. package/dist/__tests__/integration/workflows.test.js +449 -0
  4. package/dist/__tests__/knowledge-graph.test.js +8 -3
  5. package/dist/__tests__/performance/benchmarks.test.js +411 -0
  6. package/dist/__tests__/unit/core/EntityManager.test.js +334 -0
  7. package/dist/__tests__/unit/core/GraphStorage.test.js +205 -0
  8. package/dist/__tests__/unit/core/RelationManager.test.js +274 -0
  9. package/dist/__tests__/unit/features/CompressionManager.test.js +350 -0
  10. package/dist/__tests__/unit/search/BasicSearch.test.js +311 -0
  11. package/dist/__tests__/unit/search/BooleanSearch.test.js +432 -0
  12. package/dist/__tests__/unit/search/FuzzySearch.test.js +448 -0
  13. package/dist/__tests__/unit/search/RankedSearch.test.js +379 -0
  14. package/dist/__tests__/unit/utils/levenshtein.test.js +77 -0
  15. package/dist/core/EntityManager.js +554 -0
  16. package/dist/core/GraphStorage.js +172 -0
  17. package/dist/core/KnowledgeGraphManager.js +400 -0
  18. package/dist/core/ObservationManager.js +129 -0
  19. package/dist/core/RelationManager.js +186 -0
  20. package/dist/core/TransactionManager.js +389 -0
  21. package/dist/core/index.js +9 -0
  22. package/dist/features/AnalyticsManager.js +222 -0
  23. package/dist/features/ArchiveManager.js +74 -0
  24. package/dist/features/BackupManager.js +311 -0
  25. package/dist/features/CompressionManager.js +310 -0
  26. package/dist/features/ExportManager.js +305 -0
  27. package/dist/features/HierarchyManager.js +219 -0
  28. package/dist/features/ImportExportManager.js +50 -0
  29. package/dist/features/ImportManager.js +328 -0
  30. package/dist/features/TagManager.js +210 -0
  31. package/dist/features/index.js +12 -0
  32. package/dist/index.js +13 -996
  33. package/dist/memory.jsonl +225 -0
  34. package/dist/search/BasicSearch.js +161 -0
  35. package/dist/search/BooleanSearch.js +304 -0
  36. package/dist/search/FuzzySearch.js +115 -0
  37. package/dist/search/RankedSearch.js +206 -0
  38. package/dist/search/SavedSearchManager.js +145 -0
  39. package/dist/search/SearchManager.js +305 -0
  40. package/dist/search/SearchSuggestions.js +57 -0
  41. package/dist/search/TFIDFIndexManager.js +217 -0
  42. package/dist/search/index.js +10 -0
  43. package/dist/server/MCPServer.js +889 -0
  44. package/dist/types/analytics.types.js +6 -0
  45. package/dist/types/entity.types.js +7 -0
  46. package/dist/types/import-export.types.js +7 -0
  47. package/dist/types/index.js +12 -0
  48. package/dist/types/search.types.js +7 -0
  49. package/dist/types/tag.types.js +6 -0
  50. package/dist/utils/constants.js +127 -0
  51. package/dist/utils/dateUtils.js +89 -0
  52. package/dist/utils/errors.js +121 -0
  53. package/dist/utils/index.js +13 -0
  54. package/dist/utils/levenshtein.js +62 -0
  55. package/dist/utils/logger.js +33 -0
  56. package/dist/utils/pathUtils.js +115 -0
  57. package/dist/utils/schemas.js +184 -0
  58. package/dist/utils/searchCache.js +209 -0
  59. package/dist/utils/tfidf.js +90 -0
  60. package/dist/utils/validationUtils.js +109 -0
  61. package/package.json +50 -48
@@ -0,0 +1,186 @@
1
+ /**
2
+ * Relation Manager
3
+ *
4
+ * Handles CRUD operations for relations in the knowledge graph.
5
+ *
6
+ * @module core/RelationManager
7
+ */
8
+ import { ValidationError } from '../utils/errors.js';
9
+ import { BatchCreateRelationsSchema, DeleteRelationsSchema } from '../utils/index.js';
10
+ import { GRAPH_LIMITS } from '../utils/constants.js';
11
+ /**
12
+ * Manages relation operations with automatic timestamp handling.
13
+ */
14
+ export class RelationManager {
15
+ storage;
16
+ constructor(storage) {
17
+ this.storage = storage;
18
+ }
19
+ /**
20
+ * Create multiple relations in a single batch operation.
21
+ *
22
+ * This method performs the following operations:
23
+ * - Filters out duplicate relations (same from, to, and relationType)
24
+ * - Automatically adds createdAt and lastModified timestamps
25
+ * - Validates that entities referenced in relations exist (should be done by caller)
26
+ *
27
+ * A relation is considered duplicate if another relation exists with the same:
28
+ * - from entity name
29
+ * - to entity name
30
+ * - relationType
31
+ *
32
+ * @param relations - Array of relations to create
33
+ * @returns Promise resolving to array of newly created relations (excludes duplicates)
34
+ *
35
+ * @example
36
+ * ```typescript
37
+ * const manager = new RelationManager(storage);
38
+ *
39
+ * // Create single relation
40
+ * const results = await manager.createRelations([{
41
+ * from: 'Alice',
42
+ * to: 'Bob',
43
+ * relationType: 'works_with'
44
+ * }]);
45
+ *
46
+ * // Create multiple relations at once
47
+ * await manager.createRelations([
48
+ * { from: 'Alice', to: 'Project_X', relationType: 'contributes_to' },
49
+ * { from: 'Bob', to: 'Project_X', relationType: 'leads' },
50
+ * { from: 'Charlie', to: 'Alice', relationType: 'reports_to' }
51
+ * ]);
52
+ *
53
+ * // Duplicate relations are filtered out
54
+ * await manager.createRelations([
55
+ * { from: 'Alice', to: 'Bob', relationType: 'works_with' } // Already exists, won't be added
56
+ * ]);
57
+ * ```
58
+ */
59
+ async createRelations(relations) {
60
+ // Validate input
61
+ const validation = BatchCreateRelationsSchema.safeParse(relations);
62
+ if (!validation.success) {
63
+ const errors = validation.error.issues.map((e) => `${e.path.join('.')}: ${e.message}`);
64
+ throw new ValidationError('Invalid relation data', errors);
65
+ }
66
+ const graph = await this.storage.loadGraph();
67
+ const timestamp = new Date().toISOString();
68
+ // Check graph size limits
69
+ const relationsToAdd = relations.filter(r => !graph.relations.some(existing => existing.from === r.from &&
70
+ existing.to === r.to &&
71
+ existing.relationType === r.relationType));
72
+ if (graph.relations.length + relationsToAdd.length > GRAPH_LIMITS.MAX_RELATIONS) {
73
+ throw new ValidationError('Graph size limit exceeded', [`Adding ${relationsToAdd.length} relations would exceed maximum of ${GRAPH_LIMITS.MAX_RELATIONS} relations`]);
74
+ }
75
+ const newRelations = relationsToAdd
76
+ .map(r => ({
77
+ ...r,
78
+ createdAt: r.createdAt || timestamp,
79
+ lastModified: r.lastModified || timestamp,
80
+ }));
81
+ graph.relations.push(...newRelations);
82
+ await this.storage.saveGraph(graph);
83
+ return newRelations;
84
+ }
85
+ /**
86
+ * Delete multiple relations in a single batch operation.
87
+ *
88
+ * This method performs the following operations:
89
+ * - Removes all specified relations from the graph
90
+ * - Automatically updates lastModified timestamp for all affected entities
91
+ * - Silently ignores relations that don't exist (no error thrown)
92
+ *
93
+ * An entity is considered "affected" if it appears as either the source (from)
94
+ * or target (to) of any deleted relation.
95
+ *
96
+ * @param relations - Array of relations to delete. Each relation is matched by from, to, and relationType.
97
+ * @returns Promise that resolves when deletion is complete
98
+ *
99
+ * @example
100
+ * ```typescript
101
+ * const manager = new RelationManager(storage);
102
+ *
103
+ * // Delete single relation
104
+ * await manager.deleteRelations([{
105
+ * from: 'Alice',
106
+ * to: 'Bob',
107
+ * relationType: 'works_with'
108
+ * }]);
109
+ *
110
+ * // Delete multiple relations at once
111
+ * await manager.deleteRelations([
112
+ * { from: 'Alice', to: 'Project_X', relationType: 'contributes_to' },
113
+ * { from: 'Bob', to: 'Project_X', relationType: 'leads' }
114
+ * ]);
115
+ * // Note: Alice, Bob, and Project_X will all have their lastModified timestamp updated
116
+ *
117
+ * // Safe to delete non-existent relations
118
+ * await manager.deleteRelations([
119
+ * { from: 'NonExistent', to: 'AlsoNonExistent', relationType: 'fake' } // No error
120
+ * ]);
121
+ * ```
122
+ */
123
+ async deleteRelations(relations) {
124
+ // Validate input
125
+ const validation = DeleteRelationsSchema.safeParse(relations);
126
+ if (!validation.success) {
127
+ const errors = validation.error.issues.map((e) => `${e.path.join('.')}: ${e.message}`);
128
+ throw new ValidationError('Invalid relation data', errors);
129
+ }
130
+ const graph = await this.storage.loadGraph();
131
+ const timestamp = new Date().toISOString();
132
+ // Track affected entities
133
+ const affectedEntityNames = new Set();
134
+ relations.forEach(rel => {
135
+ affectedEntityNames.add(rel.from);
136
+ affectedEntityNames.add(rel.to);
137
+ });
138
+ // Remove relations
139
+ graph.relations = graph.relations.filter(r => !relations.some(delRelation => r.from === delRelation.from &&
140
+ r.to === delRelation.to &&
141
+ r.relationType === delRelation.relationType));
142
+ // Update lastModified for affected entities
143
+ graph.entities.forEach(entity => {
144
+ if (affectedEntityNames.has(entity.name)) {
145
+ entity.lastModified = timestamp;
146
+ }
147
+ });
148
+ await this.storage.saveGraph(graph);
149
+ }
150
+ /**
151
+ * Retrieve all relations involving a specific entity.
152
+ *
153
+ * This is a read-only operation that returns all relations where the specified
154
+ * entity appears as either the source (from) or target (to) of the relation.
155
+ * Entity names are case-sensitive.
156
+ *
157
+ * @param entityName - The unique name of the entity to find relations for
158
+ * @returns Promise resolving to array of Relation objects (empty array if no relations found)
159
+ *
160
+ * @example
161
+ * ```typescript
162
+ * const manager = new RelationManager(storage);
163
+ *
164
+ * // Get all relations for an entity
165
+ * const aliceRelations = await manager.getRelations('Alice');
166
+ * // Returns: [
167
+ * // { from: 'Alice', to: 'Bob', relationType: 'works_with' },
168
+ * // { from: 'Alice', to: 'Project_X', relationType: 'contributes_to' },
169
+ * // { from: 'Charlie', to: 'Alice', relationType: 'reports_to' }
170
+ * // ]
171
+ *
172
+ * // Process relations by type
173
+ * const relations = await manager.getRelations('Alice');
174
+ * const outgoing = relations.filter(r => r.from === 'Alice');
175
+ * const incoming = relations.filter(r => r.to === 'Alice');
176
+ *
177
+ * // Handle entity with no relations
178
+ * const noRelations = await manager.getRelations('IsolatedEntity');
179
+ * console.log(noRelations); // []
180
+ * ```
181
+ */
182
+ async getRelations(entityName) {
183
+ const graph = await this.storage.loadGraph();
184
+ return graph.relations.filter(r => r.from === entityName || r.to === entityName);
185
+ }
186
+ }
@@ -0,0 +1,389 @@
1
+ /**
2
+ * Transaction Manager
3
+ *
4
+ * Provides atomic transaction support for knowledge graph operations.
5
+ * Ensures data consistency by allowing multiple operations to be
6
+ * grouped together and committed atomically, with automatic rollback on failure.
7
+ *
8
+ * @module core/TransactionManager
9
+ */
10
+ import { BackupManager } from '../features/BackupManager.js';
11
+ import { KnowledgeGraphError } from '../utils/errors.js';
12
+ /**
13
+ * Types of operations that can be performed in a transaction.
14
+ */
15
+ export var OperationType;
16
+ (function (OperationType) {
17
+ OperationType["CREATE_ENTITY"] = "CREATE_ENTITY";
18
+ OperationType["UPDATE_ENTITY"] = "UPDATE_ENTITY";
19
+ OperationType["DELETE_ENTITY"] = "DELETE_ENTITY";
20
+ OperationType["CREATE_RELATION"] = "CREATE_RELATION";
21
+ OperationType["DELETE_RELATION"] = "DELETE_RELATION";
22
+ })(OperationType || (OperationType = {}));
23
+ /**
24
+ * Manages atomic transactions for knowledge graph operations.
25
+ *
26
+ * Provides ACID-like guarantees:
27
+ * - Atomicity: All operations succeed or all fail
28
+ * - Consistency: Graph is always in a valid state
29
+ * - Isolation: Each transaction operates on a snapshot
30
+ * - Durability: Changes are persisted to disk
31
+ *
32
+ * @example
33
+ * ```typescript
34
+ * const storage = new GraphStorage('/data/memory.jsonl');
35
+ * const txManager = new TransactionManager(storage);
36
+ *
37
+ * // Begin transaction
38
+ * txManager.begin();
39
+ *
40
+ * // Stage operations
41
+ * txManager.createEntity({ name: 'Alice', entityType: 'person', observations: [] });
42
+ * txManager.createRelation({ from: 'Alice', to: 'Bob', relationType: 'knows' });
43
+ *
44
+ * // Commit atomically (or rollback on error)
45
+ * const result = await txManager.commit();
46
+ * if (result.success) {
47
+ * console.log(`Transaction completed: ${result.operationsExecuted} operations`);
48
+ * }
49
+ * ```
50
+ */
51
+ export class TransactionManager {
52
+ storage;
53
+ operations = [];
54
+ inTransaction = false;
55
+ backupManager;
56
+ transactionBackup;
57
+ constructor(storage) {
58
+ this.storage = storage;
59
+ this.backupManager = new BackupManager(storage);
60
+ }
61
+ /**
62
+ * Begin a new transaction.
63
+ *
64
+ * Creates a backup of the current state for rollback purposes.
65
+ * Only one transaction can be active at a time.
66
+ *
67
+ * @throws {KnowledgeGraphError} If a transaction is already in progress
68
+ *
69
+ * @example
70
+ * ```typescript
71
+ * txManager.begin();
72
+ * // ... stage operations ...
73
+ * await txManager.commit();
74
+ * ```
75
+ */
76
+ begin() {
77
+ if (this.inTransaction) {
78
+ throw new KnowledgeGraphError('Transaction already in progress', 'TRANSACTION_ACTIVE');
79
+ }
80
+ this.operations = [];
81
+ this.inTransaction = true;
82
+ }
83
+ /**
84
+ * Stage a create entity operation.
85
+ *
86
+ * @param entity - Entity to create (without timestamps)
87
+ *
88
+ * @example
89
+ * ```typescript
90
+ * txManager.begin();
91
+ * txManager.createEntity({
92
+ * name: 'Alice',
93
+ * entityType: 'person',
94
+ * observations: ['Software engineer'],
95
+ * importance: 8
96
+ * });
97
+ * ```
98
+ */
99
+ createEntity(entity) {
100
+ this.ensureInTransaction();
101
+ this.operations.push({
102
+ type: OperationType.CREATE_ENTITY,
103
+ data: entity,
104
+ });
105
+ }
106
+ /**
107
+ * Stage an update entity operation.
108
+ *
109
+ * @param name - Name of entity to update
110
+ * @param updates - Partial entity updates
111
+ *
112
+ * @example
113
+ * ```typescript
114
+ * txManager.begin();
115
+ * txManager.updateEntity('Alice', {
116
+ * importance: 9,
117
+ * observations: ['Lead software engineer']
118
+ * });
119
+ * ```
120
+ */
121
+ updateEntity(name, updates) {
122
+ this.ensureInTransaction();
123
+ this.operations.push({
124
+ type: OperationType.UPDATE_ENTITY,
125
+ data: { name, updates },
126
+ });
127
+ }
128
+ /**
129
+ * Stage a delete entity operation.
130
+ *
131
+ * @param name - Name of entity to delete
132
+ *
133
+ * @example
134
+ * ```typescript
135
+ * txManager.begin();
136
+ * txManager.deleteEntity('OldEntity');
137
+ * ```
138
+ */
139
+ deleteEntity(name) {
140
+ this.ensureInTransaction();
141
+ this.operations.push({
142
+ type: OperationType.DELETE_ENTITY,
143
+ data: { name },
144
+ });
145
+ }
146
+ /**
147
+ * Stage a create relation operation.
148
+ *
149
+ * @param relation - Relation to create (without timestamps)
150
+ *
151
+ * @example
152
+ * ```typescript
153
+ * txManager.begin();
154
+ * txManager.createRelation({
155
+ * from: 'Alice',
156
+ * to: 'Bob',
157
+ * relationType: 'mentors'
158
+ * });
159
+ * ```
160
+ */
161
+ createRelation(relation) {
162
+ this.ensureInTransaction();
163
+ this.operations.push({
164
+ type: OperationType.CREATE_RELATION,
165
+ data: relation,
166
+ });
167
+ }
168
+ /**
169
+ * Stage a delete relation operation.
170
+ *
171
+ * @param from - Source entity name
172
+ * @param to - Target entity name
173
+ * @param relationType - Type of relation
174
+ *
175
+ * @example
176
+ * ```typescript
177
+ * txManager.begin();
178
+ * txManager.deleteRelation('Alice', 'Bob', 'mentors');
179
+ * ```
180
+ */
181
+ deleteRelation(from, to, relationType) {
182
+ this.ensureInTransaction();
183
+ this.operations.push({
184
+ type: OperationType.DELETE_RELATION,
185
+ data: { from, to, relationType },
186
+ });
187
+ }
188
+ /**
189
+ * Commit the transaction, applying all staged operations atomically.
190
+ *
191
+ * Creates a backup before applying changes. If any operation fails,
192
+ * automatically rolls back to the pre-transaction state.
193
+ *
194
+ * @returns Promise resolving to transaction result
195
+ *
196
+ * @example
197
+ * ```typescript
198
+ * txManager.begin();
199
+ * txManager.createEntity({ name: 'Alice', entityType: 'person', observations: [] });
200
+ * txManager.createRelation({ from: 'Alice', to: 'Bob', relationType: 'knows' });
201
+ *
202
+ * const result = await txManager.commit();
203
+ * if (result.success) {
204
+ * console.log(`Committed ${result.operationsExecuted} operations`);
205
+ * } else {
206
+ * console.error(`Transaction failed: ${result.error}`);
207
+ * }
208
+ * ```
209
+ */
210
+ async commit() {
211
+ this.ensureInTransaction();
212
+ 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();
217
+ const timestamp = new Date().toISOString();
218
+ // Apply all operations
219
+ let operationsExecuted = 0;
220
+ for (const operation of this.operations) {
221
+ this.applyOperation(graph, operation, timestamp);
222
+ operationsExecuted++;
223
+ }
224
+ // Save the modified graph
225
+ await this.storage.saveGraph(graph);
226
+ // Clean up transaction state
227
+ this.inTransaction = false;
228
+ this.operations = [];
229
+ // Delete the transaction backup (no longer needed)
230
+ if (this.transactionBackup) {
231
+ await this.backupManager.deleteBackup(this.transactionBackup);
232
+ this.transactionBackup = undefined;
233
+ }
234
+ return {
235
+ success: true,
236
+ operationsExecuted,
237
+ };
238
+ }
239
+ catch (error) {
240
+ // Rollback on error
241
+ const rollbackResult = await this.rollback();
242
+ return {
243
+ success: false,
244
+ operationsExecuted: 0,
245
+ error: error instanceof Error ? error.message : String(error),
246
+ rollbackBackup: rollbackResult.backupUsed,
247
+ };
248
+ }
249
+ }
250
+ /**
251
+ * Rollback the current transaction.
252
+ *
253
+ * Restores the graph to the pre-transaction state using the backup.
254
+ * Automatically called by commit() on failure.
255
+ *
256
+ * @returns Promise resolving to rollback result
257
+ *
258
+ * @example
259
+ * ```typescript
260
+ * txManager.begin();
261
+ * txManager.createEntity({ name: 'Test', entityType: 'temp', observations: [] });
262
+ *
263
+ * // Explicit rollback (e.g., user cancellation)
264
+ * const result = await txManager.rollback();
265
+ * console.log(`Rolled back, restored from: ${result.backupUsed}`);
266
+ * ```
267
+ */
268
+ async rollback() {
269
+ if (!this.transactionBackup) {
270
+ this.inTransaction = false;
271
+ this.operations = [];
272
+ return { success: false };
273
+ }
274
+ try {
275
+ // Restore from backup
276
+ await this.backupManager.restoreFromBackup(this.transactionBackup);
277
+ // Clean up
278
+ const backupUsed = this.transactionBackup;
279
+ await this.backupManager.deleteBackup(this.transactionBackup);
280
+ this.inTransaction = false;
281
+ this.operations = [];
282
+ this.transactionBackup = undefined;
283
+ return { success: true, backupUsed };
284
+ }
285
+ catch (error) {
286
+ // Rollback failed - keep backup for manual recovery
287
+ this.inTransaction = false;
288
+ this.operations = [];
289
+ return { success: false, backupUsed: this.transactionBackup };
290
+ }
291
+ }
292
+ /**
293
+ * Check if a transaction is currently in progress.
294
+ *
295
+ * @returns True if transaction is active
296
+ */
297
+ isInTransaction() {
298
+ return this.inTransaction;
299
+ }
300
+ /**
301
+ * Get the number of staged operations in the current transaction.
302
+ *
303
+ * @returns Number of operations staged
304
+ */
305
+ getOperationCount() {
306
+ return this.operations.length;
307
+ }
308
+ /**
309
+ * Ensure a transaction is in progress, or throw an error.
310
+ *
311
+ * @private
312
+ */
313
+ ensureInTransaction() {
314
+ if (!this.inTransaction) {
315
+ throw new KnowledgeGraphError('No transaction in progress. Call begin() first.', 'NO_TRANSACTION');
316
+ }
317
+ }
318
+ /**
319
+ * Apply a single operation to the graph.
320
+ *
321
+ * @private
322
+ */
323
+ applyOperation(graph, operation, timestamp) {
324
+ switch (operation.type) {
325
+ case OperationType.CREATE_ENTITY: {
326
+ const entity = {
327
+ ...operation.data,
328
+ createdAt: timestamp,
329
+ lastModified: timestamp,
330
+ };
331
+ // Check for duplicates
332
+ if (graph.entities.some(e => e.name === entity.name)) {
333
+ throw new KnowledgeGraphError(`Entity "${entity.name}" already exists`, 'DUPLICATE_ENTITY');
334
+ }
335
+ graph.entities.push(entity);
336
+ break;
337
+ }
338
+ case OperationType.UPDATE_ENTITY: {
339
+ const { name, updates } = operation.data;
340
+ const entity = graph.entities.find(e => e.name === name);
341
+ if (!entity) {
342
+ throw new KnowledgeGraphError(`Entity "${name}" not found`, 'ENTITY_NOT_FOUND');
343
+ }
344
+ Object.assign(entity, updates);
345
+ entity.lastModified = timestamp;
346
+ break;
347
+ }
348
+ case OperationType.DELETE_ENTITY: {
349
+ const { name } = operation.data;
350
+ const index = graph.entities.findIndex(e => e.name === name);
351
+ if (index === -1) {
352
+ throw new KnowledgeGraphError(`Entity "${name}" not found`, 'ENTITY_NOT_FOUND');
353
+ }
354
+ graph.entities.splice(index, 1);
355
+ // Delete related relations
356
+ graph.relations = graph.relations.filter(r => r.from !== name && r.to !== name);
357
+ break;
358
+ }
359
+ case OperationType.CREATE_RELATION: {
360
+ const relation = {
361
+ ...operation.data,
362
+ createdAt: timestamp,
363
+ lastModified: timestamp,
364
+ };
365
+ // Check for duplicates
366
+ const exists = graph.relations.some(r => r.from === relation.from && r.to === relation.to && r.relationType === relation.relationType);
367
+ if (exists) {
368
+ throw new KnowledgeGraphError(`Relation "${relation.from}" -> "${relation.to}" (${relation.relationType}) already exists`, 'DUPLICATE_RELATION');
369
+ }
370
+ graph.relations.push(relation);
371
+ break;
372
+ }
373
+ case OperationType.DELETE_RELATION: {
374
+ const { from, to, relationType } = operation.data;
375
+ const index = graph.relations.findIndex(r => r.from === from && r.to === to && r.relationType === relationType);
376
+ if (index === -1) {
377
+ throw new KnowledgeGraphError(`Relation "${from}" -> "${to}" (${relationType}) not found`, 'RELATION_NOT_FOUND');
378
+ }
379
+ graph.relations.splice(index, 1);
380
+ break;
381
+ }
382
+ default: {
383
+ // Exhaustiveness check - TypeScript will error if we miss a case
384
+ const _exhaustiveCheck = operation;
385
+ throw new KnowledgeGraphError(`Unknown operation type: ${_exhaustiveCheck.type}`, 'UNKNOWN_OPERATION');
386
+ }
387
+ }
388
+ }
389
+ }
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Core Module Barrel Export
3
+ */
4
+ export { GraphStorage } from './GraphStorage.js';
5
+ export { EntityManager } from './EntityManager.js';
6
+ export { RelationManager } from './RelationManager.js';
7
+ export { ObservationManager } from './ObservationManager.js';
8
+ export { KnowledgeGraphManager } from './KnowledgeGraphManager.js';
9
+ export { TransactionManager, OperationType, } from './TransactionManager.js';