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.
- package/CHANGELOG.md +433 -0
- package/LICENSE +21 -0
- package/README.md +1051 -0
- package/bin/mcp-memory-keeper +52 -0
- package/dist/__tests__/helpers/database-test-helper.js +160 -0
- package/dist/__tests__/helpers/test-server.js +92 -0
- package/dist/__tests__/integration/advanced-features.test.js +614 -0
- package/dist/__tests__/integration/backward-compatibility.test.js +245 -0
- package/dist/__tests__/integration/batchOperationsE2E.test.js +396 -0
- package/dist/__tests__/integration/batchOperationsHandler.test.js +1230 -0
- package/dist/__tests__/integration/channelManagementHandler.test.js +1291 -0
- package/dist/__tests__/integration/channels.test.js +376 -0
- package/dist/__tests__/integration/checkpoint.test.js +251 -0
- package/dist/__tests__/integration/concurrent-access.test.js +190 -0
- package/dist/__tests__/integration/context-operations.test.js +243 -0
- package/dist/__tests__/integration/contextDiff.test.js +852 -0
- package/dist/__tests__/integration/contextDiffHandler.test.js +976 -0
- package/dist/__tests__/integration/contextExportHandler.test.js +510 -0
- package/dist/__tests__/integration/contextGetPaginationDefaults.test.js +298 -0
- package/dist/__tests__/integration/contextReassignChannelHandler.test.js +908 -0
- package/dist/__tests__/integration/contextRelationshipsHandler.test.js +1151 -0
- package/dist/__tests__/integration/contextSearch.test.js +938 -0
- package/dist/__tests__/integration/contextSearchHandler.test.js +552 -0
- package/dist/__tests__/integration/contextWatchActual.test.js +165 -0
- package/dist/__tests__/integration/contextWatchHandler.test.js +1500 -0
- package/dist/__tests__/integration/cross-session-sharing.test.js +302 -0
- package/dist/__tests__/integration/database-initialization.test.js +134 -0
- package/dist/__tests__/integration/enhanced-context-operations.test.js +1082 -0
- package/dist/__tests__/integration/enhancedContextGetHandler.test.js +915 -0
- package/dist/__tests__/integration/enhancedContextTimelineHandler.test.js +716 -0
- package/dist/__tests__/integration/error-cases.test.js +407 -0
- package/dist/__tests__/integration/export-import.test.js +367 -0
- package/dist/__tests__/integration/feature-flags.test.js +542 -0
- package/dist/__tests__/integration/file-operations.test.js +264 -0
- package/dist/__tests__/integration/git-integration.test.js +237 -0
- package/dist/__tests__/integration/index-tools.test.js +496 -0
- package/dist/__tests__/integration/issue11-actual-bug-demo.test.js +304 -0
- package/dist/__tests__/integration/issue11-search-filters-bug.test.js +561 -0
- package/dist/__tests__/integration/issue12-checkpoint-restore-behavior.test.js +621 -0
- package/dist/__tests__/integration/issue13-key-validation.test.js +433 -0
- package/dist/__tests__/integration/knowledge-graph.test.js +338 -0
- package/dist/__tests__/integration/migrations.test.js +528 -0
- package/dist/__tests__/integration/multi-agent.test.js +546 -0
- package/dist/__tests__/integration/pagination-critical-fix.test.js +296 -0
- package/dist/__tests__/integration/paginationDefaultsHandler.test.js +600 -0
- package/dist/__tests__/integration/project-directory.test.js +283 -0
- package/dist/__tests__/integration/resource-cleanup.test.js +149 -0
- package/dist/__tests__/integration/retention.test.js +513 -0
- package/dist/__tests__/integration/search.test.js +333 -0
- package/dist/__tests__/integration/semantic-search.test.js +266 -0
- package/dist/__tests__/integration/server-initialization.test.js +307 -0
- package/dist/__tests__/integration/session-management.test.js +219 -0
- package/dist/__tests__/integration/simplified-sharing.test.js +346 -0
- package/dist/__tests__/integration/smart-compaction.test.js +230 -0
- package/dist/__tests__/integration/summarization.test.js +308 -0
- package/dist/__tests__/integration/watcher-migration-validation.test.js +544 -0
- package/dist/__tests__/security/input-validation.test.js +115 -0
- package/dist/__tests__/utils/agents.test.js +473 -0
- package/dist/__tests__/utils/database.test.js +177 -0
- package/dist/__tests__/utils/git.test.js +122 -0
- package/dist/__tests__/utils/knowledge-graph.test.js +297 -0
- package/dist/__tests__/utils/migrationHealthCheck.test.js +302 -0
- package/dist/__tests__/utils/project-directory-messages.test.js +188 -0
- package/dist/__tests__/utils/timezone-safe-dates.js +119 -0
- package/dist/__tests__/utils/validation.test.js +200 -0
- package/dist/__tests__/utils/vector-store.test.js +231 -0
- package/dist/handlers/contextWatchHandlers.js +206 -0
- package/dist/index.js +4310 -0
- package/dist/index.phase1.backup.js +410 -0
- package/dist/index.phase2.backup.js +704 -0
- package/dist/migrations/003_add_channels.js +174 -0
- package/dist/migrations/004_add_context_watch.js +151 -0
- package/dist/migrations/005_add_context_watch.js +98 -0
- package/dist/migrations/simplify-sharing.js +117 -0
- package/dist/repositories/BaseRepository.js +30 -0
- package/dist/repositories/CheckpointRepository.js +140 -0
- package/dist/repositories/ContextRepository.js +1873 -0
- package/dist/repositories/FileRepository.js +104 -0
- package/dist/repositories/RepositoryManager.js +62 -0
- package/dist/repositories/SessionRepository.js +66 -0
- package/dist/repositories/WatcherRepository.js +252 -0
- package/dist/repositories/index.js +15 -0
- package/dist/server.js +384 -0
- package/dist/test-helpers/database-helper.js +128 -0
- package/dist/types/entities.js +3 -0
- package/dist/utils/agents.js +791 -0
- package/dist/utils/channels.js +150 -0
- package/dist/utils/database.js +731 -0
- package/dist/utils/feature-flags.js +476 -0
- package/dist/utils/git.js +145 -0
- package/dist/utils/knowledge-graph.js +264 -0
- package/dist/utils/migrationHealthCheck.js +373 -0
- package/dist/utils/migrations.js +452 -0
- package/dist/utils/retention.js +460 -0
- package/dist/utils/timestamps.js +112 -0
- package/dist/utils/validation.js +296 -0
- package/dist/utils/vector-store.js +247 -0
- 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
|
+
});
|