@danielsimonjr/memory-mcp 12.2.3 → 12.5.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 (158) hide show
  1. package/README.md +88 -102
  2. package/dist/index.js +6 -0
  3. package/dist/server/toolDefinitions.d.ts.map +1 -1
  4. package/dist/server/toolDefinitions.js +745 -3
  5. package/dist/server/toolHandlers.d.ts +1 -9
  6. package/dist/server/toolHandlers.d.ts.map +1 -1
  7. package/dist/server/toolHandlers.js +859 -11
  8. package/package.json +9 -6
  9. package/dist/core/EntityManager.d.ts +0 -263
  10. package/dist/core/EntityManager.d.ts.map +0 -1
  11. package/dist/core/EntityManager.js +0 -478
  12. package/dist/core/GraphStorage.d.ts +0 -344
  13. package/dist/core/GraphStorage.d.ts.map +0 -1
  14. package/dist/core/GraphStorage.js +0 -708
  15. package/dist/core/GraphTraversal.d.ts +0 -136
  16. package/dist/core/GraphTraversal.d.ts.map +0 -1
  17. package/dist/core/GraphTraversal.js +0 -556
  18. package/dist/core/HierarchyManager.d.ts +0 -111
  19. package/dist/core/HierarchyManager.d.ts.map +0 -1
  20. package/dist/core/HierarchyManager.js +0 -224
  21. package/dist/core/ManagerContext.d.ts +0 -72
  22. package/dist/core/ManagerContext.d.ts.map +0 -1
  23. package/dist/core/ManagerContext.js +0 -118
  24. package/dist/core/ObservationManager.d.ts +0 -85
  25. package/dist/core/ObservationManager.d.ts.map +0 -1
  26. package/dist/core/ObservationManager.js +0 -123
  27. package/dist/core/RelationManager.d.ts +0 -131
  28. package/dist/core/RelationManager.d.ts.map +0 -1
  29. package/dist/core/RelationManager.js +0 -210
  30. package/dist/core/SQLiteStorage.d.ts +0 -354
  31. package/dist/core/SQLiteStorage.d.ts.map +0 -1
  32. package/dist/core/SQLiteStorage.js +0 -917
  33. package/dist/core/StorageFactory.d.ts +0 -45
  34. package/dist/core/StorageFactory.d.ts.map +0 -1
  35. package/dist/core/StorageFactory.js +0 -64
  36. package/dist/core/TransactionManager.d.ts +0 -259
  37. package/dist/core/TransactionManager.d.ts.map +0 -1
  38. package/dist/core/TransactionManager.js +0 -392
  39. package/dist/core/index.d.ts +0 -16
  40. package/dist/core/index.d.ts.map +0 -1
  41. package/dist/core/index.js +0 -17
  42. package/dist/features/AnalyticsManager.d.ts +0 -44
  43. package/dist/features/AnalyticsManager.d.ts.map +0 -1
  44. package/dist/features/AnalyticsManager.js +0 -223
  45. package/dist/features/ArchiveManager.d.ts +0 -121
  46. package/dist/features/ArchiveManager.d.ts.map +0 -1
  47. package/dist/features/ArchiveManager.js +0 -240
  48. package/dist/features/CompressionManager.d.ts +0 -109
  49. package/dist/features/CompressionManager.d.ts.map +0 -1
  50. package/dist/features/CompressionManager.js +0 -404
  51. package/dist/features/IOManager.d.ts +0 -221
  52. package/dist/features/IOManager.d.ts.map +0 -1
  53. package/dist/features/IOManager.js +0 -997
  54. package/dist/features/StreamingExporter.d.ts +0 -105
  55. package/dist/features/StreamingExporter.d.ts.map +0 -1
  56. package/dist/features/StreamingExporter.js +0 -150
  57. package/dist/features/TagManager.d.ts +0 -147
  58. package/dist/features/TagManager.d.ts.map +0 -1
  59. package/dist/features/TagManager.js +0 -210
  60. package/dist/features/index.d.ts +0 -12
  61. package/dist/features/index.d.ts.map +0 -1
  62. package/dist/features/index.js +0 -11
  63. package/dist/search/BasicSearch.d.ts +0 -51
  64. package/dist/search/BasicSearch.d.ts.map +0 -1
  65. package/dist/search/BasicSearch.js +0 -137
  66. package/dist/search/BooleanSearch.d.ts +0 -98
  67. package/dist/search/BooleanSearch.d.ts.map +0 -1
  68. package/dist/search/BooleanSearch.js +0 -430
  69. package/dist/search/EmbeddingService.d.ts +0 -178
  70. package/dist/search/EmbeddingService.d.ts.map +0 -1
  71. package/dist/search/EmbeddingService.js +0 -358
  72. package/dist/search/FuzzySearch.d.ts +0 -118
  73. package/dist/search/FuzzySearch.d.ts.map +0 -1
  74. package/dist/search/FuzzySearch.js +0 -312
  75. package/dist/search/RankedSearch.d.ts +0 -71
  76. package/dist/search/RankedSearch.d.ts.map +0 -1
  77. package/dist/search/RankedSearch.js +0 -238
  78. package/dist/search/SavedSearchManager.d.ts +0 -79
  79. package/dist/search/SavedSearchManager.d.ts.map +0 -1
  80. package/dist/search/SavedSearchManager.js +0 -145
  81. package/dist/search/SearchFilterChain.d.ts +0 -120
  82. package/dist/search/SearchFilterChain.d.ts.map +0 -1
  83. package/dist/search/SearchFilterChain.js +0 -185
  84. package/dist/search/SearchManager.d.ts +0 -285
  85. package/dist/search/SearchManager.d.ts.map +0 -1
  86. package/dist/search/SearchManager.js +0 -338
  87. package/dist/search/SearchSuggestions.d.ts +0 -27
  88. package/dist/search/SearchSuggestions.d.ts.map +0 -1
  89. package/dist/search/SearchSuggestions.js +0 -57
  90. package/dist/search/SemanticSearch.d.ts +0 -146
  91. package/dist/search/SemanticSearch.d.ts.map +0 -1
  92. package/dist/search/SemanticSearch.js +0 -313
  93. package/dist/search/TFIDFIndexManager.d.ts +0 -63
  94. package/dist/search/TFIDFIndexManager.d.ts.map +0 -1
  95. package/dist/search/TFIDFIndexManager.js +0 -215
  96. package/dist/search/VectorStore.d.ts +0 -235
  97. package/dist/search/VectorStore.d.ts.map +0 -1
  98. package/dist/search/VectorStore.js +0 -311
  99. package/dist/search/index.d.ts +0 -18
  100. package/dist/search/index.d.ts.map +0 -1
  101. package/dist/search/index.js +0 -21
  102. package/dist/types/index.d.ts +0 -13
  103. package/dist/types/index.d.ts.map +0 -1
  104. package/dist/types/index.js +0 -12
  105. package/dist/types/types.d.ts +0 -1234
  106. package/dist/types/types.d.ts.map +0 -1
  107. package/dist/types/types.js +0 -9
  108. package/dist/utils/compressedCache.d.ts +0 -192
  109. package/dist/utils/compressedCache.d.ts.map +0 -1
  110. package/dist/utils/compressedCache.js +0 -309
  111. package/dist/utils/compressionUtil.d.ts +0 -214
  112. package/dist/utils/compressionUtil.d.ts.map +0 -1
  113. package/dist/utils/compressionUtil.js +0 -247
  114. package/dist/utils/constants.d.ts +0 -245
  115. package/dist/utils/constants.d.ts.map +0 -1
  116. package/dist/utils/constants.js +0 -252
  117. package/dist/utils/entityUtils.d.ts +0 -321
  118. package/dist/utils/entityUtils.d.ts.map +0 -1
  119. package/dist/utils/entityUtils.js +0 -538
  120. package/dist/utils/errors.d.ts +0 -77
  121. package/dist/utils/errors.d.ts.map +0 -1
  122. package/dist/utils/errors.js +0 -121
  123. package/dist/utils/formatters.d.ts +0 -145
  124. package/dist/utils/formatters.d.ts.map +0 -1
  125. package/dist/utils/formatters.js +0 -132
  126. package/dist/utils/index.d.ts +0 -22
  127. package/dist/utils/index.d.ts.map +0 -1
  128. package/dist/utils/index.js +0 -75
  129. package/dist/utils/indexes.d.ts +0 -270
  130. package/dist/utils/indexes.d.ts.map +0 -1
  131. package/dist/utils/indexes.js +0 -526
  132. package/dist/utils/logger.d.ts +0 -24
  133. package/dist/utils/logger.d.ts.map +0 -1
  134. package/dist/utils/logger.js +0 -33
  135. package/dist/utils/parallelUtils.d.ts +0 -72
  136. package/dist/utils/parallelUtils.d.ts.map +0 -1
  137. package/dist/utils/parallelUtils.js +0 -169
  138. package/dist/utils/schemas.d.ts +0 -374
  139. package/dist/utils/schemas.d.ts.map +0 -1
  140. package/dist/utils/schemas.js +0 -484
  141. package/dist/utils/searchAlgorithms.d.ts +0 -99
  142. package/dist/utils/searchAlgorithms.d.ts.map +0 -1
  143. package/dist/utils/searchAlgorithms.js +0 -167
  144. package/dist/utils/searchCache.d.ts +0 -108
  145. package/dist/utils/searchCache.d.ts.map +0 -1
  146. package/dist/utils/searchCache.js +0 -209
  147. package/dist/utils/taskScheduler.d.ts +0 -290
  148. package/dist/utils/taskScheduler.d.ts.map +0 -1
  149. package/dist/utils/taskScheduler.js +0 -466
  150. package/dist/workers/WorkerPool.d.ts +0 -81
  151. package/dist/workers/WorkerPool.d.ts.map +0 -1
  152. package/dist/workers/WorkerPool.js +0 -121
  153. package/dist/workers/index.d.ts +0 -12
  154. package/dist/workers/index.d.ts.map +0 -1
  155. package/dist/workers/index.js +0 -9
  156. package/dist/workers/levenshteinWorker.d.ts +0 -60
  157. package/dist/workers/levenshteinWorker.d.ts.map +0 -1
  158. package/dist/workers/levenshteinWorker.js +0 -98
@@ -1,123 +0,0 @@
1
- /**
2
- * Observation Manager
3
- *
4
- * Handles observation CRUD operations for entities.
5
- * Extracted from EntityManager (Phase 4: Consolidate God Objects).
6
- *
7
- * @module core/ObservationManager
8
- */
9
- import { EntityNotFoundError } from '../utils/errors.js';
10
- /**
11
- * Manages observation operations for entities in the knowledge graph.
12
- */
13
- export class ObservationManager {
14
- storage;
15
- constructor(storage) {
16
- this.storage = storage;
17
- }
18
- /**
19
- * Add observations to multiple entities in a single batch operation.
20
- *
21
- * This method performs the following operations:
22
- * - Adds new observations to specified entities
23
- * - Filters out duplicate observations (already present)
24
- * - Updates lastModified timestamp only if new observations were added
25
- * - ATOMIC: All updates are saved in a single operation
26
- *
27
- * @param observations - Array of entity names and observations to add
28
- * @returns Promise resolving to array of results showing which observations were added
29
- * @throws {EntityNotFoundError} If any entity is not found
30
- *
31
- * @example
32
- * ```typescript
33
- * const manager = new ObservationManager(storage);
34
- *
35
- * // Add observations to multiple entities
36
- * const results = await manager.addObservations([
37
- * { entityName: 'Alice', contents: ['Completed project X', 'Started project Y'] },
38
- * { entityName: 'Bob', contents: ['Joined team meeting'] }
39
- * ]);
40
- *
41
- * // Check what was added (duplicates are filtered out)
42
- * results.forEach(r => {
43
- * console.log(`${r.entityName}: added ${r.addedObservations.length} new observations`);
44
- * });
45
- * ```
46
- */
47
- async addObservations(observations) {
48
- // Get mutable graph for atomic update
49
- const graph = await this.storage.getGraphForMutation();
50
- const timestamp = new Date().toISOString();
51
- const results = [];
52
- let hasChanges = false;
53
- for (const o of observations) {
54
- const entity = graph.entities.find(e => e.name === o.entityName);
55
- if (!entity) {
56
- throw new EntityNotFoundError(o.entityName);
57
- }
58
- const newObservations = o.contents.filter(content => !entity.observations.includes(content));
59
- if (newObservations.length > 0) {
60
- // Add new observations directly to the entity
61
- entity.observations.push(...newObservations);
62
- entity.lastModified = timestamp;
63
- hasChanges = true;
64
- }
65
- results.push({ entityName: o.entityName, addedObservations: newObservations });
66
- }
67
- // Save all changes in a single atomic operation
68
- if (hasChanges) {
69
- await this.storage.saveGraph(graph);
70
- }
71
- return results;
72
- }
73
- /**
74
- * Delete observations from multiple entities in a single batch operation.
75
- *
76
- * This method performs the following operations:
77
- * - Removes specified observations from entities
78
- * - Updates lastModified timestamp only if observations were deleted
79
- * - Silently ignores entities that don't exist (no error thrown)
80
- * - ATOMIC: All deletions are saved in a single operation
81
- *
82
- * @param deletions - Array of entity names and observations to delete
83
- * @returns Promise that resolves when deletion is complete
84
- *
85
- * @example
86
- * ```typescript
87
- * const manager = new ObservationManager(storage);
88
- *
89
- * // Delete observations from multiple entities
90
- * await manager.deleteObservations([
91
- * { entityName: 'Alice', observations: ['Old observation 1', 'Old observation 2'] },
92
- * { entityName: 'Bob', observations: ['Outdated info'] }
93
- * ]);
94
- *
95
- * // Safe to delete from non-existent entities (no error)
96
- * await manager.deleteObservations([
97
- * { entityName: 'NonExistent', observations: ['Some text'] }
98
- * ]); // No error thrown
99
- * ```
100
- */
101
- async deleteObservations(deletions) {
102
- // Get mutable graph for atomic update
103
- const graph = await this.storage.getGraphForMutation();
104
- const timestamp = new Date().toISOString();
105
- let hasChanges = false;
106
- deletions.forEach(d => {
107
- const entity = graph.entities.find(e => e.name === d.entityName);
108
- if (entity) {
109
- const originalLength = entity.observations.length;
110
- entity.observations = entity.observations.filter(o => !d.observations.includes(o));
111
- // Update lastModified timestamp if observations were deleted
112
- if (entity.observations.length < originalLength) {
113
- entity.lastModified = timestamp;
114
- hasChanges = true;
115
- }
116
- }
117
- });
118
- // Save all changes in a single atomic operation
119
- if (hasChanges) {
120
- await this.storage.saveGraph(graph);
121
- }
122
- }
123
- }
@@ -1,131 +0,0 @@
1
- /**
2
- * Relation Manager
3
- *
4
- * Handles CRUD operations for relations in the knowledge graph.
5
- *
6
- * @module core/RelationManager
7
- */
8
- import type { Relation } from '../types/index.js';
9
- import type { GraphStorage } from './GraphStorage.js';
10
- /**
11
- * Manages relation operations with automatic timestamp handling.
12
- */
13
- export declare class RelationManager {
14
- private storage;
15
- constructor(storage: GraphStorage);
16
- /**
17
- * Create multiple relations in a single batch operation.
18
- *
19
- * This method performs the following operations:
20
- * - Validates that all referenced entities exist (prevents dangling relations)
21
- * - Filters out duplicate relations (same from, to, and relationType)
22
- * - Automatically adds createdAt and lastModified timestamps
23
- *
24
- * A relation is considered duplicate if another relation exists with the same:
25
- * - from entity name
26
- * - to entity name
27
- * - relationType
28
- *
29
- * @param relations - Array of relations to create
30
- * @returns Promise resolving to array of newly created relations (excludes duplicates)
31
- * @throws {ValidationError} If any relation references non-existent entities
32
- *
33
- * @example
34
- * ```typescript
35
- * const manager = new RelationManager(storage);
36
- *
37
- * // Create single relation
38
- * const results = await manager.createRelations([{
39
- * from: 'Alice',
40
- * to: 'Bob',
41
- * relationType: 'works_with'
42
- * }]);
43
- *
44
- * // Create multiple relations at once
45
- * await manager.createRelations([
46
- * { from: 'Alice', to: 'Project_X', relationType: 'contributes_to' },
47
- * { from: 'Bob', to: 'Project_X', relationType: 'leads' },
48
- * { from: 'Charlie', to: 'Alice', relationType: 'reports_to' }
49
- * ]);
50
- *
51
- * // Duplicate relations are filtered out
52
- * await manager.createRelations([
53
- * { from: 'Alice', to: 'Bob', relationType: 'works_with' } // Already exists, won't be added
54
- * ]);
55
- * ```
56
- */
57
- createRelations(relations: Relation[]): Promise<Relation[]>;
58
- /**
59
- * Delete multiple relations in a single batch operation.
60
- *
61
- * This method performs the following operations:
62
- * - Removes all specified relations from the graph
63
- * - Automatically updates lastModified timestamp for all affected entities
64
- * - Silently ignores relations that don't exist (no error thrown)
65
- *
66
- * An entity is considered "affected" if it appears as either the source (from)
67
- * or target (to) of any deleted relation.
68
- *
69
- * @param relations - Array of relations to delete. Each relation is matched by from, to, and relationType.
70
- * @returns Promise that resolves when deletion is complete
71
- *
72
- * @example
73
- * ```typescript
74
- * const manager = new RelationManager(storage);
75
- *
76
- * // Delete single relation
77
- * await manager.deleteRelations([{
78
- * from: 'Alice',
79
- * to: 'Bob',
80
- * relationType: 'works_with'
81
- * }]);
82
- *
83
- * // Delete multiple relations at once
84
- * await manager.deleteRelations([
85
- * { from: 'Alice', to: 'Project_X', relationType: 'contributes_to' },
86
- * { from: 'Bob', to: 'Project_X', relationType: 'leads' }
87
- * ]);
88
- * // Note: Alice, Bob, and Project_X will all have their lastModified timestamp updated
89
- *
90
- * // Safe to delete non-existent relations
91
- * await manager.deleteRelations([
92
- * { from: 'NonExistent', to: 'AlsoNonExistent', relationType: 'fake' } // No error
93
- * ]);
94
- * ```
95
- */
96
- deleteRelations(relations: Relation[]): Promise<void>;
97
- /**
98
- * Retrieve all relations involving a specific entity.
99
- *
100
- * This is a read-only operation that returns all relations where the specified
101
- * entity appears as either the source (from) or target (to) of the relation.
102
- * Entity names are case-sensitive.
103
- *
104
- * @param entityName - The unique name of the entity to find relations for
105
- * @returns Promise resolving to array of Relation objects (empty array if no relations found)
106
- *
107
- * @example
108
- * ```typescript
109
- * const manager = new RelationManager(storage);
110
- *
111
- * // Get all relations for an entity
112
- * const aliceRelations = await manager.getRelations('Alice');
113
- * // Returns: [
114
- * // { from: 'Alice', to: 'Bob', relationType: 'works_with' },
115
- * // { from: 'Alice', to: 'Project_X', relationType: 'contributes_to' },
116
- * // { from: 'Charlie', to: 'Alice', relationType: 'reports_to' }
117
- * // ]
118
- *
119
- * // Process relations by type
120
- * const relations = await manager.getRelations('Alice');
121
- * const outgoing = relations.filter(r => r.from === 'Alice');
122
- * const incoming = relations.filter(r => r.to === 'Alice');
123
- *
124
- * // Handle entity with no relations
125
- * const noRelations = await manager.getRelations('IsolatedEntity');
126
- * console.log(noRelations); // []
127
- * ```
128
- */
129
- getRelations(entityName: string): Promise<Relation[]>;
130
- }
131
- //# sourceMappingURL=RelationManager.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"RelationManager.d.ts","sourceRoot":"","sources":["../../src/core/RelationManager.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAClD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAKtD;;GAEG;AACH,qBAAa,eAAe;IACd,OAAO,CAAC,OAAO;gBAAP,OAAO,EAAE,YAAY;IAEzC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAwCG;IACG,eAAe,CAAC,SAAS,EAAE,QAAQ,EAAE,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC;IAiEjE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAqCG;IACG,eAAe,CAAC,SAAS,EAAE,QAAQ,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAqC3D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA+BG;IACG,YAAY,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC;CAK5D"}
@@ -1,210 +0,0 @@
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
- * - Validates that all referenced entities exist (prevents dangling relations)
24
- * - Filters out duplicate relations (same from, to, and relationType)
25
- * - Automatically adds createdAt and lastModified timestamps
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
- * @throws {ValidationError} If any relation references non-existent entities
35
- *
36
- * @example
37
- * ```typescript
38
- * const manager = new RelationManager(storage);
39
- *
40
- * // Create single relation
41
- * const results = await manager.createRelations([{
42
- * from: 'Alice',
43
- * to: 'Bob',
44
- * relationType: 'works_with'
45
- * }]);
46
- *
47
- * // Create multiple relations at once
48
- * await manager.createRelations([
49
- * { from: 'Alice', to: 'Project_X', relationType: 'contributes_to' },
50
- * { from: 'Bob', to: 'Project_X', relationType: 'leads' },
51
- * { from: 'Charlie', to: 'Alice', relationType: 'reports_to' }
52
- * ]);
53
- *
54
- * // Duplicate relations are filtered out
55
- * await manager.createRelations([
56
- * { from: 'Alice', to: 'Bob', relationType: 'works_with' } // Already exists, won't be added
57
- * ]);
58
- * ```
59
- */
60
- async createRelations(relations) {
61
- // Validate input
62
- const validation = BatchCreateRelationsSchema.safeParse(relations);
63
- if (!validation.success) {
64
- const errors = validation.error.issues.map((e) => `${e.path.join('.')}: ${e.message}`);
65
- throw new ValidationError('Invalid relation data', errors);
66
- }
67
- // Use read-only graph for checking existing relations and entity existence
68
- const readGraph = await this.storage.loadGraph();
69
- const timestamp = new Date().toISOString();
70
- // Build set of existing entity names for O(1) lookup
71
- const existingEntityNames = new Set(readGraph.entities.map(e => e.name));
72
- // Validate that all referenced entities exist (fixes bug 7.2 from analysis)
73
- const danglingRelations = [];
74
- for (const relation of relations) {
75
- const missingEntities = [];
76
- if (!existingEntityNames.has(relation.from)) {
77
- missingEntities.push(relation.from);
78
- }
79
- if (!existingEntityNames.has(relation.to)) {
80
- missingEntities.push(relation.to);
81
- }
82
- if (missingEntities.length > 0) {
83
- danglingRelations.push(`Relation from "${relation.from}" to "${relation.to}" references non-existent entities: ${missingEntities.join(', ')}`);
84
- }
85
- }
86
- if (danglingRelations.length > 0) {
87
- throw new ValidationError('Relations reference non-existent entities', danglingRelations);
88
- }
89
- // Check graph size limits
90
- const relationsToAdd = relations.filter(r => !readGraph.relations.some(existing => existing.from === r.from &&
91
- existing.to === r.to &&
92
- existing.relationType === r.relationType));
93
- if (readGraph.relations.length + relationsToAdd.length > GRAPH_LIMITS.MAX_RELATIONS) {
94
- throw new ValidationError('Graph size limit exceeded', [`Adding ${relationsToAdd.length} relations would exceed maximum of ${GRAPH_LIMITS.MAX_RELATIONS} relations`]);
95
- }
96
- const newRelations = relationsToAdd
97
- .map(r => ({
98
- ...r,
99
- createdAt: r.createdAt || timestamp,
100
- lastModified: r.lastModified || timestamp,
101
- }));
102
- // Get mutable copy for write operation
103
- const graph = await this.storage.getGraphForMutation();
104
- graph.relations.push(...newRelations);
105
- await this.storage.saveGraph(graph);
106
- return newRelations;
107
- }
108
- /**
109
- * Delete multiple relations in a single batch operation.
110
- *
111
- * This method performs the following operations:
112
- * - Removes all specified relations from the graph
113
- * - Automatically updates lastModified timestamp for all affected entities
114
- * - Silently ignores relations that don't exist (no error thrown)
115
- *
116
- * An entity is considered "affected" if it appears as either the source (from)
117
- * or target (to) of any deleted relation.
118
- *
119
- * @param relations - Array of relations to delete. Each relation is matched by from, to, and relationType.
120
- * @returns Promise that resolves when deletion is complete
121
- *
122
- * @example
123
- * ```typescript
124
- * const manager = new RelationManager(storage);
125
- *
126
- * // Delete single relation
127
- * await manager.deleteRelations([{
128
- * from: 'Alice',
129
- * to: 'Bob',
130
- * relationType: 'works_with'
131
- * }]);
132
- *
133
- * // Delete multiple relations at once
134
- * await manager.deleteRelations([
135
- * { from: 'Alice', to: 'Project_X', relationType: 'contributes_to' },
136
- * { from: 'Bob', to: 'Project_X', relationType: 'leads' }
137
- * ]);
138
- * // Note: Alice, Bob, and Project_X will all have their lastModified timestamp updated
139
- *
140
- * // Safe to delete non-existent relations
141
- * await manager.deleteRelations([
142
- * { from: 'NonExistent', to: 'AlsoNonExistent', relationType: 'fake' } // No error
143
- * ]);
144
- * ```
145
- */
146
- async deleteRelations(relations) {
147
- // Validate input
148
- const validation = DeleteRelationsSchema.safeParse(relations);
149
- if (!validation.success) {
150
- const errors = validation.error.issues.map((e) => `${e.path.join('.')}: ${e.message}`);
151
- throw new ValidationError('Invalid relation data', errors);
152
- }
153
- const graph = await this.storage.getGraphForMutation();
154
- const timestamp = new Date().toISOString();
155
- // Track affected entities
156
- const affectedEntityNames = new Set();
157
- relations.forEach(rel => {
158
- affectedEntityNames.add(rel.from);
159
- affectedEntityNames.add(rel.to);
160
- });
161
- // Remove relations
162
- graph.relations = graph.relations.filter(r => !relations.some(delRelation => r.from === delRelation.from &&
163
- r.to === delRelation.to &&
164
- r.relationType === delRelation.relationType));
165
- // Update lastModified for affected entities
166
- graph.entities.forEach(entity => {
167
- if (affectedEntityNames.has(entity.name)) {
168
- entity.lastModified = timestamp;
169
- }
170
- });
171
- await this.storage.saveGraph(graph);
172
- }
173
- /**
174
- * Retrieve all relations involving a specific entity.
175
- *
176
- * This is a read-only operation that returns all relations where the specified
177
- * entity appears as either the source (from) or target (to) of the relation.
178
- * Entity names are case-sensitive.
179
- *
180
- * @param entityName - The unique name of the entity to find relations for
181
- * @returns Promise resolving to array of Relation objects (empty array if no relations found)
182
- *
183
- * @example
184
- * ```typescript
185
- * const manager = new RelationManager(storage);
186
- *
187
- * // Get all relations for an entity
188
- * const aliceRelations = await manager.getRelations('Alice');
189
- * // Returns: [
190
- * // { from: 'Alice', to: 'Bob', relationType: 'works_with' },
191
- * // { from: 'Alice', to: 'Project_X', relationType: 'contributes_to' },
192
- * // { from: 'Charlie', to: 'Alice', relationType: 'reports_to' }
193
- * // ]
194
- *
195
- * // Process relations by type
196
- * const relations = await manager.getRelations('Alice');
197
- * const outgoing = relations.filter(r => r.from === 'Alice');
198
- * const incoming = relations.filter(r => r.to === 'Alice');
199
- *
200
- * // Handle entity with no relations
201
- * const noRelations = await manager.getRelations('IsolatedEntity');
202
- * console.log(noRelations); // []
203
- * ```
204
- */
205
- async getRelations(entityName) {
206
- // OPTIMIZED: Uses RelationIndex for O(1) lookup instead of O(n) array scan
207
- await this.storage.ensureLoaded();
208
- return this.storage.getRelationsFor(entityName);
209
- }
210
- }