@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,241 @@
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 git_1 = require("../../utils/git");
37
+ const os = __importStar(require("os"));
38
+ const path = __importStar(require("path"));
39
+ const fs = __importStar(require("fs"));
40
+ const uuid_1 = require("uuid");
41
+ const simple_git_1 = require("simple-git");
42
+ const database_helper_js_1 = require("../../test-helpers/database-helper.js");
43
+ describe('Git Integration Tests', () => {
44
+ let dbManager;
45
+ let gitOps;
46
+ let tempDbPath;
47
+ let tempRepoPath;
48
+ let db;
49
+ let git; // Track git instance for cleanup
50
+ beforeEach(async () => {
51
+ tempDbPath = path.join(os.tmpdir(), `test-git-${Date.now()}.db`);
52
+ tempRepoPath = path.join(os.tmpdir(), `test-repo-${Date.now()}`);
53
+ dbManager = database_helper_js_1.TestDatabaseHelper.createTestDatabase();
54
+ db = dbManager.getDatabase();
55
+ // Create and initialize a real git repo for testing
56
+ fs.mkdirSync(tempRepoPath, { recursive: true });
57
+ git = (0, simple_git_1.simpleGit)(tempRepoPath);
58
+ await git.init(['--initial-branch=master']);
59
+ await git.addConfig('user.name', 'Test User');
60
+ await git.addConfig('user.email', 'test@example.com');
61
+ // Use repo-local hooks directory to prevent global hooks from interfering
62
+ const localHooksDir = path.join(tempRepoPath, '.git', 'hooks');
63
+ await git.addConfig('core.hooksPath', localHooksDir);
64
+ await git.addConfig('commit.gpgsign', 'false');
65
+ // Create initial commit
66
+ fs.writeFileSync(path.join(tempRepoPath, 'README.md'), '# Test Repo');
67
+ await git.add('.');
68
+ await git.commit('Initial commit');
69
+ gitOps = new git_1.GitOperations(tempRepoPath);
70
+ });
71
+ afterEach(async () => {
72
+ // Clean up git processes first
73
+ if (git) {
74
+ try {
75
+ // Clear any pending git operations
76
+ git.removeAllListeners?.();
77
+ }
78
+ catch (error) {
79
+ console.warn('Error cleaning up git:', error);
80
+ }
81
+ }
82
+ // Clean up databases
83
+ await database_helper_js_1.TestDatabaseHelper.cleanupAll();
84
+ // Clean up temp directories and files
85
+ try {
86
+ database_helper_js_1.TestDatabaseHelper.cleanupDbFiles(tempDbPath);
87
+ fs.rmSync(tempRepoPath, { recursive: true, force: true });
88
+ }
89
+ catch (error) {
90
+ console.warn('Error cleaning up temp files:', error);
91
+ }
92
+ git = null;
93
+ });
94
+ describe('context_git_commit', () => {
95
+ it('should automatically save context on commit', async () => {
96
+ const sessionId = (0, uuid_1.v4)();
97
+ db.prepare('INSERT INTO sessions (id, name) VALUES (?, ?)').run(sessionId, 'Git Test Session');
98
+ // Add context items
99
+ const items = [
100
+ { key: 'current_task', value: 'Implementing git integration', priority: 'high' },
101
+ { key: 'decision', value: 'Use simple-git library', priority: 'normal' },
102
+ ];
103
+ items.forEach(item => {
104
+ db.prepare('INSERT INTO context_items (id, session_id, key, value, priority) VALUES (?, ?, ?, ?, ?)').run((0, uuid_1.v4)(), sessionId, item.key, item.value, item.priority);
105
+ });
106
+ // Make a change and commit
107
+ fs.writeFileSync(path.join(tempRepoPath, 'test.txt'), 'test content');
108
+ const git = (0, simple_git_1.simpleGit)(tempRepoPath);
109
+ await git.add('.');
110
+ const commitResult = await git.commit('Test commit');
111
+ // Simulate auto-save on commit
112
+ const checkpointId = (0, uuid_1.v4)();
113
+ const gitInfo = await gitOps.getGitInfo();
114
+ db.prepare('INSERT INTO checkpoints (id, session_id, name, description, git_status, git_branch) VALUES (?, ?, ?, ?, ?, ?)').run(checkpointId, sessionId, `Git commit: ${commitResult.commit}`, 'Auto-saved on git commit', gitInfo.status, gitInfo.branch);
115
+ // Link context items
116
+ const contextItems = db
117
+ .prepare('SELECT id FROM context_items WHERE session_id = ?')
118
+ .all(sessionId);
119
+ contextItems.forEach((item) => {
120
+ db.prepare('INSERT INTO checkpoint_items (id, checkpoint_id, context_item_id) VALUES (?, ?, ?)').run((0, uuid_1.v4)(), checkpointId, item.id);
121
+ });
122
+ // Verify checkpoint was created
123
+ const checkpoint = db
124
+ .prepare('SELECT * FROM checkpoints WHERE id = ?')
125
+ .get(checkpointId);
126
+ expect(checkpoint).toBeDefined();
127
+ expect(checkpoint.name).toContain('Git commit:');
128
+ expect(checkpoint.git_branch).toBeTruthy();
129
+ });
130
+ it('should capture git status in checkpoint', async () => {
131
+ const sessionId = (0, uuid_1.v4)();
132
+ db.prepare('INSERT INTO sessions (id, name) VALUES (?, ?)').run(sessionId, 'Status Test');
133
+ // Create some changes
134
+ fs.writeFileSync(path.join(tempRepoPath, 'modified.txt'), 'original');
135
+ const git = (0, simple_git_1.simpleGit)(tempRepoPath);
136
+ await git.add('.');
137
+ await git.commit('Add file');
138
+ // Modify file
139
+ fs.writeFileSync(path.join(tempRepoPath, 'modified.txt'), 'changed');
140
+ // Create new file
141
+ fs.writeFileSync(path.join(tempRepoPath, 'new.txt'), 'new content');
142
+ // Stage one file
143
+ await git.add('modified.txt');
144
+ // Get git info
145
+ const gitInfo = await gitOps.getGitInfo();
146
+ // Create checkpoint with git status
147
+ const checkpointId = (0, uuid_1.v4)();
148
+ db.prepare('INSERT INTO checkpoints (id, session_id, name, git_status, git_branch) VALUES (?, ?, ?, ?, ?)').run(checkpointId, sessionId, 'Status Checkpoint', gitInfo.status, gitInfo.branch);
149
+ const checkpoint = db
150
+ .prepare('SELECT * FROM checkpoints WHERE id = ?')
151
+ .get(checkpointId);
152
+ expect(checkpoint.git_status).toContain('modified.txt');
153
+ // Parse the status to check properly
154
+ const status = JSON.parse(checkpoint.git_status);
155
+ expect(status.not_added).toContain('new.txt');
156
+ expect(checkpoint.git_branch).toBe('master'); // Default branch name
157
+ });
158
+ it('should handle commits with message containing context summary', async () => {
159
+ const sessionId = (0, uuid_1.v4)();
160
+ db.prepare('INSERT INTO sessions (id, name) VALUES (?, ?)').run(sessionId, 'Commit Message Test');
161
+ // Add context items that should be in commit message
162
+ const tasks = [
163
+ { key: 'task1', value: 'Fixed authentication bug' },
164
+ { key: 'task2', value: 'Added user validation' },
165
+ ];
166
+ tasks.forEach(task => {
167
+ db.prepare('INSERT INTO context_items (id, session_id, key, value, category) VALUES (?, ?, ?, ?, ?)').run((0, uuid_1.v4)(), sessionId, task.key, task.value, 'task');
168
+ });
169
+ // Generate commit message with context
170
+ const completedTasks = db
171
+ .prepare('SELECT value FROM context_items WHERE session_id = ? AND category = ?')
172
+ .all(sessionId, 'task');
173
+ const commitMessage = [
174
+ 'Feature: User authentication improvements',
175
+ '',
176
+ 'Tasks completed:',
177
+ ...completedTasks.map((t) => `- ${t.value}`),
178
+ '',
179
+ '[Context saved by MCP Memory Keeper]',
180
+ ].join('\n');
181
+ // Make change and commit
182
+ fs.writeFileSync(path.join(tempRepoPath, 'auth.js'), 'auth code');
183
+ const git = (0, simple_git_1.simpleGit)(tempRepoPath);
184
+ await git.add('.');
185
+ const commitResult = await git.commit(commitMessage);
186
+ expect(commitResult.commit).toBeTruthy();
187
+ // Verify commit message
188
+ const log = await git.log(['-1']);
189
+ expect(log.latest).toBeDefined();
190
+ expect(log.latest?.message || log.latest?.hash).toBeDefined();
191
+ // The actual message should be in the latest entry
192
+ });
193
+ it('should link commits to sessions', async () => {
194
+ const sessionId = (0, uuid_1.v4)();
195
+ db.prepare('INSERT INTO sessions (id, name) VALUES (?, ?)').run(sessionId, 'Linked Commit Test');
196
+ // Make multiple commits
197
+ const git = (0, simple_git_1.simpleGit)(tempRepoPath);
198
+ const commits = [];
199
+ for (let i = 0; i < 3; i++) {
200
+ fs.writeFileSync(path.join(tempRepoPath, `file${i}.txt`), `content ${i}`);
201
+ await git.add('.');
202
+ const result = await git.commit(`Commit ${i}`);
203
+ commits.push(result.commit);
204
+ // Link commit to session - store commit hash in description
205
+ const checkpointId = (0, uuid_1.v4)();
206
+ db.prepare('INSERT INTO checkpoints (id, session_id, name, description) VALUES (?, ?, ?, ?)').run(checkpointId, sessionId, `Commit ${i}`, `Commit hash: ${result.commit}`);
207
+ }
208
+ // Query commits for session - using description field instead of metadata
209
+ const sessionCommits = db
210
+ .prepare(`SELECT * FROM checkpoints
211
+ WHERE session_id = ?
212
+ AND description LIKE 'Commit hash:%'
213
+ ORDER BY created_at`)
214
+ .all(sessionId);
215
+ expect(sessionCommits).toHaveLength(3);
216
+ sessionCommits.forEach((checkpoint, i) => {
217
+ // Extract commit hash from description
218
+ const match = checkpoint.description.match(/Commit hash: (.+)/);
219
+ expect(match).toBeTruthy();
220
+ expect(match[1]).toBe(commits[i]);
221
+ });
222
+ });
223
+ });
224
+ describe('Git error handling', () => {
225
+ it('should handle non-git directories gracefully', async () => {
226
+ const nonGitPath = path.join(os.tmpdir(), `non-git-${Date.now()}`);
227
+ fs.mkdirSync(nonGitPath, { recursive: true });
228
+ const nonGitOps = new git_1.GitOperations(nonGitPath);
229
+ const info = await nonGitOps.getGitInfo();
230
+ expect(info.isGitRepo).toBe(false);
231
+ expect(info.status.toLowerCase()).toContain('not a git repository');
232
+ fs.rmSync(nonGitPath, { recursive: true, force: true });
233
+ });
234
+ it('should handle git operation failures', async () => {
235
+ // Test with invalid commit (no changes)
236
+ const result = await gitOps.safeCommit('Empty commit');
237
+ expect(result.success).toBe(false);
238
+ expect(result.error).toContain('No changes to commit');
239
+ });
240
+ });
241
+ });