@smallironman/mcp-memory-keeper 0.12.2-fork1

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 (110) hide show
  1. package/CHANGELOG.md +542 -0
  2. package/LICENSE +21 -0
  3. package/README.md +1281 -0
  4. package/bin/mcp-memory-keeper +54 -0
  5. package/dist/__tests__/e2e/issue33-reproduce.test.js +234 -0
  6. package/dist/__tests__/e2e/server-e2e.test.js +341 -0
  7. package/dist/__tests__/helpers/database-test-helper.js +160 -0
  8. package/dist/__tests__/helpers/test-server.js +92 -0
  9. package/dist/__tests__/integration/advanced-features.test.js +614 -0
  10. package/dist/__tests__/integration/backward-compatibility.test.js +245 -0
  11. package/dist/__tests__/integration/batchOperationsE2E.test.js +396 -0
  12. package/dist/__tests__/integration/batchOperationsHandler.test.js +1230 -0
  13. package/dist/__tests__/integration/channelManagementHandler.test.js +1291 -0
  14. package/dist/__tests__/integration/channels.test.js +376 -0
  15. package/dist/__tests__/integration/checkpoint.test.js +251 -0
  16. package/dist/__tests__/integration/concurrent-access.test.js +190 -0
  17. package/dist/__tests__/integration/context-operations.test.js +243 -0
  18. package/dist/__tests__/integration/contextDiff.test.js +852 -0
  19. package/dist/__tests__/integration/contextDiffHandler.test.js +976 -0
  20. package/dist/__tests__/integration/contextExportHandler.test.js +510 -0
  21. package/dist/__tests__/integration/contextGetPaginationDefaults.test.js +298 -0
  22. package/dist/__tests__/integration/contextReassignChannelHandler.test.js +908 -0
  23. package/dist/__tests__/integration/contextRelationshipsHandler.test.js +1151 -0
  24. package/dist/__tests__/integration/contextSearch.test.js +1054 -0
  25. package/dist/__tests__/integration/contextSearchHandler.test.js +552 -0
  26. package/dist/__tests__/integration/contextWatchActual.test.js +165 -0
  27. package/dist/__tests__/integration/contextWatchHandler.test.js +1500 -0
  28. package/dist/__tests__/integration/database-initialization.test.js +134 -0
  29. package/dist/__tests__/integration/enhanced-context-operations.test.js +1082 -0
  30. package/dist/__tests__/integration/enhancedContextGetHandler.test.js +915 -0
  31. package/dist/__tests__/integration/enhancedContextTimelineHandler.test.js +716 -0
  32. package/dist/__tests__/integration/error-cases.test.js +411 -0
  33. package/dist/__tests__/integration/export-import.test.js +367 -0
  34. package/dist/__tests__/integration/feature-flags.test.js +542 -0
  35. package/dist/__tests__/integration/file-operations.test.js +264 -0
  36. package/dist/__tests__/integration/filterBySessionId.test.js +251 -0
  37. package/dist/__tests__/integration/git-integration.test.js +241 -0
  38. package/dist/__tests__/integration/index-tools.test.js +496 -0
  39. package/dist/__tests__/integration/issue11-actual-bug-demo.test.js +304 -0
  40. package/dist/__tests__/integration/issue11-search-filters-bug.test.js +561 -0
  41. package/dist/__tests__/integration/issue12-checkpoint-restore-behavior.test.js +621 -0
  42. package/dist/__tests__/integration/issue13-key-validation.test.js +433 -0
  43. package/dist/__tests__/integration/issue24-final-fix.test.js +241 -0
  44. package/dist/__tests__/integration/issue24-fix-validation.test.js +158 -0
  45. package/dist/__tests__/integration/issue24-reproduce.test.js +225 -0
  46. package/dist/__tests__/integration/issue24-token-limit.test.js +199 -0
  47. package/dist/__tests__/integration/issue33-array-items-schema.test.js +165 -0
  48. package/dist/__tests__/integration/knowledge-graph.test.js +338 -0
  49. package/dist/__tests__/integration/migrations.test.js +528 -0
  50. package/dist/__tests__/integration/multi-agent.test.js +546 -0
  51. package/dist/__tests__/integration/pagination-critical-fix.test.js +296 -0
  52. package/dist/__tests__/integration/paginationDefaultsHandler.test.js +600 -0
  53. package/dist/__tests__/integration/project-directory.test.js +291 -0
  54. package/dist/__tests__/integration/resource-cleanup.test.js +149 -0
  55. package/dist/__tests__/integration/retention.test.js +513 -0
  56. package/dist/__tests__/integration/search.test.js +333 -0
  57. package/dist/__tests__/integration/semantic-search.test.js +266 -0
  58. package/dist/__tests__/integration/server-initialization.test.js +305 -0
  59. package/dist/__tests__/integration/session-management.test.js +219 -0
  60. package/dist/__tests__/integration/simplified-sharing.test.js +346 -0
  61. package/dist/__tests__/integration/smart-compaction.test.js +230 -0
  62. package/dist/__tests__/integration/summarization.test.js +308 -0
  63. package/dist/__tests__/integration/tokenLimitEnforcement.test.js +134 -0
  64. package/dist/__tests__/integration/tool-profiles-integration.test.js +150 -0
  65. package/dist/__tests__/integration/watcher-migration-validation.test.js +544 -0
  66. package/dist/__tests__/security/input-validation.test.js +115 -0
  67. package/dist/__tests__/utils/agents.test.js +473 -0
  68. package/dist/__tests__/utils/database.test.js +177 -0
  69. package/dist/__tests__/utils/git.test.js +122 -0
  70. package/dist/__tests__/utils/knowledge-graph.test.js +297 -0
  71. package/dist/__tests__/utils/migrationHealthCheck.test.js +302 -0
  72. package/dist/__tests__/utils/project-directory-messages.test.js +192 -0
  73. package/dist/__tests__/utils/timezone-safe-dates.js +119 -0
  74. package/dist/__tests__/utils/token-limits.test.js +225 -0
  75. package/dist/__tests__/utils/tool-profiles.test.js +374 -0
  76. package/dist/__tests__/utils/validation.test.js +200 -0
  77. package/dist/__tests__/utils/vector-store.test.js +231 -0
  78. package/dist/handlers/contextWatchHandlers.js +206 -0
  79. package/dist/index.js +4425 -0
  80. package/dist/migrations/003_add_channels.js +174 -0
  81. package/dist/migrations/004_add_context_watch.js +151 -0
  82. package/dist/migrations/005_add_context_watch.js +98 -0
  83. package/dist/migrations/simplify-sharing.js +117 -0
  84. package/dist/repositories/BaseRepository.js +30 -0
  85. package/dist/repositories/CheckpointRepository.js +140 -0
  86. package/dist/repositories/ContextRepository.js +2017 -0
  87. package/dist/repositories/FileRepository.js +104 -0
  88. package/dist/repositories/RepositoryManager.js +62 -0
  89. package/dist/repositories/SessionRepository.js +66 -0
  90. package/dist/repositories/WatcherRepository.js +252 -0
  91. package/dist/repositories/index.js +15 -0
  92. package/dist/test-helpers/database-helper.js +128 -0
  93. package/dist/types/entities.js +3 -0
  94. package/dist/utils/agents.js +791 -0
  95. package/dist/utils/channels.js +150 -0
  96. package/dist/utils/database.js +780 -0
  97. package/dist/utils/feature-flags.js +476 -0
  98. package/dist/utils/git.js +145 -0
  99. package/dist/utils/knowledge-graph.js +264 -0
  100. package/dist/utils/migrationHealthCheck.js +373 -0
  101. package/dist/utils/migrations.js +452 -0
  102. package/dist/utils/retention.js +460 -0
  103. package/dist/utils/timestamps.js +112 -0
  104. package/dist/utils/token-limits.js +350 -0
  105. package/dist/utils/tool-profiles.js +242 -0
  106. package/dist/utils/validation.js +296 -0
  107. package/dist/utils/vector-store.js +247 -0
  108. package/examples/config.json +31 -0
  109. package/examples/project-directory-setup.md +114 -0
  110. package/package.json +85 -0
@@ -0,0 +1,298 @@
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 globals_1 = require("@jest/globals");
37
+ const database_1 = require("../../utils/database");
38
+ const ContextRepository_1 = require("../../repositories/ContextRepository");
39
+ const SessionRepository_1 = require("../../repositories/SessionRepository");
40
+ const os = __importStar(require("os"));
41
+ const path = __importStar(require("path"));
42
+ const fs = __importStar(require("fs"));
43
+ const uuid_1 = require("uuid");
44
+ (0, globals_1.describe)('context_get Pagination Defaults', () => {
45
+ let dbManager;
46
+ let tempDbPath;
47
+ let db;
48
+ let contextRepo;
49
+ let sessionRepo;
50
+ let testSessionId;
51
+ (0, globals_1.beforeEach)(() => {
52
+ tempDbPath = path.join(os.tmpdir(), `test-context-get-pagination-${Date.now()}.db`);
53
+ dbManager = new database_1.DatabaseManager({
54
+ filename: tempDbPath,
55
+ maxSize: 10 * 1024 * 1024,
56
+ walMode: true,
57
+ });
58
+ db = dbManager.getDatabase();
59
+ contextRepo = new ContextRepository_1.ContextRepository(dbManager);
60
+ sessionRepo = new SessionRepository_1.SessionRepository(dbManager);
61
+ // Create test session
62
+ const session = sessionRepo.create({
63
+ name: 'Test Session',
64
+ description: 'Testing context_get pagination',
65
+ });
66
+ testSessionId = session.id;
67
+ });
68
+ (0, globals_1.afterEach)(() => {
69
+ dbManager.close();
70
+ try {
71
+ fs.unlinkSync(tempDbPath);
72
+ fs.unlinkSync(`${tempDbPath}-wal`);
73
+ fs.unlinkSync(`${tempDbPath}-shm`);
74
+ }
75
+ catch (_e) {
76
+ // Ignore
77
+ }
78
+ });
79
+ (0, globals_1.describe)('Default Limit Behavior', () => {
80
+ (0, globals_1.beforeEach)(() => {
81
+ // Create 150 test items to test default limit
82
+ for (let i = 0; i < 150; i++) {
83
+ contextRepo.save(testSessionId, {
84
+ key: `test.item.${i.toString().padStart(3, '0')}`,
85
+ value: `Test value ${i}`,
86
+ category: i % 2 === 0 ? 'task' : 'note',
87
+ priority: i % 3 === 0 ? 'high' : 'normal',
88
+ });
89
+ }
90
+ });
91
+ (0, globals_1.it)('should apply default limit of 100 when limit is not provided', () => {
92
+ const result = contextRepo.queryEnhanced({
93
+ sessionId: testSessionId,
94
+ // No limit specified
95
+ });
96
+ (0, globals_1.expect)(result.items.length).toBe(100);
97
+ (0, globals_1.expect)(result.totalCount).toBe(150);
98
+ });
99
+ (0, globals_1.it)('should apply default limit of 100 when limit is undefined', () => {
100
+ const result = contextRepo.queryEnhanced({
101
+ sessionId: testSessionId,
102
+ limit: undefined,
103
+ });
104
+ (0, globals_1.expect)(result.items.length).toBe(100);
105
+ (0, globals_1.expect)(result.totalCount).toBe(150);
106
+ });
107
+ (0, globals_1.it)('should respect explicit limit when provided', () => {
108
+ const result = contextRepo.queryEnhanced({
109
+ sessionId: testSessionId,
110
+ limit: 50,
111
+ });
112
+ (0, globals_1.expect)(result.items.length).toBe(50);
113
+ (0, globals_1.expect)(result.totalCount).toBe(150);
114
+ });
115
+ (0, globals_1.it)('should handle limit of 0 as unlimited', () => {
116
+ const result = contextRepo.queryEnhanced({
117
+ sessionId: testSessionId,
118
+ limit: 0,
119
+ });
120
+ (0, globals_1.expect)(result.items.length).toBe(150); // All items
121
+ (0, globals_1.expect)(result.totalCount).toBe(150);
122
+ });
123
+ (0, globals_1.it)('should treat negative limit as default (100)', () => {
124
+ const result = contextRepo.queryEnhanced({
125
+ sessionId: testSessionId,
126
+ limit: -1,
127
+ });
128
+ (0, globals_1.expect)(result.items.length).toBe(100);
129
+ (0, globals_1.expect)(result.totalCount).toBe(150);
130
+ });
131
+ (0, globals_1.it)('should apply default sort (created_desc) when not specified', () => {
132
+ const result = contextRepo.queryEnhanced({
133
+ sessionId: testSessionId,
134
+ // No sort specified
135
+ });
136
+ // Items should be sorted by created_at descending
137
+ for (let i = 1; i < result.items.length; i++) {
138
+ const prevDate = new Date(result.items[i - 1].created_at);
139
+ const currDate = new Date(result.items[i].created_at);
140
+ (0, globals_1.expect)(prevDate.getTime()).toBeGreaterThanOrEqual(currDate.getTime());
141
+ }
142
+ });
143
+ });
144
+ (0, globals_1.describe)('Pagination with Filters', () => {
145
+ (0, globals_1.beforeEach)(() => {
146
+ // Create items with different categories
147
+ for (let i = 0; i < 120; i++) {
148
+ contextRepo.save(testSessionId, {
149
+ key: `filtered.item.${i}`,
150
+ value: `Filtered value ${i}`,
151
+ category: i % 3 === 0 ? 'task' : i % 3 === 1 ? 'note' : 'decision',
152
+ priority: i % 2 === 0 ? 'high' : 'normal',
153
+ });
154
+ }
155
+ });
156
+ (0, globals_1.it)('should apply default limit with category filter', () => {
157
+ const result = contextRepo.queryEnhanced({
158
+ sessionId: testSessionId,
159
+ category: 'task',
160
+ // No limit specified
161
+ });
162
+ // Should have 40 total tasks (120 / 3)
163
+ (0, globals_1.expect)(result.totalCount).toBe(40);
164
+ // But still limited to default of 100 (which is more than 40)
165
+ (0, globals_1.expect)(result.items.length).toBe(40);
166
+ (0, globals_1.expect)(result.items.every(item => item.category === 'task')).toBe(true);
167
+ });
168
+ (0, globals_1.it)('should apply default limit with multiple filters', () => {
169
+ const result = contextRepo.queryEnhanced({
170
+ sessionId: testSessionId,
171
+ category: 'task',
172
+ priorities: ['high'],
173
+ // No limit specified
174
+ });
175
+ // Should filter by both category and priority
176
+ (0, globals_1.expect)(result.items.every(item => item.category === 'task' && item.priority === 'high')).toBe(true);
177
+ // Default limit still applies
178
+ (0, globals_1.expect)(result.items.length).toBeLessThanOrEqual(100);
179
+ });
180
+ });
181
+ (0, globals_1.describe)('Offset Behavior', () => {
182
+ (0, globals_1.beforeEach)(() => {
183
+ // Create exactly 25 items for easier offset testing
184
+ for (let i = 0; i < 25; i++) {
185
+ contextRepo.save(testSessionId, {
186
+ key: `offset.test.${i.toString().padStart(2, '0')}`,
187
+ value: `Offset test value ${i}`,
188
+ });
189
+ }
190
+ });
191
+ (0, globals_1.it)('should default offset to 0 when not specified', () => {
192
+ const result = contextRepo.queryEnhanced({
193
+ sessionId: testSessionId,
194
+ limit: 10,
195
+ // No offset specified
196
+ });
197
+ (0, globals_1.expect)(result.items.length).toBe(10);
198
+ // Should start from the beginning (most recent items due to default sort)
199
+ });
200
+ (0, globals_1.it)('should handle offset with default limit', () => {
201
+ const result = contextRepo.queryEnhanced({
202
+ sessionId: testSessionId,
203
+ offset: 10,
204
+ // No limit specified - should default to 100
205
+ });
206
+ (0, globals_1.expect)(result.items.length).toBe(15); // 25 total - 10 offset = 15 remaining
207
+ });
208
+ (0, globals_1.it)('should handle negative offset as 0', () => {
209
+ const result = contextRepo.queryEnhanced({
210
+ sessionId: testSessionId,
211
+ offset: -10,
212
+ limit: 5,
213
+ });
214
+ (0, globals_1.expect)(result.items.length).toBe(5);
215
+ // Should behave as if offset was 0
216
+ });
217
+ });
218
+ (0, globals_1.describe)('Edge Cases', () => {
219
+ (0, globals_1.it)('should handle empty result set gracefully', () => {
220
+ const result = contextRepo.queryEnhanced({
221
+ sessionId: testSessionId,
222
+ category: 'non-existent-category',
223
+ });
224
+ (0, globals_1.expect)(result.items.length).toBe(0);
225
+ (0, globals_1.expect)(result.totalCount).toBe(0);
226
+ });
227
+ (0, globals_1.it)('should handle offset beyond available items', () => {
228
+ // Create only 5 items
229
+ for (let i = 0; i < 5; i++) {
230
+ contextRepo.save(testSessionId, {
231
+ key: `limited.${i}`,
232
+ value: `Limited value ${i}`,
233
+ });
234
+ }
235
+ const result = contextRepo.queryEnhanced({
236
+ sessionId: testSessionId,
237
+ offset: 100, // Far beyond available items
238
+ // No limit specified
239
+ });
240
+ (0, globals_1.expect)(result.items.length).toBe(0);
241
+ (0, globals_1.expect)(result.totalCount).toBe(5);
242
+ });
243
+ (0, globals_1.it)('should handle very large datasets efficiently', () => {
244
+ // Create 1000 items
245
+ const stmt = db.prepare(`
246
+ INSERT INTO context_items (id, session_id, key, value, created_at)
247
+ VALUES (?, ?, ?, ?, ?)
248
+ `);
249
+ const _startCreate = Date.now();
250
+ for (let i = 0; i < 1000; i++) {
251
+ stmt.run((0, uuid_1.v4)(), testSessionId, `large.dataset.${i.toString().padStart(4, '0')}`, `Large dataset value ${i}`, new Date(Date.now() - i * 1000).toISOString());
252
+ }
253
+ const _endCreate = Date.now();
254
+ const startQuery = Date.now();
255
+ const result = contextRepo.queryEnhanced({
256
+ sessionId: testSessionId,
257
+ // No limit specified - should default to 100
258
+ });
259
+ const endQuery = Date.now();
260
+ (0, globals_1.expect)(result.items.length).toBe(100); // Default limit
261
+ (0, globals_1.expect)(result.totalCount).toBe(1000);
262
+ // Query should be fast even with 1000 items
263
+ const queryTime = endQuery - startQuery;
264
+ (0, globals_1.expect)(queryTime).toBeLessThan(100); // Should complete in < 100ms
265
+ // Performance metrics (using underscored vars to avoid lint errors):
266
+ // Created 1000 items in ${_endCreate - _startCreate}ms
267
+ // Queried with default limit in ${queryTime}ms
268
+ });
269
+ });
270
+ (0, globals_1.describe)('Repository Type Handling', () => {
271
+ (0, globals_1.it)('should handle string numbers that can be converted', () => {
272
+ // The repository's type checking will treat non-numbers as undefined
273
+ const result = contextRepo.queryEnhanced({
274
+ sessionId: testSessionId,
275
+ limit: '50', // String that looks like a number
276
+ });
277
+ // Repository treats non-numbers as undefined, so it applies default
278
+ (0, globals_1.expect)(result.items.length).toBeLessThanOrEqual(100);
279
+ });
280
+ (0, globals_1.it)('should treat non-numeric types as undefined and apply defaults', () => {
281
+ // Create some test items
282
+ for (let i = 0; i < 10; i++) {
283
+ contextRepo.save(testSessionId, {
284
+ key: `type.test.${i}`,
285
+ value: `Type test value ${i}`,
286
+ });
287
+ }
288
+ // Repository checks typeof limit === 'number'
289
+ const result = contextRepo.queryEnhanced({
290
+ sessionId: testSessionId,
291
+ limit: 'not-a-number',
292
+ });
293
+ // Should apply default limit of 100
294
+ (0, globals_1.expect)(result.items.length).toBe(10); // We only have 10 items
295
+ (0, globals_1.expect)(result.totalCount).toBe(10);
296
+ });
297
+ });
298
+ });