@danielsimonjr/memory-mcp 0.47.1 → 9.8.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 (207) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +2000 -194
  3. package/dist/__tests__/file-path.test.js +5 -5
  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 +85 -133
  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 +643 -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 +917 -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 +490 -13
  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 +14 -13
  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 +1041 -0
  53. package/dist/features/StreamingExporter.d.ts +123 -0
  54. package/dist/features/StreamingExporter.d.ts.map +1 -0
  55. package/dist/features/StreamingExporter.js +203 -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 +12 -45
  64. package/dist/memory.jsonl +1 -18
  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/SearchFilterChain.d.ts +120 -0
  86. package/dist/search/SearchFilterChain.d.ts.map +1 -0
  87. package/dist/search/SearchFilterChain.js +2 -4
  88. package/dist/search/SearchManager.d.ts +326 -0
  89. package/dist/search/SearchManager.d.ts.map +1 -0
  90. package/dist/search/SearchManager.js +148 -0
  91. package/dist/search/SearchSuggestions.d.ts +27 -0
  92. package/dist/search/SearchSuggestions.d.ts.map +1 -0
  93. package/dist/search/SearchSuggestions.js +1 -1
  94. package/dist/search/SemanticSearch.d.ts +149 -0
  95. package/dist/search/SemanticSearch.d.ts.map +1 -0
  96. package/dist/search/SemanticSearch.js +323 -0
  97. package/dist/search/TFIDFEventSync.d.ts +85 -0
  98. package/dist/search/TFIDFEventSync.d.ts.map +1 -0
  99. package/dist/search/TFIDFEventSync.js +133 -0
  100. package/dist/search/TFIDFIndexManager.d.ts +151 -0
  101. package/dist/search/TFIDFIndexManager.d.ts.map +1 -0
  102. package/dist/search/TFIDFIndexManager.js +232 -17
  103. package/dist/search/VectorStore.d.ts +235 -0
  104. package/dist/search/VectorStore.d.ts.map +1 -0
  105. package/dist/search/VectorStore.js +311 -0
  106. package/dist/search/index.d.ts +21 -0
  107. package/dist/search/index.d.ts.map +1 -0
  108. package/dist/search/index.js +12 -0
  109. package/dist/server/MCPServer.d.ts +21 -0
  110. package/dist/server/MCPServer.d.ts.map +1 -0
  111. package/dist/server/MCPServer.js +4 -4
  112. package/dist/server/responseCompressor.d.ts +94 -0
  113. package/dist/server/responseCompressor.d.ts.map +1 -0
  114. package/dist/server/responseCompressor.js +127 -0
  115. package/dist/server/toolDefinitions.d.ts +27 -0
  116. package/dist/server/toolDefinitions.d.ts.map +1 -0
  117. package/dist/server/toolDefinitions.js +189 -18
  118. package/dist/server/toolHandlers.d.ts +41 -0
  119. package/dist/server/toolHandlers.d.ts.map +1 -0
  120. package/dist/server/toolHandlers.js +467 -75
  121. package/dist/types/index.d.ts +13 -0
  122. package/dist/types/index.d.ts.map +1 -0
  123. package/dist/types/index.js +1 -1
  124. package/dist/types/types.d.ts +1654 -0
  125. package/dist/types/types.d.ts.map +1 -0
  126. package/dist/types/types.js +9 -0
  127. package/dist/utils/compressedCache.d.ts +192 -0
  128. package/dist/utils/compressedCache.d.ts.map +1 -0
  129. package/dist/utils/compressedCache.js +309 -0
  130. package/dist/utils/compressionUtil.d.ts +214 -0
  131. package/dist/utils/compressionUtil.d.ts.map +1 -0
  132. package/dist/utils/compressionUtil.js +247 -0
  133. package/dist/utils/constants.d.ts +245 -0
  134. package/dist/utils/constants.d.ts.map +1 -0
  135. package/dist/utils/constants.js +124 -0
  136. package/dist/utils/entityUtils.d.ts +321 -0
  137. package/dist/utils/entityUtils.d.ts.map +1 -0
  138. package/dist/utils/entityUtils.js +434 -4
  139. package/dist/utils/errors.d.ts +95 -0
  140. package/dist/utils/errors.d.ts.map +1 -0
  141. package/dist/utils/errors.js +24 -0
  142. package/dist/utils/formatters.d.ts +145 -0
  143. package/dist/utils/formatters.d.ts.map +1 -0
  144. package/dist/utils/{paginationUtils.js → formatters.js} +54 -3
  145. package/dist/utils/index.d.ts +23 -0
  146. package/dist/utils/index.d.ts.map +1 -0
  147. package/dist/utils/index.js +69 -31
  148. package/dist/utils/indexes.d.ts +270 -0
  149. package/dist/utils/indexes.d.ts.map +1 -0
  150. package/dist/utils/indexes.js +526 -0
  151. package/dist/utils/logger.d.ts +24 -0
  152. package/dist/utils/logger.d.ts.map +1 -0
  153. package/dist/utils/operationUtils.d.ts +124 -0
  154. package/dist/utils/operationUtils.d.ts.map +1 -0
  155. package/dist/utils/operationUtils.js +175 -0
  156. package/dist/utils/parallelUtils.d.ts +72 -0
  157. package/dist/utils/parallelUtils.d.ts.map +1 -0
  158. package/dist/utils/parallelUtils.js +169 -0
  159. package/dist/utils/schemas.d.ts +374 -0
  160. package/dist/utils/schemas.d.ts.map +1 -0
  161. package/dist/utils/schemas.js +302 -2
  162. package/dist/utils/searchAlgorithms.d.ts +99 -0
  163. package/dist/utils/searchAlgorithms.d.ts.map +1 -0
  164. package/dist/utils/searchAlgorithms.js +167 -0
  165. package/dist/utils/searchCache.d.ts +108 -0
  166. package/dist/utils/searchCache.d.ts.map +1 -0
  167. package/dist/utils/taskScheduler.d.ts +290 -0
  168. package/dist/utils/taskScheduler.d.ts.map +1 -0
  169. package/dist/utils/taskScheduler.js +466 -0
  170. package/dist/workers/index.d.ts +12 -0
  171. package/dist/workers/index.d.ts.map +1 -0
  172. package/dist/workers/index.js +9 -0
  173. package/dist/workers/levenshteinWorker.d.ts +60 -0
  174. package/dist/workers/levenshteinWorker.d.ts.map +1 -0
  175. package/dist/workers/levenshteinWorker.js +98 -0
  176. package/package.json +17 -4
  177. package/dist/__tests__/edge-cases/edge-cases.test.js +0 -406
  178. package/dist/__tests__/integration/workflows.test.js +0 -449
  179. package/dist/__tests__/performance/benchmarks.test.js +0 -413
  180. package/dist/__tests__/unit/core/EntityManager.test.js +0 -334
  181. package/dist/__tests__/unit/core/GraphStorage.test.js +0 -205
  182. package/dist/__tests__/unit/core/RelationManager.test.js +0 -274
  183. package/dist/__tests__/unit/features/CompressionManager.test.js +0 -350
  184. package/dist/__tests__/unit/search/BasicSearch.test.js +0 -311
  185. package/dist/__tests__/unit/search/BooleanSearch.test.js +0 -432
  186. package/dist/__tests__/unit/search/FuzzySearch.test.js +0 -448
  187. package/dist/__tests__/unit/search/RankedSearch.test.js +0 -379
  188. package/dist/__tests__/unit/utils/levenshtein.test.js +0 -77
  189. package/dist/core/KnowledgeGraphManager.js +0 -423
  190. package/dist/features/BackupManager.js +0 -311
  191. package/dist/features/ExportManager.js +0 -305
  192. package/dist/features/ImportExportManager.js +0 -50
  193. package/dist/features/ImportManager.js +0 -328
  194. package/dist/types/analytics.types.js +0 -6
  195. package/dist/types/entity.types.js +0 -7
  196. package/dist/types/import-export.types.js +0 -7
  197. package/dist/types/search.types.js +0 -7
  198. package/dist/types/tag.types.js +0 -6
  199. package/dist/utils/dateUtils.js +0 -89
  200. package/dist/utils/filterUtils.js +0 -155
  201. package/dist/utils/levenshtein.js +0 -62
  202. package/dist/utils/pathUtils.js +0 -115
  203. package/dist/utils/responseFormatter.js +0 -55
  204. package/dist/utils/tagUtils.js +0 -107
  205. package/dist/utils/tfidf.js +0 -90
  206. package/dist/utils/validationHelper.js +0 -99
  207. package/dist/utils/validationUtils.js +0 -109
@@ -1,311 +0,0 @@
1
- /**
2
- * Backup Manager
3
- *
4
- * Manages backup and restore operations for the knowledge graph.
5
- * Provides point-in-time recovery and data protection.
6
- *
7
- * @module features/BackupManager
8
- */
9
- import { promises as fs } from 'fs';
10
- import { dirname, join } from 'path';
11
- import { FileOperationError } from '../utils/errors.js';
12
- /**
13
- * Manages backup and restore operations for the knowledge graph.
14
- *
15
- * Backup files are stored in a `.backups` directory next to the main graph file.
16
- * Each backup includes the graph data and metadata about the backup.
17
- *
18
- * @example
19
- * ```typescript
20
- * const storage = new GraphStorage('/data/memory.jsonl');
21
- * const backup = new BackupManager(storage);
22
- *
23
- * // Create a backup
24
- * const backupPath = await backup.createBackup('Before compression');
25
- *
26
- * // List available backups
27
- * const backups = await backup.listBackups();
28
- *
29
- * // Restore from backup
30
- * await backup.restoreFromBackup(backupPath);
31
- *
32
- * // Clean old backups (keep last 10)
33
- * await backup.cleanOldBackups(10);
34
- * ```
35
- */
36
- export class BackupManager {
37
- storage;
38
- backupDir;
39
- constructor(storage) {
40
- this.storage = storage;
41
- const filePath = this.storage.getFilePath();
42
- const dir = dirname(filePath);
43
- this.backupDir = join(dir, '.backups');
44
- }
45
- /**
46
- * Ensure backup directory exists.
47
- *
48
- * @private
49
- */
50
- async ensureBackupDir() {
51
- try {
52
- await fs.mkdir(this.backupDir, { recursive: true });
53
- }
54
- catch (error) {
55
- throw new FileOperationError('create backup directory', this.backupDir, error);
56
- }
57
- }
58
- /**
59
- * Generate backup file name with timestamp.
60
- *
61
- * Format: backup_YYYY-MM-DD_HH-MM-SS-mmm.jsonl
62
- *
63
- * @private
64
- */
65
- generateBackupFileName() {
66
- const now = new Date();
67
- const timestamp = now.toISOString()
68
- .replace(/:/g, '-')
69
- .replace(/\./g, '-')
70
- .replace('T', '_')
71
- .replace('Z', '');
72
- return `backup_${timestamp}.jsonl`;
73
- }
74
- /**
75
- * Create a backup of the current knowledge graph.
76
- *
77
- * Backup includes:
78
- * - Complete graph data (entities and relations)
79
- * - Metadata (timestamp, counts, file size, description)
80
- *
81
- * @param description - Optional description for this backup
82
- * @returns Promise resolving to the backup file path
83
- * @throws {FileOperationError} If backup creation fails
84
- *
85
- * @example
86
- * ```typescript
87
- * // Create backup with description
88
- * const backupPath = await manager.createBackup('Before merging duplicates');
89
- *
90
- * // Create backup without description
91
- * const backupPath = await manager.createBackup();
92
- * ```
93
- */
94
- async createBackup(description) {
95
- await this.ensureBackupDir();
96
- // Load current graph
97
- const graph = await this.storage.loadGraph();
98
- const fileName = this.generateBackupFileName();
99
- const backupPath = join(this.backupDir, fileName);
100
- try {
101
- // Read the current file content to preserve exact formatting
102
- const originalPath = this.storage.getFilePath();
103
- let fileContent;
104
- try {
105
- fileContent = await fs.readFile(originalPath, 'utf-8');
106
- }
107
- catch (error) {
108
- // File doesn't exist yet - generate content from graph
109
- const lines = [
110
- ...graph.entities.map(e => JSON.stringify({ type: 'entity', ...e })),
111
- ...graph.relations.map(r => JSON.stringify({ type: 'relation', ...r })),
112
- ];
113
- fileContent = lines.join('\n');
114
- }
115
- // Write backup file
116
- await fs.writeFile(backupPath, fileContent);
117
- // Get file stats
118
- const stats = await fs.stat(backupPath);
119
- // Create metadata
120
- const metadata = {
121
- timestamp: new Date().toISOString(),
122
- entityCount: graph.entities.length,
123
- relationCount: graph.relations.length,
124
- fileSize: stats.size,
125
- description,
126
- };
127
- // Write metadata file
128
- const metadataPath = `${backupPath}.meta.json`;
129
- await fs.writeFile(metadataPath, JSON.stringify(metadata, null, 2));
130
- return backupPath;
131
- }
132
- catch (error) {
133
- throw new FileOperationError('create backup', backupPath, error);
134
- }
135
- }
136
- /**
137
- * List all available backups, sorted by timestamp (newest first).
138
- *
139
- * @returns Promise resolving to array of backup information
140
- * @throws {FileOperationError} If listing fails
141
- *
142
- * @example
143
- * ```typescript
144
- * const backups = await manager.listBackups();
145
- * console.log(`Found ${backups.length} backups`);
146
- *
147
- * for (const backup of backups) {
148
- * console.log(`${backup.fileName}: ${backup.metadata.entityCount} entities`);
149
- * }
150
- * ```
151
- */
152
- async listBackups() {
153
- try {
154
- // Check if backup directory exists
155
- try {
156
- await fs.access(this.backupDir);
157
- }
158
- catch {
159
- // Directory doesn't exist - no backups
160
- return [];
161
- }
162
- const files = await fs.readdir(this.backupDir);
163
- const backupFiles = files.filter(f => f.startsWith('backup_') && f.endsWith('.jsonl'));
164
- const backups = [];
165
- for (const fileName of backupFiles) {
166
- const filePath = join(this.backupDir, fileName);
167
- const metadataPath = `${filePath}.meta.json`;
168
- try {
169
- // Read metadata if it exists
170
- const metadataContent = await fs.readFile(metadataPath, 'utf-8');
171
- const metadata = JSON.parse(metadataContent);
172
- backups.push({
173
- fileName,
174
- filePath,
175
- metadata,
176
- });
177
- }
178
- catch {
179
- // Metadata file doesn't exist or is corrupt - skip this backup
180
- continue;
181
- }
182
- }
183
- // Sort by timestamp (newest first)
184
- backups.sort((a, b) => new Date(b.metadata.timestamp).getTime() - new Date(a.metadata.timestamp).getTime());
185
- return backups;
186
- }
187
- catch (error) {
188
- throw new FileOperationError('list backups', this.backupDir, error);
189
- }
190
- }
191
- /**
192
- * Restore the knowledge graph from a backup file.
193
- *
194
- * CAUTION: This operation overwrites the current graph with backup data.
195
- * Consider creating a backup before restoring.
196
- *
197
- * @param backupPath - Path to the backup file to restore from
198
- * @returns Promise that resolves when restore is complete
199
- * @throws {FileOperationError} If restore fails
200
- *
201
- * @example
202
- * ```typescript
203
- * // List backups and restore the most recent
204
- * const backups = await manager.listBackups();
205
- * if (backups.length > 0) {
206
- * await manager.restoreFromBackup(backups[0].filePath);
207
- * }
208
- *
209
- * // Restore specific backup by path
210
- * await manager.restoreFromBackup('/data/.backups/backup_2024-01-15_10-30-00.jsonl');
211
- * ```
212
- */
213
- async restoreFromBackup(backupPath) {
214
- try {
215
- // Verify backup file exists
216
- await fs.access(backupPath);
217
- // Read backup content
218
- const backupContent = await fs.readFile(backupPath, 'utf-8');
219
- // Write to main graph file
220
- const mainPath = this.storage.getFilePath();
221
- await fs.writeFile(mainPath, backupContent);
222
- // Clear storage cache to force reload
223
- this.storage.clearCache();
224
- }
225
- catch (error) {
226
- throw new FileOperationError('restore from backup', backupPath, error);
227
- }
228
- }
229
- /**
230
- * Delete a specific backup file.
231
- *
232
- * Also deletes the associated metadata file.
233
- *
234
- * @param backupPath - Path to the backup file to delete
235
- * @returns Promise that resolves when deletion is complete
236
- * @throws {FileOperationError} If deletion fails
237
- *
238
- * @example
239
- * ```typescript
240
- * const backups = await manager.listBackups();
241
- * // Delete oldest backup
242
- * if (backups.length > 0) {
243
- * await manager.deleteBackup(backups[backups.length - 1].filePath);
244
- * }
245
- * ```
246
- */
247
- async deleteBackup(backupPath) {
248
- try {
249
- // Delete backup file
250
- await fs.unlink(backupPath);
251
- // Delete metadata file (ignore errors if it doesn't exist)
252
- try {
253
- await fs.unlink(`${backupPath}.meta.json`);
254
- }
255
- catch {
256
- // Metadata file doesn't exist - that's ok
257
- }
258
- }
259
- catch (error) {
260
- throw new FileOperationError('delete backup', backupPath, error);
261
- }
262
- }
263
- /**
264
- * Clean old backups, keeping only the most recent N backups.
265
- *
266
- * Backups are sorted by timestamp, and older backups are deleted.
267
- *
268
- * @param keepCount - Number of recent backups to keep (default: 10)
269
- * @returns Promise resolving to number of backups deleted
270
- * @throws {FileOperationError} If cleanup fails
271
- *
272
- * @example
273
- * ```typescript
274
- * // Keep only the 5 most recent backups
275
- * const deleted = await manager.cleanOldBackups(5);
276
- * console.log(`Deleted ${deleted} old backups`);
277
- *
278
- * // Keep default 10 most recent backups
279
- * await manager.cleanOldBackups();
280
- * ```
281
- */
282
- async cleanOldBackups(keepCount = 10) {
283
- const backups = await this.listBackups();
284
- // If we have fewer backups than keepCount, nothing to delete
285
- if (backups.length <= keepCount) {
286
- return 0;
287
- }
288
- // Delete backups beyond keepCount
289
- const backupsToDelete = backups.slice(keepCount);
290
- let deletedCount = 0;
291
- for (const backup of backupsToDelete) {
292
- try {
293
- await this.deleteBackup(backup.filePath);
294
- deletedCount++;
295
- }
296
- catch {
297
- // Continue deleting other backups even if one fails
298
- continue;
299
- }
300
- }
301
- return deletedCount;
302
- }
303
- /**
304
- * Get the path to the backup directory.
305
- *
306
- * @returns The backup directory path
307
- */
308
- getBackupDir() {
309
- return this.backupDir;
310
- }
311
- }
@@ -1,305 +0,0 @@
1
- /**
2
- * Export Manager
3
- *
4
- * Exports knowledge graphs to various formats (JSON, CSV, GraphML, GEXF, DOT, Markdown, Mermaid).
5
- *
6
- * @module features/ExportManager
7
- */
8
- /**
9
- * Manages knowledge graph exports to multiple formats.
10
- */
11
- export class ExportManager {
12
- /**
13
- * Export graph to specified format.
14
- *
15
- * @param graph - Knowledge graph to export
16
- * @param format - Export format
17
- * @returns Formatted export string
18
- */
19
- exportGraph(graph, format) {
20
- switch (format) {
21
- case 'json':
22
- return this.exportAsJson(graph);
23
- case 'csv':
24
- return this.exportAsCsv(graph);
25
- case 'graphml':
26
- return this.exportAsGraphML(graph);
27
- case 'gexf':
28
- return this.exportAsGEXF(graph);
29
- case 'dot':
30
- return this.exportAsDOT(graph);
31
- case 'markdown':
32
- return this.exportAsMarkdown(graph);
33
- case 'mermaid':
34
- return this.exportAsMermaid(graph);
35
- default:
36
- throw new Error(`Unsupported export format: ${format}`);
37
- }
38
- }
39
- /**
40
- * Export as pretty-printed JSON.
41
- */
42
- exportAsJson(graph) {
43
- return JSON.stringify(graph, null, 2);
44
- }
45
- /**
46
- * Export as CSV with proper escaping.
47
- */
48
- exportAsCsv(graph) {
49
- const lines = [];
50
- const escapeCsvField = (field) => {
51
- if (field === undefined || field === null)
52
- return '';
53
- const str = String(field);
54
- if (str.includes(',') || str.includes('"') || str.includes('\n')) {
55
- return `"${str.replace(/"/g, '""')}"`;
56
- }
57
- return str;
58
- };
59
- // Entities section
60
- lines.push('# ENTITIES');
61
- lines.push('name,entityType,observations,createdAt,lastModified,tags,importance');
62
- for (const entity of graph.entities) {
63
- const observationsStr = entity.observations.join('; ');
64
- const tagsStr = entity.tags ? entity.tags.join('; ') : '';
65
- const importanceStr = entity.importance !== undefined ? String(entity.importance) : '';
66
- lines.push([
67
- escapeCsvField(entity.name),
68
- escapeCsvField(entity.entityType),
69
- escapeCsvField(observationsStr),
70
- escapeCsvField(entity.createdAt),
71
- escapeCsvField(entity.lastModified),
72
- escapeCsvField(tagsStr),
73
- escapeCsvField(importanceStr),
74
- ].join(','));
75
- }
76
- // Relations section
77
- lines.push('');
78
- lines.push('# RELATIONS');
79
- lines.push('from,to,relationType,createdAt,lastModified');
80
- for (const relation of graph.relations) {
81
- lines.push([
82
- escapeCsvField(relation.from),
83
- escapeCsvField(relation.to),
84
- escapeCsvField(relation.relationType),
85
- escapeCsvField(relation.createdAt),
86
- escapeCsvField(relation.lastModified),
87
- ].join(','));
88
- }
89
- return lines.join('\n');
90
- }
91
- /**
92
- * Export as GraphML XML format.
93
- */
94
- exportAsGraphML(graph) {
95
- const lines = [];
96
- const escapeXml = (str) => {
97
- if (str === undefined || str === null)
98
- return '';
99
- return String(str)
100
- .replace(/&/g, '&amp;')
101
- .replace(/</g, '&lt;')
102
- .replace(/>/g, '&gt;')
103
- .replace(/"/g, '&quot;')
104
- .replace(/'/g, '&apos;');
105
- };
106
- lines.push('<?xml version="1.0" encoding="UTF-8"?>');
107
- lines.push('<graphml xmlns="http://graphml.graphdrawing.org/xmlns">');
108
- lines.push(' <key id="d0" for="node" attr.name="entityType" attr.type="string"/>');
109
- lines.push(' <key id="d1" for="node" attr.name="observations" attr.type="string"/>');
110
- lines.push(' <key id="d2" for="node" attr.name="createdAt" attr.type="string"/>');
111
- lines.push(' <key id="d3" for="node" attr.name="lastModified" attr.type="string"/>');
112
- lines.push(' <key id="d4" for="node" attr.name="tags" attr.type="string"/>');
113
- lines.push(' <key id="d5" for="node" attr.name="importance" attr.type="double"/>');
114
- lines.push(' <key id="e0" for="edge" attr.name="relationType" attr.type="string"/>');
115
- lines.push(' <key id="e1" for="edge" attr.name="createdAt" attr.type="string"/>');
116
- lines.push(' <key id="e2" for="edge" attr.name="lastModified" attr.type="string"/>');
117
- lines.push(' <graph id="G" edgedefault="directed">');
118
- // Nodes
119
- for (const entity of graph.entities) {
120
- const nodeId = escapeXml(entity.name);
121
- lines.push(` <node id="${nodeId}">`);
122
- lines.push(` <data key="d0">${escapeXml(entity.entityType)}</data>`);
123
- lines.push(` <data key="d1">${escapeXml(entity.observations.join('; '))}</data>`);
124
- if (entity.createdAt)
125
- lines.push(` <data key="d2">${escapeXml(entity.createdAt)}</data>`);
126
- if (entity.lastModified)
127
- lines.push(` <data key="d3">${escapeXml(entity.lastModified)}</data>`);
128
- if (entity.tags?.length)
129
- lines.push(` <data key="d4">${escapeXml(entity.tags.join('; '))}</data>`);
130
- if (entity.importance !== undefined)
131
- lines.push(` <data key="d5">${entity.importance}</data>`);
132
- lines.push(' </node>');
133
- }
134
- // Edges
135
- let edgeId = 0;
136
- for (const relation of graph.relations) {
137
- const sourceId = escapeXml(relation.from);
138
- const targetId = escapeXml(relation.to);
139
- lines.push(` <edge id="e${edgeId}" source="${sourceId}" target="${targetId}">`);
140
- lines.push(` <data key="e0">${escapeXml(relation.relationType)}</data>`);
141
- if (relation.createdAt)
142
- lines.push(` <data key="e1">${escapeXml(relation.createdAt)}</data>`);
143
- if (relation.lastModified)
144
- lines.push(` <data key="e2">${escapeXml(relation.lastModified)}</data>`);
145
- lines.push(' </edge>');
146
- edgeId++;
147
- }
148
- lines.push(' </graph>');
149
- lines.push('</graphml>');
150
- return lines.join('\n');
151
- }
152
- /**
153
- * Export as GEXF format for Gephi.
154
- */
155
- exportAsGEXF(graph) {
156
- const lines = [];
157
- const escapeXml = (str) => {
158
- if (str === undefined || str === null)
159
- return '';
160
- return String(str)
161
- .replace(/&/g, '&amp;')
162
- .replace(/</g, '&lt;')
163
- .replace(/>/g, '&gt;')
164
- .replace(/"/g, '&quot;')
165
- .replace(/'/g, '&apos;');
166
- };
167
- lines.push('<?xml version="1.0" encoding="UTF-8"?>');
168
- lines.push('<gexf xmlns="http://www.gexf.net/1.2draft" version="1.2">');
169
- lines.push(' <meta>');
170
- lines.push(' <creator>Memory MCP Server</creator>');
171
- lines.push(' </meta>');
172
- lines.push(' <graph mode="static" defaultedgetype="directed">');
173
- lines.push(' <attributes class="node">');
174
- lines.push(' <attribute id="0" title="entityType" type="string"/>');
175
- lines.push(' <attribute id="1" title="observations" type="string"/>');
176
- lines.push(' </attributes>');
177
- lines.push(' <nodes>');
178
- for (const entity of graph.entities) {
179
- const nodeId = escapeXml(entity.name);
180
- lines.push(` <node id="${nodeId}" label="${nodeId}">`);
181
- lines.push(' <attvalues>');
182
- lines.push(` <attvalue for="0" value="${escapeXml(entity.entityType)}"/>`);
183
- lines.push(` <attvalue for="1" value="${escapeXml(entity.observations.join('; '))}"/>`);
184
- lines.push(' </attvalues>');
185
- lines.push(' </node>');
186
- }
187
- lines.push(' </nodes>');
188
- lines.push(' <edges>');
189
- let edgeId = 0;
190
- for (const relation of graph.relations) {
191
- const sourceId = escapeXml(relation.from);
192
- const targetId = escapeXml(relation.to);
193
- const label = escapeXml(relation.relationType);
194
- lines.push(` <edge id="${edgeId}" source="${sourceId}" target="${targetId}" label="${label}"/>`);
195
- edgeId++;
196
- }
197
- lines.push(' </edges>');
198
- lines.push(' </graph>');
199
- lines.push('</gexf>');
200
- return lines.join('\n');
201
- }
202
- /**
203
- * Export as DOT format for GraphViz.
204
- */
205
- exportAsDOT(graph) {
206
- const lines = [];
207
- const escapeDot = (str) => {
208
- return '"' + str.replace(/\\/g, '\\\\').replace(/"/g, '\\"').replace(/\n/g, '\\n') + '"';
209
- };
210
- lines.push('digraph KnowledgeGraph {');
211
- lines.push(' rankdir=LR;');
212
- lines.push(' node [shape=box, style=rounded];');
213
- lines.push('');
214
- for (const entity of graph.entities) {
215
- const nodeId = escapeDot(entity.name);
216
- const label = [`${entity.name}`, `Type: ${entity.entityType}`];
217
- if (entity.tags?.length)
218
- label.push(`Tags: ${entity.tags.join(', ')}`);
219
- const labelStr = escapeDot(label.join('\\n'));
220
- lines.push(` ${nodeId} [label=${labelStr}];`);
221
- }
222
- lines.push('');
223
- for (const relation of graph.relations) {
224
- const fromId = escapeDot(relation.from);
225
- const toId = escapeDot(relation.to);
226
- const label = escapeDot(relation.relationType);
227
- lines.push(` ${fromId} -> ${toId} [label=${label}];`);
228
- }
229
- lines.push('}');
230
- return lines.join('\n');
231
- }
232
- /**
233
- * Export as Markdown documentation.
234
- */
235
- exportAsMarkdown(graph) {
236
- const lines = [];
237
- lines.push('# Knowledge Graph Export');
238
- lines.push('');
239
- lines.push(`**Exported:** ${new Date().toISOString()}`);
240
- lines.push(`**Entities:** ${graph.entities.length}`);
241
- lines.push(`**Relations:** ${graph.relations.length}`);
242
- lines.push('');
243
- lines.push('## Entities');
244
- lines.push('');
245
- for (const entity of graph.entities) {
246
- lines.push(`### ${entity.name}`);
247
- lines.push('');
248
- lines.push(`- **Type:** ${entity.entityType}`);
249
- if (entity.tags?.length)
250
- lines.push(`- **Tags:** ${entity.tags.map(t => `\`${t}\``).join(', ')}`);
251
- if (entity.importance !== undefined)
252
- lines.push(`- **Importance:** ${entity.importance}/10`);
253
- if (entity.observations.length > 0) {
254
- lines.push('');
255
- lines.push('**Observations:**');
256
- for (const obs of entity.observations) {
257
- lines.push(`- ${obs}`);
258
- }
259
- }
260
- lines.push('');
261
- }
262
- if (graph.relations.length > 0) {
263
- lines.push('## Relations');
264
- lines.push('');
265
- for (const relation of graph.relations) {
266
- lines.push(`- **${relation.from}** → *${relation.relationType}* → **${relation.to}**`);
267
- }
268
- lines.push('');
269
- }
270
- return lines.join('\n');
271
- }
272
- /**
273
- * Export as Mermaid diagram.
274
- */
275
- exportAsMermaid(graph) {
276
- const lines = [];
277
- const sanitizeId = (str) => str.replace(/[^a-zA-Z0-9_]/g, '_');
278
- const escapeLabel = (str) => str.replace(/"/g, '#quot;');
279
- lines.push('graph LR');
280
- lines.push(' %% Knowledge Graph');
281
- lines.push('');
282
- const nodeIds = new Map();
283
- for (const entity of graph.entities) {
284
- nodeIds.set(entity.name, sanitizeId(entity.name));
285
- }
286
- for (const entity of graph.entities) {
287
- const nodeId = nodeIds.get(entity.name);
288
- const labelParts = [entity.name, `Type: ${entity.entityType}`];
289
- if (entity.tags?.length)
290
- labelParts.push(`Tags: ${entity.tags.join(', ')}`);
291
- const label = escapeLabel(labelParts.join('<br/>'));
292
- lines.push(` ${nodeId}["${label}"]`);
293
- }
294
- lines.push('');
295
- for (const relation of graph.relations) {
296
- const fromId = nodeIds.get(relation.from);
297
- const toId = nodeIds.get(relation.to);
298
- if (fromId && toId) {
299
- const label = escapeLabel(relation.relationType);
300
- lines.push(` ${fromId} -->|"${label}"| ${toId}`);
301
- }
302
- }
303
- return lines.join('\n');
304
- }
305
- }
@@ -1,50 +0,0 @@
1
- /**
2
- * Import/Export Manager
3
- *
4
- * Orchestrates import and export operations with optional filtering.
5
- *
6
- * @module features/ImportExportManager
7
- */
8
- /**
9
- * Orchestrates import and export operations.
10
- */
11
- export class ImportExportManager {
12
- basicSearch;
13
- exportManager;
14
- importManager;
15
- constructor(exportManager, importManager, basicSearch) {
16
- this.basicSearch = basicSearch;
17
- this.exportManager = exportManager;
18
- this.importManager = importManager;
19
- }
20
- /**
21
- * Export graph to specified format with optional filtering.
22
- *
23
- * @param format - Export format
24
- * @param filter - Optional export filter
25
- * @returns Formatted export string
26
- */
27
- async exportGraph(format, filter) {
28
- let graph;
29
- if (filter) {
30
- graph = await this.basicSearch.searchByDateRange(filter.startDate, filter.endDate, filter.entityType, filter.tags);
31
- }
32
- else {
33
- // Get full graph via basicSearch's storage
34
- graph = await this.basicSearch.storage.loadGraph();
35
- }
36
- return this.exportManager.exportGraph(graph, format);
37
- }
38
- /**
39
- * Import graph from formatted data.
40
- *
41
- * @param format - Import format
42
- * @param data - Import data string
43
- * @param mergeStrategy - How to handle conflicts
44
- * @param dryRun - If true, preview changes without applying
45
- * @returns Import result with statistics
46
- */
47
- async importGraph(format, data, mergeStrategy, dryRun) {
48
- return this.importManager.importGraph(format, data, mergeStrategy, dryRun);
49
- }
50
- }