mcp-memory-keeper 0.10.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 (98) hide show
  1. package/CHANGELOG.md +433 -0
  2. package/LICENSE +21 -0
  3. package/README.md +1051 -0
  4. package/bin/mcp-memory-keeper +52 -0
  5. package/dist/__tests__/helpers/database-test-helper.js +160 -0
  6. package/dist/__tests__/helpers/test-server.js +92 -0
  7. package/dist/__tests__/integration/advanced-features.test.js +614 -0
  8. package/dist/__tests__/integration/backward-compatibility.test.js +245 -0
  9. package/dist/__tests__/integration/batchOperationsE2E.test.js +396 -0
  10. package/dist/__tests__/integration/batchOperationsHandler.test.js +1230 -0
  11. package/dist/__tests__/integration/channelManagementHandler.test.js +1291 -0
  12. package/dist/__tests__/integration/channels.test.js +376 -0
  13. package/dist/__tests__/integration/checkpoint.test.js +251 -0
  14. package/dist/__tests__/integration/concurrent-access.test.js +190 -0
  15. package/dist/__tests__/integration/context-operations.test.js +243 -0
  16. package/dist/__tests__/integration/contextDiff.test.js +852 -0
  17. package/dist/__tests__/integration/contextDiffHandler.test.js +976 -0
  18. package/dist/__tests__/integration/contextExportHandler.test.js +510 -0
  19. package/dist/__tests__/integration/contextGetPaginationDefaults.test.js +298 -0
  20. package/dist/__tests__/integration/contextReassignChannelHandler.test.js +908 -0
  21. package/dist/__tests__/integration/contextRelationshipsHandler.test.js +1151 -0
  22. package/dist/__tests__/integration/contextSearch.test.js +938 -0
  23. package/dist/__tests__/integration/contextSearchHandler.test.js +552 -0
  24. package/dist/__tests__/integration/contextWatchActual.test.js +165 -0
  25. package/dist/__tests__/integration/contextWatchHandler.test.js +1500 -0
  26. package/dist/__tests__/integration/cross-session-sharing.test.js +302 -0
  27. package/dist/__tests__/integration/database-initialization.test.js +134 -0
  28. package/dist/__tests__/integration/enhanced-context-operations.test.js +1082 -0
  29. package/dist/__tests__/integration/enhancedContextGetHandler.test.js +915 -0
  30. package/dist/__tests__/integration/enhancedContextTimelineHandler.test.js +716 -0
  31. package/dist/__tests__/integration/error-cases.test.js +407 -0
  32. package/dist/__tests__/integration/export-import.test.js +367 -0
  33. package/dist/__tests__/integration/feature-flags.test.js +542 -0
  34. package/dist/__tests__/integration/file-operations.test.js +264 -0
  35. package/dist/__tests__/integration/git-integration.test.js +237 -0
  36. package/dist/__tests__/integration/index-tools.test.js +496 -0
  37. package/dist/__tests__/integration/issue11-actual-bug-demo.test.js +304 -0
  38. package/dist/__tests__/integration/issue11-search-filters-bug.test.js +561 -0
  39. package/dist/__tests__/integration/issue12-checkpoint-restore-behavior.test.js +621 -0
  40. package/dist/__tests__/integration/issue13-key-validation.test.js +433 -0
  41. package/dist/__tests__/integration/knowledge-graph.test.js +338 -0
  42. package/dist/__tests__/integration/migrations.test.js +528 -0
  43. package/dist/__tests__/integration/multi-agent.test.js +546 -0
  44. package/dist/__tests__/integration/pagination-critical-fix.test.js +296 -0
  45. package/dist/__tests__/integration/paginationDefaultsHandler.test.js +600 -0
  46. package/dist/__tests__/integration/project-directory.test.js +283 -0
  47. package/dist/__tests__/integration/resource-cleanup.test.js +149 -0
  48. package/dist/__tests__/integration/retention.test.js +513 -0
  49. package/dist/__tests__/integration/search.test.js +333 -0
  50. package/dist/__tests__/integration/semantic-search.test.js +266 -0
  51. package/dist/__tests__/integration/server-initialization.test.js +307 -0
  52. package/dist/__tests__/integration/session-management.test.js +219 -0
  53. package/dist/__tests__/integration/simplified-sharing.test.js +346 -0
  54. package/dist/__tests__/integration/smart-compaction.test.js +230 -0
  55. package/dist/__tests__/integration/summarization.test.js +308 -0
  56. package/dist/__tests__/integration/watcher-migration-validation.test.js +544 -0
  57. package/dist/__tests__/security/input-validation.test.js +115 -0
  58. package/dist/__tests__/utils/agents.test.js +473 -0
  59. package/dist/__tests__/utils/database.test.js +177 -0
  60. package/dist/__tests__/utils/git.test.js +122 -0
  61. package/dist/__tests__/utils/knowledge-graph.test.js +297 -0
  62. package/dist/__tests__/utils/migrationHealthCheck.test.js +302 -0
  63. package/dist/__tests__/utils/project-directory-messages.test.js +188 -0
  64. package/dist/__tests__/utils/timezone-safe-dates.js +119 -0
  65. package/dist/__tests__/utils/validation.test.js +200 -0
  66. package/dist/__tests__/utils/vector-store.test.js +231 -0
  67. package/dist/handlers/contextWatchHandlers.js +206 -0
  68. package/dist/index.js +4310 -0
  69. package/dist/index.phase1.backup.js +410 -0
  70. package/dist/index.phase2.backup.js +704 -0
  71. package/dist/migrations/003_add_channels.js +174 -0
  72. package/dist/migrations/004_add_context_watch.js +151 -0
  73. package/dist/migrations/005_add_context_watch.js +98 -0
  74. package/dist/migrations/simplify-sharing.js +117 -0
  75. package/dist/repositories/BaseRepository.js +30 -0
  76. package/dist/repositories/CheckpointRepository.js +140 -0
  77. package/dist/repositories/ContextRepository.js +1873 -0
  78. package/dist/repositories/FileRepository.js +104 -0
  79. package/dist/repositories/RepositoryManager.js +62 -0
  80. package/dist/repositories/SessionRepository.js +66 -0
  81. package/dist/repositories/WatcherRepository.js +252 -0
  82. package/dist/repositories/index.js +15 -0
  83. package/dist/server.js +384 -0
  84. package/dist/test-helpers/database-helper.js +128 -0
  85. package/dist/types/entities.js +3 -0
  86. package/dist/utils/agents.js +791 -0
  87. package/dist/utils/channels.js +150 -0
  88. package/dist/utils/database.js +731 -0
  89. package/dist/utils/feature-flags.js +476 -0
  90. package/dist/utils/git.js +145 -0
  91. package/dist/utils/knowledge-graph.js +264 -0
  92. package/dist/utils/migrationHealthCheck.js +373 -0
  93. package/dist/utils/migrations.js +452 -0
  94. package/dist/utils/retention.js +460 -0
  95. package/dist/utils/timestamps.js +112 -0
  96. package/dist/utils/validation.js +296 -0
  97. package/dist/utils/vector-store.js +247 -0
  98. package/package.json +84 -0
@@ -0,0 +1,338 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ const database_1 = require("../../utils/database");
37
+ const knowledge_graph_1 = require("../../utils/knowledge-graph");
38
+ const os = __importStar(require("os"));
39
+ const path = __importStar(require("path"));
40
+ const fs = __importStar(require("fs"));
41
+ const uuid_1 = require("uuid");
42
+ describe('Knowledge Graph Integration Tests', () => {
43
+ let dbManager;
44
+ let knowledgeGraph;
45
+ let tempDbPath;
46
+ let db;
47
+ let testSessionId;
48
+ beforeEach(() => {
49
+ tempDbPath = path.join(os.tmpdir(), `test-kg-integration-${Date.now()}.db`);
50
+ dbManager = new database_1.DatabaseManager({
51
+ filename: tempDbPath,
52
+ maxSize: 10 * 1024 * 1024,
53
+ walMode: true,
54
+ });
55
+ db = dbManager.getDatabase();
56
+ knowledgeGraph = new knowledge_graph_1.KnowledgeGraphManager(db);
57
+ // Create test session
58
+ testSessionId = (0, uuid_1.v4)();
59
+ db.prepare('INSERT INTO sessions (id, name, description) VALUES (?, ?, ?)').run(testSessionId, 'KG Integration Test', 'Testing knowledge graph integration');
60
+ });
61
+ afterEach(() => {
62
+ dbManager.close();
63
+ try {
64
+ fs.unlinkSync(tempDbPath);
65
+ fs.unlinkSync(`${tempDbPath}-wal`);
66
+ fs.unlinkSync(`${tempDbPath}-shm`);
67
+ }
68
+ catch (_e) {
69
+ // Ignore
70
+ }
71
+ });
72
+ describe('context_analyze', () => {
73
+ beforeEach(() => {
74
+ // Add some context items to analyze
75
+ const items = [
76
+ {
77
+ key: 'task_auth',
78
+ value: 'Working on AuthService class that implements authentication using JWT tokens',
79
+ category: 'task',
80
+ },
81
+ {
82
+ key: 'decision_db',
83
+ value: 'UserModel extends BaseModel and uses PostgreSQL database',
84
+ category: 'decision',
85
+ },
86
+ {
87
+ key: 'progress_api',
88
+ value: 'The function validateToken calls checkExpiry and getUserById',
89
+ category: 'progress',
90
+ },
91
+ {
92
+ key: 'note_files',
93
+ value: 'Modified files: auth.service.ts, user.model.ts, and token.utils.ts',
94
+ category: 'note',
95
+ },
96
+ ];
97
+ items.forEach(item => {
98
+ db.prepare('INSERT INTO context_items (id, session_id, key, value, category) VALUES (?, ?, ?, ?, ?)').run((0, uuid_1.v4)(), testSessionId, item.key, item.value, item.category);
99
+ });
100
+ });
101
+ it('should analyze all context items and extract entities', () => {
102
+ // Simulate context_analyze tool call
103
+ const items = db
104
+ .prepare('SELECT * FROM context_items WHERE session_id = ?')
105
+ .all(testSessionId);
106
+ let entitiesCreated = 0;
107
+ let _relationsCreated = 0;
108
+ for (const item of items) {
109
+ const analysis = knowledgeGraph.analyzeContext(testSessionId, item.value);
110
+ for (const entityData of analysis.entities) {
111
+ const existing = knowledgeGraph.findEntity(testSessionId, entityData.name, entityData.type);
112
+ if (!existing) {
113
+ knowledgeGraph.createEntity(testSessionId, entityData.type, entityData.name, {
114
+ confidence: entityData.confidence,
115
+ source: item.key,
116
+ });
117
+ entitiesCreated++;
118
+ }
119
+ }
120
+ for (const relationData of analysis.relations) {
121
+ const subject = knowledgeGraph.findEntity(testSessionId, relationData.subject);
122
+ const object = knowledgeGraph.findEntity(testSessionId, relationData.object);
123
+ if (subject && object) {
124
+ knowledgeGraph.createRelation(testSessionId, subject.id, relationData.predicate, object.id, relationData.confidence);
125
+ _relationsCreated++;
126
+ }
127
+ }
128
+ }
129
+ expect(entitiesCreated).toBeGreaterThan(0);
130
+ // Verify specific entities were created
131
+ expect(knowledgeGraph.findEntity(testSessionId, 'AuthService')).toBeDefined();
132
+ expect(knowledgeGraph.findEntity(testSessionId, 'auth.service.ts')).toBeDefined();
133
+ expect(knowledgeGraph.findEntity(testSessionId, 'validateToken')).toBeDefined();
134
+ });
135
+ it('should analyze specific categories only', () => {
136
+ const categories = ['task', 'decision'];
137
+ const items = db
138
+ .prepare(`SELECT * FROM context_items WHERE session_id = ? AND category IN (${categories.map(() => '?').join(',')})`)
139
+ .all(testSessionId, ...categories);
140
+ expect(items).toHaveLength(2);
141
+ for (const item of items) {
142
+ const analysis = knowledgeGraph.analyzeContext(testSessionId, item.value);
143
+ expect(analysis.entities.length).toBeGreaterThan(0);
144
+ }
145
+ });
146
+ });
147
+ describe('context_find_related', () => {
148
+ beforeEach(() => {
149
+ // Create a network of entities
150
+ const authService = knowledgeGraph.createEntity(testSessionId, 'class', 'AuthService');
151
+ const userModel = knowledgeGraph.createEntity(testSessionId, 'class', 'UserModel');
152
+ const tokenUtil = knowledgeGraph.createEntity(testSessionId, 'module', 'TokenUtil');
153
+ const database = knowledgeGraph.createEntity(testSessionId, 'database', 'PostgreSQL');
154
+ const validateFunc = knowledgeGraph.createEntity(testSessionId, 'function', 'validateToken');
155
+ // Create relations
156
+ knowledgeGraph.createRelation(testSessionId, authService.id, 'uses', userModel.id);
157
+ knowledgeGraph.createRelation(testSessionId, authService.id, 'imports', tokenUtil.id);
158
+ knowledgeGraph.createRelation(testSessionId, userModel.id, 'stores_in', database.id);
159
+ knowledgeGraph.createRelation(testSessionId, authService.id, 'contains', validateFunc.id);
160
+ // Add a context item that references AuthService
161
+ db.prepare('INSERT INTO context_items (id, session_id, key, value) VALUES (?, ?, ?, ?)').run((0, uuid_1.v4)(), testSessionId, 'auth_task', 'Working on AuthService authentication');
162
+ });
163
+ it('should find related entities by entity name', () => {
164
+ const entity = knowledgeGraph.findEntity(testSessionId, 'AuthService');
165
+ expect(entity).toBeDefined();
166
+ const connected = knowledgeGraph.getConnectedEntities(entity.id, 2);
167
+ expect(connected.size).toBeGreaterThan(1);
168
+ // Should include AuthService and its connections
169
+ const entities = Array.from(connected).map(id => {
170
+ const e = db.prepare('SELECT * FROM entities WHERE id = ?').get(id);
171
+ return e.name;
172
+ });
173
+ expect(entities).toContain('AuthService');
174
+ expect(entities).toContain('UserModel');
175
+ expect(entities).toContain('TokenUtil');
176
+ expect(entities).toContain('validateToken');
177
+ });
178
+ it('should find related entities by context key', () => {
179
+ const contextItem = db
180
+ .prepare('SELECT * FROM context_items WHERE session_id = ? AND key = ?')
181
+ .get(testSessionId, 'auth_task');
182
+ expect(contextItem).toBeDefined();
183
+ // Extract entity from context
184
+ const analysis = knowledgeGraph.analyzeContext(testSessionId, contextItem.value);
185
+ expect(analysis.entities.length).toBeGreaterThan(0);
186
+ const entity = knowledgeGraph.findEntity(testSessionId, 'AuthService');
187
+ expect(entity).toBeDefined();
188
+ });
189
+ it('should filter by relation types', () => {
190
+ const entity = knowledgeGraph.findEntity(testSessionId, 'AuthService');
191
+ const relations = knowledgeGraph.getRelations(entity.id);
192
+ const usesRelations = relations.filter(r => r.predicate === 'uses');
193
+ const importsRelations = relations.filter(r => r.predicate === 'imports');
194
+ expect(usesRelations.length).toBeGreaterThan(0);
195
+ expect(importsRelations.length).toBeGreaterThan(0);
196
+ });
197
+ });
198
+ describe('context_visualize', () => {
199
+ beforeEach(() => {
200
+ // Create entities for visualization
201
+ knowledgeGraph.createEntity(testSessionId, 'class', 'User');
202
+ knowledgeGraph.createEntity(testSessionId, 'class', 'Product');
203
+ knowledgeGraph.createEntity(testSessionId, 'service', 'AuthService');
204
+ // Create context items with different categories and times
205
+ const now = new Date();
206
+ for (let i = 0; i < 10; i++) {
207
+ const category = ['task', 'decision', 'progress'][i % 3];
208
+ const priority = ['high', 'normal', 'low'][i % 3];
209
+ db.prepare(`INSERT INTO context_items
210
+ (id, session_id, key, value, category, priority, created_at)
211
+ VALUES (?, ?, ?, ?, ?, ?, ?)`).run((0, uuid_1.v4)(), testSessionId, `item_${i}`, `Test item ${i}`, category, priority, new Date(now.getTime() - i * 3600000).toISOString() // 1 hour apart
212
+ );
213
+ }
214
+ });
215
+ it('should generate graph visualization data', () => {
216
+ const user = knowledgeGraph.findEntity(testSessionId, 'User');
217
+ const auth = knowledgeGraph.findEntity(testSessionId, 'AuthService');
218
+ knowledgeGraph.createRelation(testSessionId, auth.id, 'validates', user.id);
219
+ const graphData = knowledgeGraph.getGraphData(testSessionId);
220
+ expect(graphData.nodes.length).toBeGreaterThan(0);
221
+ expect(graphData.edges.length).toBeGreaterThan(0);
222
+ // Verify structure
223
+ expect(graphData.nodes[0]).toHaveProperty('id');
224
+ expect(graphData.nodes[0]).toHaveProperty('type');
225
+ expect(graphData.nodes[0]).toHaveProperty('name');
226
+ expect(graphData.edges[0]).toHaveProperty('source');
227
+ expect(graphData.edges[0]).toHaveProperty('target');
228
+ expect(graphData.edges[0]).toHaveProperty('predicate');
229
+ });
230
+ it('should generate timeline visualization data', () => {
231
+ const timeline = db
232
+ .prepare(`
233
+ SELECT
234
+ strftime('%Y-%m-%d %H:00', created_at) as hour,
235
+ COUNT(*) as events,
236
+ GROUP_CONCAT(DISTINCT category) as categories
237
+ FROM context_items
238
+ WHERE session_id = ?
239
+ GROUP BY hour
240
+ ORDER BY hour DESC
241
+ LIMIT 24
242
+ `)
243
+ .all(testSessionId);
244
+ expect(timeline.length).toBeGreaterThan(0);
245
+ expect(timeline[0]).toHaveProperty('hour');
246
+ expect(timeline[0]).toHaveProperty('events');
247
+ expect(timeline[0]).toHaveProperty('categories');
248
+ });
249
+ it('should generate heatmap visualization data', () => {
250
+ const heatmap = db
251
+ .prepare(`
252
+ SELECT
253
+ category,
254
+ priority,
255
+ COUNT(*) as count
256
+ FROM context_items
257
+ WHERE session_id = ?
258
+ GROUP BY category, priority
259
+ `)
260
+ .all(testSessionId);
261
+ expect(heatmap.length).toBeGreaterThan(0);
262
+ expect(heatmap[0]).toHaveProperty('category');
263
+ expect(heatmap[0]).toHaveProperty('priority');
264
+ expect(heatmap[0]).toHaveProperty('count');
265
+ // Verify we have data for different category/priority combinations
266
+ const categories = new Set(heatmap.map(h => h.category));
267
+ const priorities = new Set(heatmap.map(h => h.priority));
268
+ expect(categories.size).toBeGreaterThanOrEqual(2);
269
+ expect(priorities.size).toBeGreaterThanOrEqual(2);
270
+ });
271
+ });
272
+ describe('Complex scenarios', () => {
273
+ it('should handle code analysis workflow', () => {
274
+ // Simulate analyzing a codebase
275
+ const codeContext = [
276
+ 'The AuthController class handles authentication endpoints',
277
+ 'It uses AuthService which implements IAuthService interface',
278
+ 'AuthService calls UserRepository to fetch user data',
279
+ 'The validateToken function uses jwt.verify from jsonwebtoken library',
280
+ 'Files involved: auth.controller.ts, auth.service.ts, user.repository.ts',
281
+ ];
282
+ // Analyze each piece of context
283
+ const allEntities = new Set();
284
+ const allRelations = [];
285
+ codeContext.forEach(text => {
286
+ const analysis = knowledgeGraph.analyzeContext(testSessionId, text);
287
+ analysis.entities.forEach(e => {
288
+ if (!knowledgeGraph.findEntity(testSessionId, e.name, e.type)) {
289
+ knowledgeGraph.createEntity(testSessionId, e.type, e.name);
290
+ allEntities.add(e.name);
291
+ }
292
+ });
293
+ analysis.relations.forEach(r => {
294
+ const subject = knowledgeGraph.findEntity(testSessionId, r.subject);
295
+ const object = knowledgeGraph.findEntity(testSessionId, r.object);
296
+ if (subject && object) {
297
+ knowledgeGraph.createRelation(testSessionId, subject.id, r.predicate, object.id, r.confidence);
298
+ allRelations.push(r);
299
+ }
300
+ });
301
+ });
302
+ // Verify entities were extracted
303
+ expect(allEntities.size).toBeGreaterThan(5);
304
+ expect(allEntities).toContain('AuthController');
305
+ expect(allEntities).toContain('AuthService');
306
+ expect(allEntities).toContain('auth.controller.ts');
307
+ // Verify relationships
308
+ expect(allRelations.length).toBeGreaterThan(0);
309
+ // Test finding related entities
310
+ const authService = knowledgeGraph.findEntity(testSessionId, 'AuthService');
311
+ if (authService) {
312
+ const connected = knowledgeGraph.getConnectedEntities(authService.id, 2);
313
+ expect(connected.size).toBeGreaterThan(1);
314
+ }
315
+ });
316
+ it('should maintain graph consistency across operations', () => {
317
+ // Create initial graph
318
+ const module1 = knowledgeGraph.createEntity(testSessionId, 'module', 'CoreModule');
319
+ const module2 = knowledgeGraph.createEntity(testSessionId, 'module', 'UtilsModule');
320
+ const service = knowledgeGraph.createEntity(testSessionId, 'service', 'DataService');
321
+ knowledgeGraph.createRelation(testSessionId, module1.id, 'imports', module2.id);
322
+ knowledgeGraph.createRelation(testSessionId, module1.id, 'provides', service.id);
323
+ // Add observations
324
+ knowledgeGraph.addObservation(service.id, 'Handles data transformation');
325
+ // Verify graph integrity
326
+ const graphData = knowledgeGraph.getGraphData(testSessionId);
327
+ expect(graphData.nodes).toHaveLength(3);
328
+ expect(graphData.edges).toHaveLength(2);
329
+ // Test pruning doesn't remove entities with relations
330
+ const pruned = knowledgeGraph.pruneOrphanedEntities(testSessionId);
331
+ expect(pruned).toBe(0);
332
+ // All entities should still exist
333
+ expect(knowledgeGraph.findEntity(testSessionId, 'CoreModule')).toBeDefined();
334
+ expect(knowledgeGraph.findEntity(testSessionId, 'UtilsModule')).toBeDefined();
335
+ expect(knowledgeGraph.findEntity(testSessionId, 'DataService')).toBeDefined();
336
+ });
337
+ });
338
+ });