@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,296 @@
1
+ "use strict";
2
+ /**
3
+ * Critical Pagination Fix Test
4
+ * Tests the new pagination functionality for context_search_all to prevent token overflow
5
+ */
6
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
7
+ if (k2 === undefined) k2 = k;
8
+ var desc = Object.getOwnPropertyDescriptor(m, k);
9
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
10
+ desc = { enumerable: true, get: function() { return m[k]; } };
11
+ }
12
+ Object.defineProperty(o, k2, desc);
13
+ }) : (function(o, m, k, k2) {
14
+ if (k2 === undefined) k2 = k;
15
+ o[k2] = m[k];
16
+ }));
17
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
18
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
19
+ }) : function(o, v) {
20
+ o["default"] = v;
21
+ });
22
+ var __importStar = (this && this.__importStar) || (function () {
23
+ var ownKeys = function(o) {
24
+ ownKeys = Object.getOwnPropertyNames || function (o) {
25
+ var ar = [];
26
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
27
+ return ar;
28
+ };
29
+ return ownKeys(o);
30
+ };
31
+ return function (mod) {
32
+ if (mod && mod.__esModule) return mod;
33
+ var result = {};
34
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
35
+ __setModuleDefault(result, mod);
36
+ return result;
37
+ };
38
+ })();
39
+ Object.defineProperty(exports, "__esModule", { value: true });
40
+ const database_1 = require("../../utils/database");
41
+ const repositories_1 = require("../../repositories");
42
+ const os = __importStar(require("os"));
43
+ const path = __importStar(require("path"));
44
+ const fs = __importStar(require("fs"));
45
+ const uuid_1 = require("uuid");
46
+ describe('Pagination Critical Fix', () => {
47
+ let dbManager;
48
+ let repositories;
49
+ let sessionId;
50
+ let tempDbPath;
51
+ let db;
52
+ beforeEach(() => {
53
+ tempDbPath = path.join(os.tmpdir(), `test-pagination-${Date.now()}.db`);
54
+ dbManager = new database_1.DatabaseManager({
55
+ filename: tempDbPath,
56
+ maxSize: 10 * 1024 * 1024,
57
+ walMode: true,
58
+ });
59
+ repositories = new repositories_1.RepositoryManager(dbManager);
60
+ db = dbManager.getDatabase();
61
+ // Create test session
62
+ sessionId = (0, uuid_1.v4)();
63
+ db.prepare('INSERT INTO sessions (id, name, description) VALUES (?, ?, ?)').run(sessionId, 'Pagination Test Session', 'Test session for pagination testing');
64
+ // Add test data to test pagination
65
+ for (let i = 1; i <= 50; i++) {
66
+ db.prepare('INSERT INTO context_items (id, session_id, key, value, category, priority, size) VALUES (?, ?, ?, ?, ?, ?, ?)').run((0, uuid_1.v4)(), sessionId, `test_item_${i}`, `This is test item number ${i} with searchable content`, i % 2 === 0 ? 'task' : 'note', i % 3 === 0 ? 'high' : 'normal', 100 // size in bytes
67
+ );
68
+ }
69
+ });
70
+ afterEach(() => {
71
+ dbManager.close();
72
+ try {
73
+ fs.unlinkSync(tempDbPath);
74
+ fs.unlinkSync(`${tempDbPath}-wal`);
75
+ fs.unlinkSync(`${tempDbPath}-shm`);
76
+ }
77
+ catch (_e) {
78
+ // Ignore cleanup errors
79
+ }
80
+ });
81
+ describe('searchAcrossSessionsEnhanced', () => {
82
+ test('should implement default pagination (25 items)', () => {
83
+ const result = repositories.contexts.searchAcrossSessionsEnhanced({
84
+ query: 'test',
85
+ currentSessionId: sessionId,
86
+ });
87
+ expect(result.items).toHaveLength(25); // Default limit
88
+ expect(result.totalCount).toBe(50);
89
+ expect(result.pagination).toMatchObject({
90
+ currentPage: 1,
91
+ totalPages: 2,
92
+ totalItems: 50,
93
+ itemsPerPage: 25,
94
+ hasNextPage: true,
95
+ hasPreviousPage: false,
96
+ nextOffset: 25,
97
+ previousOffset: null,
98
+ });
99
+ });
100
+ test('should handle custom pagination parameters', () => {
101
+ const result = repositories.contexts.searchAcrossSessionsEnhanced({
102
+ query: 'test',
103
+ currentSessionId: sessionId,
104
+ limit: 10,
105
+ offset: 20,
106
+ });
107
+ expect(result.items).toHaveLength(10);
108
+ expect(result.totalCount).toBe(50);
109
+ expect(result.pagination.currentPage).toBe(3); // offset 20 / limit 10 + 1
110
+ expect(result.pagination.totalPages).toBe(5); // 50 / 10
111
+ expect(result.pagination.hasNextPage).toBe(true);
112
+ expect(result.pagination.hasPreviousPage).toBe(true);
113
+ });
114
+ test('should enforce maximum limit of 100', () => {
115
+ const result = repositories.contexts.searchAcrossSessionsEnhanced({
116
+ query: 'test',
117
+ currentSessionId: sessionId,
118
+ limit: 500, // Should be capped at 100
119
+ });
120
+ expect(result.pagination.itemsPerPage).toBe(100); // Capped at maximum 100
121
+ expect(result.items).toHaveLength(50); // But only 50 items available
122
+ });
123
+ test('should handle minimum limit of 1', () => {
124
+ const result = repositories.contexts.searchAcrossSessionsEnhanced({
125
+ query: 'test',
126
+ currentSessionId: sessionId,
127
+ limit: -5, // Should be set to 1
128
+ });
129
+ expect(result.pagination.itemsPerPage).toBe(1);
130
+ expect(result.items).toHaveLength(1);
131
+ });
132
+ test('should handle invalid offset values', () => {
133
+ const result = repositories.contexts.searchAcrossSessionsEnhanced({
134
+ query: 'test',
135
+ currentSessionId: sessionId,
136
+ offset: -10, // Should be set to 0
137
+ });
138
+ expect(result.pagination.currentPage).toBe(1);
139
+ expect(result.pagination.previousOffset).toBeNull();
140
+ });
141
+ test('should work with category filtering', () => {
142
+ const result = repositories.contexts.searchAcrossSessionsEnhanced({
143
+ query: 'test',
144
+ currentSessionId: sessionId,
145
+ category: 'task',
146
+ limit: 10,
147
+ });
148
+ // Should find only task items (even numbered items)
149
+ expect(result.totalCount).toBe(25); // 50/2 = 25 task items
150
+ expect(result.items).toHaveLength(10);
151
+ expect(result.items.every(item => item.category === 'task')).toBe(true);
152
+ });
153
+ test('should work with priority filtering', () => {
154
+ const result = repositories.contexts.searchAcrossSessionsEnhanced({
155
+ query: 'test',
156
+ currentSessionId: sessionId,
157
+ priorities: ['high'],
158
+ limit: 20,
159
+ });
160
+ // Should find only high priority items (every 3rd item)
161
+ expect(result.totalCount).toBe(16); // Math.floor(50/3) + some extras
162
+ expect(result.items.every(item => item.priority === 'high')).toBe(true);
163
+ });
164
+ test('should work with multiple filters and pagination', () => {
165
+ const result = repositories.contexts.searchAcrossSessionsEnhanced({
166
+ query: 'test',
167
+ currentSessionId: sessionId,
168
+ category: 'task',
169
+ priorities: ['normal'],
170
+ limit: 5,
171
+ offset: 5,
172
+ });
173
+ expect(result.items).toHaveLength(5);
174
+ expect(result.items.every(item => item.category === 'task' && item.priority === 'normal')).toBe(true);
175
+ expect(result.pagination.currentPage).toBe(2);
176
+ });
177
+ test('should handle empty results with pagination metadata', () => {
178
+ const result = repositories.contexts.searchAcrossSessionsEnhanced({
179
+ query: 'nonexistent',
180
+ currentSessionId: sessionId,
181
+ limit: 10,
182
+ });
183
+ expect(result.items).toHaveLength(0);
184
+ expect(result.totalCount).toBe(0);
185
+ expect(result.pagination).toMatchObject({
186
+ currentPage: 1,
187
+ totalPages: 0,
188
+ totalItems: 0,
189
+ hasNextPage: false,
190
+ hasPreviousPage: false,
191
+ });
192
+ });
193
+ test('should maintain backward compatibility with original searchAcrossSessions', () => {
194
+ const newResult = repositories.contexts.searchAcrossSessionsEnhanced({
195
+ query: 'test',
196
+ currentSessionId: sessionId,
197
+ sort: 'created_desc', // Use same sorting as old method
198
+ });
199
+ const oldResult = repositories.contexts.searchAcrossSessions('test', sessionId);
200
+ // Old method should return all results, new method should paginate
201
+ expect(oldResult).toHaveLength(50);
202
+ expect(newResult.items).toHaveLength(25); // Default pagination
203
+ expect(newResult.totalCount).toBe(50);
204
+ // Both methods should use same sorting (priority DESC, created_at DESC)
205
+ // Just verify the counts and that pagination works correctly
206
+ expect(newResult.pagination).toMatchObject({
207
+ currentPage: 1,
208
+ totalPages: 2,
209
+ totalItems: 50,
210
+ itemsPerPage: 25,
211
+ hasNextPage: true,
212
+ hasPreviousPage: false,
213
+ });
214
+ });
215
+ test('should handle large datasets without token overflow', () => {
216
+ // Add more test data to simulate large dataset
217
+ for (let i = 51; i <= 200; i++) {
218
+ db.prepare('INSERT INTO context_items (id, session_id, key, value, category, priority, size) VALUES (?, ?, ?, ?, ?, ?, ?)').run((0, uuid_1.v4)(), sessionId, `large_dataset_item_${i}`, `This is a large dataset item with lots of content that could cause token overflow in the previous implementation. Item number ${i} contains substantial text content.`, 'note', 'normal', 200 // size in bytes
219
+ );
220
+ }
221
+ const result = repositories.contexts.searchAcrossSessionsEnhanced({
222
+ query: 'large',
223
+ currentSessionId: sessionId,
224
+ limit: 25,
225
+ });
226
+ // Should successfully handle large dataset with pagination
227
+ expect(result.items).toHaveLength(25);
228
+ expect(result.totalCount).toBe(150); // Items 51-200
229
+ expect(result.pagination.totalPages).toBe(6); // 150/25 = 6 pages
230
+ // Verify we can get subsequent pages
231
+ const page2 = repositories.contexts.searchAcrossSessionsEnhanced({
232
+ query: 'large',
233
+ currentSessionId: sessionId,
234
+ limit: 25,
235
+ offset: 25,
236
+ });
237
+ expect(page2.items).toHaveLength(25);
238
+ expect(page2.pagination.currentPage).toBe(2);
239
+ });
240
+ test('should support all search options with pagination', () => {
241
+ const result = repositories.contexts.searchAcrossSessionsEnhanced({
242
+ query: 'test',
243
+ currentSessionId: sessionId,
244
+ searchIn: ['key', 'value'],
245
+ sort: 'key_asc',
246
+ limit: 15,
247
+ offset: 10,
248
+ includeMetadata: true,
249
+ });
250
+ expect(result.items).toHaveLength(15);
251
+ expect(result.totalCount).toBe(50);
252
+ // Verify sorting (should be alphabetical by key)
253
+ const keys = result.items.map(item => item.key);
254
+ const sortedKeys = [...keys].sort();
255
+ expect(keys).toEqual(sortedKeys);
256
+ });
257
+ });
258
+ describe('Integration with cross-session functionality', () => {
259
+ test('should work across multiple sessions with pagination', () => {
260
+ // Create another session with data
261
+ const session2Id = (0, uuid_1.v4)();
262
+ db.prepare('INSERT INTO sessions (id, name, description) VALUES (?, ?, ?)').run(session2Id, 'Second Test Session', 'Second session for pagination testing');
263
+ // Add data to second session
264
+ for (let i = 1; i <= 30; i++) {
265
+ db.prepare('INSERT INTO context_items (id, session_id, key, value, category, priority, is_private, size) VALUES (?, ?, ?, ?, ?, ?, ?, ?)').run((0, uuid_1.v4)(), session2Id, `session2_item_${i}`, `Session 2 test item ${i}`, 'task', 'normal', 0, // Make public so it's searchable
266
+ 50 // size in bytes
267
+ );
268
+ }
269
+ const result = repositories.contexts.searchAcrossSessionsEnhanced({
270
+ query: 'test',
271
+ currentSessionId: sessionId,
272
+ limit: 20,
273
+ });
274
+ // Should find items from both sessions
275
+ expect(result.totalCount).toBe(80); // 50 from session1 + 30 from session2
276
+ expect(result.items).toHaveLength(20);
277
+ expect(result.pagination.totalPages).toBe(4); // 80/20 = 4
278
+ });
279
+ test('should respect privacy settings with pagination', () => {
280
+ // Add private items to current session
281
+ for (let i = 1; i <= 10; i++) {
282
+ db.prepare('INSERT INTO context_items (id, session_id, key, value, category, priority, is_private, size) VALUES (?, ?, ?, ?, ?, ?, ?, ?)').run((0, uuid_1.v4)(), sessionId, `private_item_${i}`, `Private test item ${i}`, 'note', 'high', 1, // Private
283
+ 60 // size in bytes
284
+ );
285
+ }
286
+ const result = repositories.contexts.searchAcrossSessionsEnhanced({
287
+ query: 'test',
288
+ currentSessionId: sessionId,
289
+ limit: 30,
290
+ });
291
+ // Should include private items from current session + public items
292
+ expect(result.totalCount).toBe(60); // 50 original + 10 private
293
+ expect(result.items).toHaveLength(30);
294
+ });
295
+ });
296
+ });