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,561 @@
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 os = __importStar(require("os"));
40
+ const path = __importStar(require("path"));
41
+ const fs = __importStar(require("fs"));
42
+ const uuid_1 = require("uuid");
43
+ /**
44
+ * Tests for Issue #11: Search filters not working with category and priority
45
+ *
46
+ * BUG DESCRIPTION:
47
+ * - context_search tool doesn't filter properly when using category + priority parameters
48
+ * - Basic search works, but adding filters returns no results even when matching items exist
49
+ * - context_get with same filters works correctly (this is the workaround)
50
+ *
51
+ * ROOT CAUSE:
52
+ * - Missing privacy filter in queryEnhanced method causes different SQL query structure
53
+ * - searchEnhanced includes privacy filter, queryEnhanced doesn't
54
+ * - This affects both the main query and the count query, leading to inconsistent results
55
+ *
56
+ * EXPECTED BEHAVIOR:
57
+ * - context_search with filters should return the same results as context_get with same filters
58
+ * - Both should respect privacy boundaries and session isolation
59
+ * - Filters should work in combination (category + priority + channels, etc.)
60
+ */
61
+ (0, globals_1.describe)('Issue #11: Search Filters Bug Tests', () => {
62
+ let dbManager;
63
+ let tempDbPath;
64
+ let db;
65
+ let contextRepo;
66
+ let testSessionId;
67
+ let otherSessionId;
68
+ (0, globals_1.beforeEach)(() => {
69
+ tempDbPath = path.join(os.tmpdir(), `test-issue11-${Date.now()}.db`);
70
+ dbManager = new database_1.DatabaseManager({
71
+ filename: tempDbPath,
72
+ maxSize: 10 * 1024 * 1024,
73
+ walMode: true,
74
+ });
75
+ db = dbManager.getDatabase();
76
+ contextRepo = new ContextRepository_1.ContextRepository(dbManager);
77
+ // Create test sessions
78
+ testSessionId = (0, uuid_1.v4)();
79
+ otherSessionId = (0, uuid_1.v4)();
80
+ db.prepare('INSERT INTO sessions (id, name) VALUES (?, ?)').run(testSessionId, 'Main Test Session');
81
+ db.prepare('INSERT INTO sessions (id, name) VALUES (?, ?)').run(otherSessionId, 'Other Session');
82
+ // Create comprehensive test data that covers the bug scenarios
83
+ const now = new Date();
84
+ const yesterday = new Date(now.getTime() - 24 * 60 * 60 * 1000);
85
+ const testItems = [
86
+ // Items in main session
87
+ {
88
+ id: (0, uuid_1.v4)(),
89
+ session_id: testSessionId,
90
+ key: 'auth_high_task',
91
+ value: 'High priority authentication task',
92
+ category: 'task',
93
+ priority: 'high',
94
+ channel: 'feature/auth',
95
+ created_at: now.toISOString(),
96
+ is_private: 0,
97
+ },
98
+ {
99
+ id: (0, uuid_1.v4)(),
100
+ session_id: testSessionId,
101
+ key: 'auth_normal_task',
102
+ value: 'Normal priority authentication configuration',
103
+ category: 'task',
104
+ priority: 'normal',
105
+ channel: 'feature/auth',
106
+ created_at: yesterday.toISOString(),
107
+ is_private: 0,
108
+ },
109
+ {
110
+ id: (0, uuid_1.v4)(),
111
+ session_id: testSessionId,
112
+ key: 'auth_config_high',
113
+ value: 'Authentication configuration settings',
114
+ category: 'config',
115
+ priority: 'high',
116
+ channel: 'main',
117
+ created_at: now.toISOString(),
118
+ is_private: 0,
119
+ },
120
+ {
121
+ id: (0, uuid_1.v4)(),
122
+ session_id: testSessionId,
123
+ key: 'db_config_normal',
124
+ value: 'Database configuration with auth settings',
125
+ category: 'config',
126
+ priority: 'normal',
127
+ channel: 'main',
128
+ created_at: yesterday.toISOString(),
129
+ is_private: 0,
130
+ },
131
+ {
132
+ id: (0, uuid_1.v4)(),
133
+ session_id: testSessionId,
134
+ key: 'private_auth_note',
135
+ value: 'Private authentication notes',
136
+ category: 'note',
137
+ priority: 'normal',
138
+ channel: 'main',
139
+ created_at: now.toISOString(),
140
+ is_private: 1, // Private item
141
+ },
142
+ // Items in other session
143
+ {
144
+ id: (0, uuid_1.v4)(),
145
+ session_id: otherSessionId,
146
+ key: 'other_auth_task',
147
+ value: 'Authentication task in other session',
148
+ category: 'task',
149
+ priority: 'high',
150
+ channel: 'feature/auth',
151
+ created_at: now.toISOString(),
152
+ is_private: 0,
153
+ },
154
+ {
155
+ id: (0, uuid_1.v4)(),
156
+ session_id: otherSessionId,
157
+ key: 'other_private_auth',
158
+ value: 'Private auth item in other session',
159
+ category: 'task',
160
+ priority: 'high',
161
+ channel: 'main',
162
+ created_at: now.toISOString(),
163
+ is_private: 1, // Private to other session
164
+ },
165
+ ];
166
+ // Insert test data
167
+ const stmt = db.prepare(`
168
+ INSERT INTO context_items (
169
+ id, session_id, key, value, category, priority, channel,
170
+ created_at, is_private
171
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
172
+ `);
173
+ testItems.forEach(item => {
174
+ stmt.run(item.id, item.session_id, item.key, item.value, item.category, item.priority, item.channel, item.created_at, item.is_private);
175
+ });
176
+ });
177
+ (0, globals_1.afterEach)(() => {
178
+ dbManager.close();
179
+ try {
180
+ fs.unlinkSync(tempDbPath);
181
+ fs.unlinkSync(`${tempDbPath}-wal`);
182
+ fs.unlinkSync(`${tempDbPath}-shm`);
183
+ }
184
+ catch (_e) {
185
+ // Ignore cleanup errors
186
+ }
187
+ });
188
+ (0, globals_1.describe)('Basic Search Functionality (Should Work)', () => {
189
+ (0, globals_1.it)('should return results for basic search without filters', () => {
190
+ const searchResult = contextRepo.searchEnhanced({
191
+ query: 'auth',
192
+ sessionId: testSessionId,
193
+ });
194
+ (0, globals_1.expect)(searchResult.items.length).toBeGreaterThan(0);
195
+ (0, globals_1.expect)(searchResult.totalCount).toBeGreaterThan(0);
196
+ (0, globals_1.expect)(searchResult.items.every(item => item.key.includes('auth') || item.value.includes('auth'))).toBe(true);
197
+ });
198
+ });
199
+ (0, globals_1.describe)('The Core Bug: Missing Privacy Filter in queryEnhanced', () => {
200
+ (0, globals_1.it)('should demonstrate privacy filter bug: queryEnhanced misses public items from other sessions', () => {
201
+ // This test will fail because queryEnhanced is missing the privacy filter
202
+ // The correct behavior should be: show public items from ANY session + private items from OWN session
203
+ const queryResult = contextRepo.queryEnhanced({
204
+ sessionId: testSessionId,
205
+ // No filters - this should show all accessible items
206
+ });
207
+ const searchResult = contextRepo.searchEnhanced({
208
+ query: '', // Empty query to match all items
209
+ sessionId: testSessionId,
210
+ });
211
+ // console.log('DEBUG: queryEnhanced results:', {
212
+ // itemCount: queryResult.items.length,
213
+ // totalCount: queryResult.totalCount,
214
+ // sessionsFound: [...new Set(queryResult.items.map(i => i.session_id))],
215
+ // items: queryResult.items.map(i => ({
216
+ // key: i.key,
217
+ // session_id: i.session_id,
218
+ // is_private: i.is_private,
219
+ // })),
220
+ // });
221
+ // console.log('DEBUG: searchEnhanced results (correct behavior):', {
222
+ // itemCount: searchResult.items.length,
223
+ // totalCount: searchResult.totalCount,
224
+ // sessionsFound: [...new Set(searchResult.items.map(i => i.session_id))],
225
+ // items: searchResult.items.map(i => ({
226
+ // key: i.key,
227
+ // session_id: i.session_id,
228
+ // is_private: i.is_private,
229
+ // })),
230
+ // });
231
+ // BUG: queryEnhanced only shows items from current session
232
+ // But it should show public items from other sessions too
233
+ const queryPublicItemsFromOtherSession = queryResult.items.filter(item => item.session_id === otherSessionId && item.is_private === 0);
234
+ const searchPublicItemsFromOtherSession = searchResult.items.filter(item => item.session_id === otherSessionId && item.is_private === 0);
235
+ // console.log('DEBUG: Public items from other session comparison:', {
236
+ // queryCount: queryPublicItemsFromOtherSession.length,
237
+ // searchCount: searchPublicItemsFromOtherSession.length,
238
+ // queryItems: queryPublicItemsFromOtherSession.map(i => i.key),
239
+ // searchItems: searchPublicItemsFromOtherSession.map(i => i.key),
240
+ // });
241
+ // This will demonstrate the bug: queryEnhanced will have 0 public items from other sessions
242
+ // while searchEnhanced will have > 0 public items from other sessions
243
+ (0, globals_1.expect)(queryPublicItemsFromOtherSession.length).toBe(searchPublicItemsFromOtherSession.length);
244
+ });
245
+ (0, globals_1.it)('should demonstrate privacy filter works correctly in searchEnhanced', () => {
246
+ // searchEnhanced should correctly respect privacy
247
+ const searchResult = contextRepo.searchEnhanced({
248
+ query: 'auth',
249
+ sessionId: testSessionId,
250
+ });
251
+ // searchEnhanced should NOT see private items from other sessions
252
+ const privateItemsFromOtherSession = searchResult.items.filter(item => item.session_id === otherSessionId && item.is_private === 1);
253
+ // console.log('DEBUG: Private items from other session found by searchEnhanced:', {
254
+ // count: privateItemsFromOtherSession.length,
255
+ // items: privateItemsFromOtherSession.map(i => ({
256
+ // key: i.key,
257
+ // session_id: i.session_id,
258
+ // is_private: i.is_private,
259
+ // })),
260
+ // });
261
+ // This should be 0 and will be 0 because searchEnhanced has the privacy filter
262
+ (0, globals_1.expect)(privateItemsFromOtherSession.length).toBe(0);
263
+ });
264
+ });
265
+ (0, globals_1.describe)('The Core Bug: Filters Failing in searchEnhanced', () => {
266
+ (0, globals_1.it)('should fail: searchEnhanced with category filter returns wrong results', () => {
267
+ // This test documents the current failing behavior
268
+ const searchResult = contextRepo.searchEnhanced({
269
+ query: 'auth',
270
+ sessionId: testSessionId,
271
+ category: 'task',
272
+ });
273
+ const queryResult = contextRepo.queryEnhanced({
274
+ sessionId: testSessionId,
275
+ category: 'task',
276
+ });
277
+ // Debug logging to understand the actual behavior
278
+ // console.log('DEBUG: searchEnhanced with category=task results:', {
279
+ // itemCount: searchResult.items.length,
280
+ // totalCount: searchResult.totalCount,
281
+ // items: searchResult.items.map(i => ({
282
+ // key: i.key,
283
+ // category: i.category,
284
+ // priority: i.priority,
285
+ // })),
286
+ // });
287
+ // BUG: searchEnhanced should return items but currently may not due to filter interaction
288
+ // The query should find: auth_high_task and auth_normal_task
289
+ (0, globals_1.expect)(searchResult.items.length).toBeGreaterThanOrEqual(0); // Currently may be 0 due to bug
290
+ // But queryEnhanced works correctly as a workaround
291
+ const taskItems = queryResult.items.filter(item => item.key.includes('auth') || item.value.includes('auth'));
292
+ // console.log('DEBUG: queryEnhanced filtered results:', {
293
+ // itemCount: taskItems.length,
294
+ // items: taskItems.map(i => ({ key: i.key, category: i.category, priority: i.priority })),
295
+ // });
296
+ (0, globals_1.expect)(taskItems.length).toBe(3); // Should find auth_high_task, auth_normal_task, and other_auth_task
297
+ // Let's see if there's actually a difference
298
+ if (searchResult.items.length !== taskItems.length) {
299
+ // // console.log('BUG DETECTED: Different result counts!');
300
+ }
301
+ });
302
+ (0, globals_1.it)('should fail: searchEnhanced with priority filter returns wrong results', () => {
303
+ const searchResult = contextRepo.searchEnhanced({
304
+ query: 'auth',
305
+ sessionId: testSessionId,
306
+ priorities: ['high'],
307
+ });
308
+ const queryResult = contextRepo.queryEnhanced({
309
+ sessionId: testSessionId,
310
+ priorities: ['high'],
311
+ });
312
+ // BUG: searchEnhanced may not work with priority filters
313
+ (0, globals_1.expect)(searchResult.items.length).toBeGreaterThanOrEqual(0); // Currently may be 0 due to bug
314
+ // But queryEnhanced works as workaround
315
+ const highPriorityItems = queryResult.items.filter(item => item.key.includes('auth') || item.value.includes('auth'));
316
+ (0, globals_1.expect)(highPriorityItems.length).toBe(3); // auth_high_task, auth_config_high, and other_auth_task
317
+ });
318
+ (0, globals_1.it)('should fail: searchEnhanced with category + priority filters returns wrong results', () => {
319
+ // This is the core failing scenario from the bug report
320
+ const searchResult = contextRepo.searchEnhanced({
321
+ query: 'auth',
322
+ sessionId: testSessionId,
323
+ category: 'task',
324
+ priorities: ['high'],
325
+ });
326
+ const queryResult = contextRepo.queryEnhanced({
327
+ sessionId: testSessionId,
328
+ category: 'task',
329
+ priorities: ['high'],
330
+ });
331
+ // BUG: Combined filters in searchEnhanced likely return no results
332
+ (0, globals_1.expect)(searchResult.items.length).toBeGreaterThanOrEqual(0); // Currently likely 0 due to bug
333
+ // But queryEnhanced works correctly
334
+ const matchingItems = queryResult.items.filter(item => item.key.includes('auth') || item.value.includes('auth'));
335
+ (0, globals_1.expect)(matchingItems.length).toBe(2); // Should find auth_high_task and other_auth_task
336
+ (0, globals_1.expect)(matchingItems.some(item => item.key === 'auth_high_task')).toBe(true);
337
+ (0, globals_1.expect)(matchingItems.some(item => item.key === 'other_auth_task')).toBe(true);
338
+ });
339
+ (0, globals_1.it)('should fail: searchEnhanced with channel filter returns wrong results', () => {
340
+ const searchResult = contextRepo.searchEnhanced({
341
+ query: 'auth',
342
+ sessionId: testSessionId,
343
+ channel: 'feature/auth',
344
+ });
345
+ const queryResult = contextRepo.queryEnhanced({
346
+ sessionId: testSessionId,
347
+ channel: 'feature/auth',
348
+ });
349
+ // BUG: Channel filtering in searchEnhanced may not work
350
+ (0, globals_1.expect)(searchResult.items.length).toBeGreaterThanOrEqual(0); // Currently may be 0 due to bug
351
+ // But queryEnhanced works as workaround
352
+ const channelItems = queryResult.items.filter(item => item.key.includes('auth') || item.value.includes('auth'));
353
+ (0, globals_1.expect)(channelItems.length).toBe(3); // auth_high_task, auth_normal_task, and other_auth_task
354
+ });
355
+ });
356
+ (0, globals_1.describe)('Expected Behavior After Fix', () => {
357
+ (0, globals_1.it)('should match: searchEnhanced and queryEnhanced with category filter', () => {
358
+ const searchResult = contextRepo.searchEnhanced({
359
+ query: 'auth',
360
+ sessionId: testSessionId,
361
+ category: 'task',
362
+ });
363
+ const queryResult = contextRepo.queryEnhanced({
364
+ sessionId: testSessionId,
365
+ category: 'task',
366
+ });
367
+ const queryMatches = queryResult.items.filter(item => item.key.includes('auth') || item.value.includes('auth'));
368
+ // After fix: searchEnhanced should return same results as queryEnhanced filter
369
+ (0, globals_1.expect)(searchResult.items.length).toBe(queryMatches.length);
370
+ (0, globals_1.expect)(searchResult.items.map(i => i.key).sort()).toEqual(queryMatches.map(i => i.key).sort());
371
+ });
372
+ (0, globals_1.it)('should match: searchEnhanced and queryEnhanced with priority filter', () => {
373
+ const searchResult = contextRepo.searchEnhanced({
374
+ query: 'auth',
375
+ sessionId: testSessionId,
376
+ priorities: ['high'],
377
+ });
378
+ const queryResult = contextRepo.queryEnhanced({
379
+ sessionId: testSessionId,
380
+ priorities: ['high'],
381
+ });
382
+ const queryMatches = queryResult.items.filter(item => item.key.includes('auth') || item.value.includes('auth'));
383
+ // After fix: should return matching results
384
+ (0, globals_1.expect)(searchResult.items.length).toBe(queryMatches.length);
385
+ (0, globals_1.expect)(searchResult.items.map(i => i.key).sort()).toEqual(queryMatches.map(i => i.key).sort());
386
+ });
387
+ (0, globals_1.it)('should match: searchEnhanced and queryEnhanced with combined filters', () => {
388
+ const searchResult = contextRepo.searchEnhanced({
389
+ query: 'auth',
390
+ sessionId: testSessionId,
391
+ category: 'task',
392
+ priorities: ['high'],
393
+ channel: 'feature/auth',
394
+ });
395
+ const queryResult = contextRepo.queryEnhanced({
396
+ sessionId: testSessionId,
397
+ category: 'task',
398
+ priorities: ['high'],
399
+ channel: 'feature/auth',
400
+ });
401
+ const queryMatches = queryResult.items.filter(item => item.key.includes('auth') || item.value.includes('auth'));
402
+ // After fix: complex filter combinations should work
403
+ (0, globals_1.expect)(searchResult.items.length).toBe(queryMatches.length);
404
+ (0, globals_1.expect)(searchResult.items.map(i => i.key).sort()).toEqual(queryMatches.map(i => i.key).sort());
405
+ });
406
+ });
407
+ (0, globals_1.describe)('Privacy and Session Boundaries', () => {
408
+ (0, globals_1.it)('should respect privacy: searchEnhanced only shows accessible items', () => {
409
+ const searchResult = contextRepo.searchEnhanced({
410
+ query: 'auth',
411
+ sessionId: testSessionId,
412
+ });
413
+ // Should find public items from any session + private items from own session
414
+ (0, globals_1.expect)(searchResult.items.some(item => item.key === 'private_auth_note')).toBe(true);
415
+ (0, globals_1.expect)(searchResult.items.some(item => item.key === 'other_private_auth')).toBe(false);
416
+ });
417
+ (0, globals_1.it)('should respect privacy: queryEnhanced only shows accessible items', () => {
418
+ const queryResult = contextRepo.queryEnhanced({
419
+ sessionId: testSessionId,
420
+ });
421
+ const authItems = queryResult.items.filter(item => item.key.includes('auth') || item.value.includes('auth'));
422
+ // Should find public items from any session + private items from own session
423
+ (0, globals_1.expect)(authItems.some(item => item.key === 'private_auth_note')).toBe(true);
424
+ (0, globals_1.expect)(authItems.some(item => item.key === 'other_private_auth')).toBe(false);
425
+ });
426
+ (0, globals_1.it)('should match privacy behavior: searchEnhanced and queryEnhanced', () => {
427
+ const searchResult = contextRepo.searchEnhanced({
428
+ query: 'auth',
429
+ sessionId: testSessionId,
430
+ });
431
+ const queryResult = contextRepo.queryEnhanced({
432
+ sessionId: testSessionId,
433
+ });
434
+ const queryMatches = queryResult.items.filter(item => item.key.includes('auth') || item.value.includes('auth'));
435
+ // Both should respect privacy in the same way
436
+ const searchPrivateItems = searchResult.items.filter(item => item.is_private === 1);
437
+ const queryPrivateItems = queryMatches.filter(item => item.is_private === 1);
438
+ (0, globals_1.expect)(searchPrivateItems.length).toBe(queryPrivateItems.length);
439
+ (0, globals_1.expect)(searchPrivateItems.every(item => item.session_id === testSessionId)).toBe(true);
440
+ (0, globals_1.expect)(queryPrivateItems.every(item => item.session_id === testSessionId)).toBe(true);
441
+ });
442
+ });
443
+ (0, globals_1.describe)('Edge Cases and Combinations', () => {
444
+ (0, globals_1.it)('should handle multiple priorities filter', () => {
445
+ const searchResult = contextRepo.searchEnhanced({
446
+ query: 'auth',
447
+ sessionId: testSessionId,
448
+ priorities: ['high', 'normal'],
449
+ });
450
+ const queryResult = contextRepo.queryEnhanced({
451
+ sessionId: testSessionId,
452
+ priorities: ['high', 'normal'],
453
+ });
454
+ const queryMatches = queryResult.items.filter(item => item.key.includes('auth') || item.value.includes('auth'));
455
+ (0, globals_1.expect)(searchResult.items.length).toBe(queryMatches.length);
456
+ });
457
+ (0, globals_1.it)('should handle multiple channels filter', () => {
458
+ const searchResult = contextRepo.searchEnhanced({
459
+ query: 'auth',
460
+ sessionId: testSessionId,
461
+ channels: ['main', 'feature/auth'],
462
+ });
463
+ const queryResult = contextRepo.queryEnhanced({
464
+ sessionId: testSessionId,
465
+ channels: ['main', 'feature/auth'],
466
+ });
467
+ const queryMatches = queryResult.items.filter(item => item.key.includes('auth') || item.value.includes('auth'));
468
+ (0, globals_1.expect)(searchResult.items.length).toBe(queryMatches.length);
469
+ });
470
+ (0, globals_1.it)('should handle empty query with filters', () => {
471
+ // Test with empty query - should rely purely on filters
472
+ const searchResult = contextRepo.searchEnhanced({
473
+ query: '',
474
+ sessionId: testSessionId,
475
+ category: 'task',
476
+ });
477
+ const queryResult = contextRepo.queryEnhanced({
478
+ sessionId: testSessionId,
479
+ category: 'task',
480
+ });
481
+ // When query is empty, searchEnhanced should return all items matching filters
482
+ (0, globals_1.expect)(searchResult.items.length).toBe(queryResult.items.length);
483
+ });
484
+ (0, globals_1.it)('should handle pagination with filters', () => {
485
+ const searchResult = contextRepo.searchEnhanced({
486
+ query: 'auth',
487
+ sessionId: testSessionId,
488
+ limit: 2,
489
+ offset: 0,
490
+ });
491
+ (0, globals_1.expect)(searchResult.items.length).toBeLessThanOrEqual(2);
492
+ (0, globals_1.expect)(searchResult.totalCount).toBeGreaterThanOrEqual(searchResult.items.length);
493
+ });
494
+ });
495
+ (0, globals_1.describe)('Success Criteria Definition', () => {
496
+ (0, globals_1.it)('SUCCESS CRITERIA: All filter combinations should work consistently', () => {
497
+ const testCases = [
498
+ { category: 'task' },
499
+ { priorities: ['high'] },
500
+ { channel: 'main' },
501
+ { category: 'task', priorities: ['high'] },
502
+ { category: 'config', channel: 'main' },
503
+ { priorities: ['high', 'normal'], channel: 'feature/auth' },
504
+ { category: 'task', priorities: ['high'], channel: 'feature/auth' },
505
+ ];
506
+ testCases.forEach((filters, _index) => {
507
+ const searchResult = contextRepo.searchEnhanced({
508
+ query: 'auth',
509
+ sessionId: testSessionId,
510
+ ...filters,
511
+ });
512
+ const queryResult = contextRepo.queryEnhanced({
513
+ sessionId: testSessionId,
514
+ ...filters,
515
+ });
516
+ const queryMatches = queryResult.items.filter(item => item.key.includes('auth') || item.value.includes('auth'));
517
+ (0, globals_1.expect)(searchResult.items.length).toBe(queryMatches.length);
518
+ (0, globals_1.expect)(searchResult.totalCount).toBe(queryMatches.length);
519
+ // Log for debugging
520
+ if (searchResult.items.length !== queryMatches.length) {
521
+ // console.log(`Test case ${index} failed:`, filters);
522
+ // console.log(
523
+ // 'Search results:',
524
+ // searchResult.items.map(i => i.key)
525
+ // );
526
+ // console.log(
527
+ // 'Query matches:',
528
+ // queryMatches.map(i => i.key)
529
+ // );
530
+ }
531
+ });
532
+ });
533
+ (0, globals_1.it)('SUCCESS CRITERIA: Search with text query + metadata filters should work', () => {
534
+ // This is the core failing scenario from the bug report
535
+ const result = contextRepo.searchEnhanced({
536
+ query: 'authentication',
537
+ sessionId: testSessionId,
538
+ category: 'task',
539
+ priorities: ['high'],
540
+ });
541
+ // Should find auth_high_task and other_auth_task
542
+ (0, globals_1.expect)(result.items.length).toBe(2);
543
+ (0, globals_1.expect)(result.items.some(item => item.key === 'auth_high_task')).toBe(true);
544
+ (0, globals_1.expect)(result.items.some(item => item.key === 'other_auth_task')).toBe(true);
545
+ (0, globals_1.expect)(result.totalCount).toBe(2);
546
+ });
547
+ (0, globals_1.it)('SUCCESS CRITERIA: Performance should be acceptable', () => {
548
+ const start = Date.now();
549
+ const result = contextRepo.searchEnhanced({
550
+ query: 'auth',
551
+ sessionId: testSessionId,
552
+ category: 'task',
553
+ priorities: ['high', 'normal'],
554
+ channels: ['main', 'feature/auth'],
555
+ });
556
+ const duration = Date.now() - start;
557
+ (0, globals_1.expect)(result.items.length).toBeGreaterThanOrEqual(0);
558
+ (0, globals_1.expect)(duration).toBeLessThan(100); // Should complete within 100ms
559
+ });
560
+ });
561
+ });