claude-recall 0.2.2 → 0.2.4

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/README.md CHANGED
@@ -43,13 +43,37 @@ Launch Claude Code and your memories will be captured automatically. Claude Reca
43
43
 
44
44
  ## How It Works
45
45
 
46
- Claude Recall uses the Model Context Protocol to integrate directly with Claude Code. When you:
47
- - Use tools or run commands - it captures the patterns
48
- - Express preferences - it remembers them
49
- - Make decisions - it stores the context
50
- - Start new conversations - it provides relevant memories
46
+ Claude Recall uses the Model Context Protocol to integrate directly with Claude Code.
51
47
 
52
- All of this happens automatically through MCP, without any manual configuration.
48
+ ### Automatic Memory Capture (v0.2.4+)
49
+
50
+ Claude Recall ensures memories are captured reliably by:
51
+ 1. **Instructing Claude via CLAUDE.md** - Installation adds instructions so Claude always calls the MCP tool when you say "remember"
52
+ 2. **Automatic pattern detection** - When Claude does use tools, additional patterns are detected
53
+
54
+ **Memory storage is triggered by:**
55
+ - "remember" / "remember that" / "please remember"
56
+ - "don't forget" / "keep in mind" / "bear in mind"
57
+ - "store in memory" / "save to memory"
58
+ - "note that" / "take note"
59
+ - "for future reference" / "memorize"
60
+
61
+ **Memory retrieval is triggered by:**
62
+ - "recall" / "what did I tell you about"
63
+ - "what do you remember about"
64
+ - "do you remember"
65
+
66
+ **Additional patterns detected automatically:**
67
+ - **Preferences**: "I prefer X over Y", "Always use X", "From now on, use Y"
68
+ - **Decisions**: "We decided to...", "Let's go with...", "We'll use..."
69
+ - **Instructions**: "Make sure to...", "Ensure that...", "Files should be in..."
70
+
71
+ ### Manual Memory Storage
72
+
73
+ You can also explicitly ask Claude to store memories using the MCP tools:
74
+ - Use the `mcp__claude-recall__store_memory` tool
75
+ - Search with `mcp__claude-recall__search`
76
+ - Get stats with `mcp__claude-recall__get_stats`
53
77
 
54
78
  ## Real-World Example
55
79
 
@@ -162,6 +186,18 @@ const memories = await mcp__claude-recall__search({
162
186
  })
163
187
  ```
164
188
 
189
+ ### Customizing Memory Patterns
190
+
191
+ Claude Recall uses configurable patterns for automatic memory capture. You can customize these by setting the `CLAUDE_RECALL_PATTERNS_CONFIG` environment variable to point to your own JSON configuration file.
192
+
193
+ Default patterns include:
194
+ - **Explicit remember**: Any sentence with "remember" (confidence: 1.0)
195
+ - **Preferences**: "I prefer", "Always use", "From now on" (confidence: 0.85-0.9)
196
+ - **Locations**: "Should be in X directory" (confidence: 0.8)
197
+ - **Instructions**: "Make sure", "Ensure that" (confidence: 0.7)
198
+
199
+ See `src/config/memory-patterns.json` for the full configuration format.
200
+
165
201
  ## Troubleshooting
166
202
 
167
203
  ### MCP Server Not Found
@@ -178,6 +214,59 @@ If Claude Code can't find the MCP server:
178
214
  2. Check stats: `claude-recall stats`
179
215
  3. Ensure MCP tools are being used in Claude Code
180
216
 
217
+ ### Clearing npm Cache (Version Issues)
218
+
219
+ If you're seeing an old version after installing `@latest`, clear the npm cache:
220
+
221
+ ```bash
222
+ # Complete cache clear and reinstall
223
+ npm uninstall -g claude-recall
224
+ npm cache clean --force
225
+ npm cache verify
226
+ npm install -g claude-recall@latest
227
+
228
+ # Verify the installation
229
+ claude-recall --version
230
+ claude-recall mcp test
231
+ ```
232
+
233
+ ### Diagnostic Commands for Support
234
+
235
+ If you need help troubleshooting, run these commands and share the output:
236
+
237
+ ```bash
238
+ """# 1. Check Installation
239
+ claude-recall --version
240
+ which claude-recall
241
+ npm list -g claude-recall
242
+
243
+ # 2. Check MCP Configuration
244
+ cat ~/.claude.json | grep -A10 "claude-recall"
245
+ claude-recall mcp test
246
+
247
+ # 3. Check Database
248
+ ls -la ~/.claude-recall/
249
+ ls -lh ~/.claude-recall/claude-recall.db 2>/dev/null || echo "Database not found"
250
+
251
+ # 4. Check System Status
252
+ claude-recall status
253
+ claude-recall stats
254
+
255
+ # 5. Test Basic Functionality
256
+ claude-recall search "test"
257
+ claude-recall stats | grep "Total memories"
258
+
259
+ # 6. Check for Errors
260
+ ls -la *.log 2>/dev/null || echo "No log files"
261
+ tail -20 info.log 2>/dev/null || echo "No info log"
262
+
263
+ # 7. Environment Info
264
+ node --version
265
+ npm --version
266
+ echo "OS: $(uname -s)"
267
+ echo "Home: $HOME""""
268
+ ```
269
+
181
270
  ## Contributing
182
271
 
183
272
  We welcome contributions! Claude Recall is designed to be hackable:
@@ -251,7 +251,7 @@ async function main() {
251
251
  program
252
252
  .name('claude-recall')
253
253
  .description('Memory-enhanced Claude Code via MCP')
254
- .version('0.2.2')
254
+ .version('0.2.4')
255
255
  .option('--verbose', 'Enable verbose logging')
256
256
  .option('--config <path>', 'Path to custom config file');
257
257
  // MCP command
@@ -0,0 +1,64 @@
1
+ {
2
+ "preferencePatterns": [
3
+ {
4
+ "pattern": "(?:I prefer|I'd prefer|prefer|preferring)\\s+([\\w\\s]+)\\s+(?:over|instead of|rather than)\\s+([\\w\\s]+)",
5
+ "type": "preference",
6
+ "confidence": 0.9,
7
+ "extractionMode": "comparison"
8
+ },
9
+ {
10
+ "pattern": "(?:always use|always using|we always use)\\s+([\\w\\s\\-\\.]+)",
11
+ "type": "preference",
12
+ "confidence": 0.85,
13
+ "extractionMode": "directive"
14
+ },
15
+ {
16
+ "pattern": "(?:from now on|moving forward|going forward)(?:,)?\\s+(?:use|we'll use|let's use)\\s+([\\w\\s\\-\\.]+)",
17
+ "type": "decision",
18
+ "confidence": 0.9,
19
+ "extractionMode": "future_directive"
20
+ },
21
+ {
22
+ "pattern": "(?:should be|must be|needs to be)\\s+(?:in|at|under)\\s+(?:the)?\\s+([\\w\\/\\-\\.]+)\\s+(?:directory|folder|dir)",
23
+ "type": "location_preference",
24
+ "confidence": 0.8,
25
+ "extractionMode": "location"
26
+ },
27
+ {
28
+ "pattern": "(?:make sure|ensure)\\s+(?:to|that)\\s+([^.!?]+)",
29
+ "type": "instruction",
30
+ "confidence": 0.7,
31
+ "extractionMode": "requirement"
32
+ },
33
+ {
34
+ "pattern": "(?:remember|Remember)\\s+(?:that\\s+)?(.+?)(?:[.!?]|$)",
35
+ "type": "explicit_memory",
36
+ "confidence": 1.0,
37
+ "extractionMode": "direct_capture"
38
+ }
39
+ ],
40
+ "actionPatterns": [
41
+ {
42
+ "pattern": "(?:creating|created|adding|added)\\s+(?:a|an|the)?\\s*([\\w\\s]+)\\s+(?:in|at|to)\\s+([\\w\\/\\-\\.]+)",
43
+ "type": "file_creation",
44
+ "confidence": 0.75
45
+ },
46
+ {
47
+ "pattern": "(?:using|used|chose|chosen)\\s+([\\w\\s\\-\\.]+)\\s+(?:for|as)\\s+(?:the)?\\s*([\\w\\s]+)",
48
+ "type": "tool_choice",
49
+ "confidence": 0.8
50
+ }
51
+ ],
52
+ "contextTriggers": {
53
+ "highConfidenceWords": ["always", "never", "must", "should", "prefer", "requirement", "important"],
54
+ "decisionIndicators": ["decided", "choosing", "selected", "going with", "settled on"],
55
+ "futureTense": ["will", "going to", "from now on", "moving forward", "next time"]
56
+ },
57
+ "captureSettings": {
58
+ "minConfidence": 0.7,
59
+ "requireExplicitConfirmation": false,
60
+ "batchProcessingDelay": 1000,
61
+ "maxMemoriesPerSession": 50,
62
+ "deduplicationWindow": 3600000
63
+ }
64
+ }
@@ -0,0 +1,314 @@
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
+ exports.MemoryCaptureMiddleware = void 0;
37
+ const preference_extractor_1 = require("../services/preference-extractor");
38
+ const action_pattern_detector_1 = require("../services/action-pattern-detector");
39
+ const memory_1 = require("../services/memory");
40
+ const logging_1 = require("../services/logging");
41
+ const fs = __importStar(require("fs"));
42
+ const path = __importStar(require("path"));
43
+ class MemoryCaptureMiddleware {
44
+ constructor() {
45
+ this.recentCaptures = new Map();
46
+ this.sessionMemoryCount = new Map();
47
+ this.preferenceExtractor = new preference_extractor_1.PreferenceExtractor();
48
+ this.actionDetector = new action_pattern_detector_1.ActionPatternDetector();
49
+ this.memoryService = memory_1.MemoryService.getInstance();
50
+ this.logger = logging_1.LoggingService.getInstance();
51
+ this.loadConfig();
52
+ }
53
+ loadConfig() {
54
+ try {
55
+ // First try custom config location
56
+ const customConfigPath = process.env.CLAUDE_RECALL_PATTERNS_CONFIG;
57
+ const defaultConfigPath = path.join(__dirname, '../../config/memory-patterns.json');
58
+ const configPath = customConfigPath && fs.existsSync(customConfigPath)
59
+ ? customConfigPath
60
+ : defaultConfigPath;
61
+ if (fs.existsSync(configPath)) {
62
+ const configContent = fs.readFileSync(configPath, 'utf-8');
63
+ this.config = JSON.parse(configContent);
64
+ this.logger.info('MemoryCaptureMiddleware', 'Loaded memory patterns config', { configPath });
65
+ }
66
+ else {
67
+ // Use default config if file doesn't exist
68
+ this.config = this.getDefaultConfig();
69
+ this.logger.warn('MemoryCaptureMiddleware', 'Using default config, no config file found');
70
+ }
71
+ }
72
+ catch (error) {
73
+ this.logger.error('MemoryCaptureMiddleware', 'Failed to load config, using defaults', error);
74
+ this.config = this.getDefaultConfig();
75
+ }
76
+ }
77
+ getDefaultConfig() {
78
+ return {
79
+ preferencePatterns: [
80
+ {
81
+ pattern: "(?:I prefer|prefer)\\s+([\\w\\s]+)\\s+(?:over|instead of)\\s+([\\w\\s]+)",
82
+ type: "preference",
83
+ confidence: 0.9,
84
+ extractionMode: "comparison"
85
+ }
86
+ ],
87
+ actionPatterns: [],
88
+ contextTriggers: {
89
+ highConfidenceWords: ["always", "never", "must", "prefer"],
90
+ decisionIndicators: ["decided", "choosing", "selected"],
91
+ futureTense: ["will", "going to", "from now on"]
92
+ },
93
+ captureSettings: {
94
+ minConfidence: 0.7,
95
+ requireExplicitConfirmation: false,
96
+ batchProcessingDelay: 1000,
97
+ maxMemoriesPerSession: 50,
98
+ deduplicationWindow: 3600000
99
+ }
100
+ };
101
+ }
102
+ /**
103
+ * Process a request/response pair for automatic memory capture
104
+ */
105
+ async processForMemoryCapture(request, response, sessionId) {
106
+ try {
107
+ // Don't capture from memory-related tools to avoid loops
108
+ if (request.method === 'tools/call' &&
109
+ request.params?.name?.includes('memory')) {
110
+ return;
111
+ }
112
+ // Extract content to analyze
113
+ const contentToAnalyze = this.extractContent(request, response);
114
+ if (!contentToAnalyze)
115
+ return;
116
+ // Check session memory limit
117
+ const sessionCount = this.sessionMemoryCount.get(sessionId) || 0;
118
+ if (sessionCount >= this.config.captureSettings.maxMemoriesPerSession) {
119
+ this.logger.debug('MemoryCaptureMiddleware', 'Session memory limit reached', { sessionId, count: sessionCount });
120
+ return;
121
+ }
122
+ // Analyze for patterns
123
+ const detectedMemories = await this.analyzeContent(contentToAnalyze, sessionId);
124
+ // Store unique memories
125
+ for (const memory of detectedMemories) {
126
+ if (this.shouldCapture(memory, sessionId)) {
127
+ await this.captureMemory(memory, sessionId);
128
+ }
129
+ }
130
+ }
131
+ catch (error) {
132
+ this.logger.error('MemoryCaptureMiddleware', 'Error in memory capture', error);
133
+ }
134
+ }
135
+ extractContent(request, response) {
136
+ let content = '';
137
+ // Extract from request
138
+ if (request.params?.arguments?.content) {
139
+ content += request.params.arguments.content + '\n';
140
+ }
141
+ // Extract from response
142
+ if (response.result?.content) {
143
+ if (Array.isArray(response.result.content)) {
144
+ response.result.content.forEach((item) => {
145
+ if (item.text)
146
+ content += item.text + '\n';
147
+ });
148
+ }
149
+ else if (typeof response.result.content === 'string') {
150
+ content += response.result.content + '\n';
151
+ }
152
+ }
153
+ return content.trim() || null;
154
+ }
155
+ async analyzeContent(content, sessionId) {
156
+ const memories = [];
157
+ // PRIORITY 1: Check for explicit "remember" commands
158
+ const rememberRegex = /(?:remember|Remember)\s+(?:that\s+)?(.+?)(?:[.!?]|$)/gi;
159
+ const rememberMatches = content.matchAll(rememberRegex);
160
+ for (const match of rememberMatches) {
161
+ const memoryContent = match[1].trim();
162
+ if (memoryContent) {
163
+ memories.push({
164
+ type: 'explicit_memory',
165
+ content: memoryContent,
166
+ data: {
167
+ raw: memoryContent,
168
+ source: 'explicit_remember_command',
169
+ confidence: 1.0
170
+ },
171
+ confidence: 1.0, // Always highest confidence
172
+ priority: 1 // Highest priority
173
+ });
174
+ }
175
+ }
176
+ // PRIORITY 2: Use configured preference patterns
177
+ for (const pattern of this.config.preferencePatterns) {
178
+ const regex = new RegExp(pattern.pattern, 'gi');
179
+ const matches = content.matchAll(regex);
180
+ for (const match of matches) {
181
+ // Skip if this was already captured as explicit memory
182
+ if (match[0].toLowerCase().includes('remember'))
183
+ continue;
184
+ memories.push({
185
+ type: pattern.type,
186
+ content: match[0],
187
+ data: {
188
+ pattern: pattern.type,
189
+ captured: match.slice(1),
190
+ confidence: pattern.confidence,
191
+ extractionMode: pattern.extractionMode
192
+ },
193
+ confidence: pattern.confidence,
194
+ priority: 2
195
+ });
196
+ }
197
+ }
198
+ // PRIORITY 3: Use existing PreferenceExtractor
199
+ const preferences = this.preferenceExtractor.extractPreferences(content);
200
+ for (const pref of preferences) {
201
+ if (pref.confidence >= this.config.captureSettings.minConfidence) {
202
+ // Skip if already captured as explicit memory
203
+ if (pref.raw.toLowerCase().includes('remember'))
204
+ continue;
205
+ memories.push({
206
+ type: 'preference',
207
+ content: pref.raw,
208
+ data: {
209
+ key: pref.key,
210
+ value: pref.value,
211
+ confidence: pref.confidence
212
+ },
213
+ confidence: pref.confidence,
214
+ priority: 3
215
+ });
216
+ }
217
+ }
218
+ // Check for action patterns using configured patterns
219
+ for (const pattern of this.config.actionPatterns) {
220
+ const regex = new RegExp(pattern.pattern, 'gi');
221
+ const matches = content.matchAll(regex);
222
+ for (const match of matches) {
223
+ memories.push({
224
+ type: pattern.type,
225
+ content: match[0],
226
+ data: {
227
+ pattern: pattern.type,
228
+ captured: match.slice(1),
229
+ confidence: pattern.confidence
230
+ },
231
+ confidence: pattern.confidence
232
+ });
233
+ }
234
+ }
235
+ // Check for high-confidence context triggers
236
+ const hasHighConfidenceContext = this.config.contextTriggers.highConfidenceWords.some(word => content.toLowerCase().includes(word.toLowerCase()));
237
+ if (hasHighConfidenceContext) {
238
+ // Boost confidence for all found patterns
239
+ memories.forEach(m => m.confidence = Math.min(1.0, m.confidence * 1.1));
240
+ }
241
+ return memories;
242
+ }
243
+ shouldCapture(memory, sessionId) {
244
+ // ALWAYS capture explicit "remember" commands
245
+ if (memory.type === 'explicit_memory' || memory.priority === 1) {
246
+ return true;
247
+ }
248
+ // Check confidence threshold for other types
249
+ if (memory.confidence < this.config.captureSettings.minConfidence) {
250
+ return false;
251
+ }
252
+ // Check for duplicates within deduplication window
253
+ const memoryKey = `${memory.type}:${memory.content}`;
254
+ const lastCapture = this.recentCaptures.get(memoryKey);
255
+ const now = Date.now();
256
+ if (lastCapture && (now - lastCapture) < this.config.captureSettings.deduplicationWindow) {
257
+ return false;
258
+ }
259
+ return true;
260
+ }
261
+ async captureMemory(memory, sessionId) {
262
+ try {
263
+ // Store using MemoryService
264
+ const stored = this.memoryService.store({
265
+ key: `auto_${memory.type}_${Date.now()}`,
266
+ value: memory.data,
267
+ type: memory.type,
268
+ context: {
269
+ projectId: sessionId,
270
+ type: 'auto_capture',
271
+ timestamp: Date.now()
272
+ }
273
+ });
274
+ // Update tracking
275
+ const memoryKey = `${memory.type}:${memory.content}`;
276
+ this.recentCaptures.set(memoryKey, Date.now());
277
+ const currentCount = this.sessionMemoryCount.get(sessionId) || 0;
278
+ this.sessionMemoryCount.set(sessionId, currentCount + 1);
279
+ this.logger.info('MemoryCaptureMiddleware', 'Auto-captured memory', {
280
+ type: memory.type,
281
+ confidence: memory.confidence,
282
+ sessionId
283
+ });
284
+ }
285
+ catch (error) {
286
+ this.logger.error('MemoryCaptureMiddleware', 'Failed to capture memory', error);
287
+ }
288
+ }
289
+ /**
290
+ * Clean up old session data
291
+ */
292
+ cleanupSessions() {
293
+ // Clean up old captures
294
+ const now = Date.now();
295
+ const cutoff = now - this.config.captureSettings.deduplicationWindow;
296
+ for (const [key, timestamp] of this.recentCaptures) {
297
+ if (timestamp < cutoff) {
298
+ this.recentCaptures.delete(key);
299
+ }
300
+ }
301
+ // Reset session counts periodically
302
+ if (this.sessionMemoryCount.size > 100) {
303
+ this.sessionMemoryCount.clear();
304
+ }
305
+ }
306
+ /**
307
+ * Reload configuration (useful for hot-reloading)
308
+ */
309
+ reloadConfig() {
310
+ this.loadConfig();
311
+ this.logger.info('MemoryCaptureMiddleware', 'Configuration reloaded');
312
+ }
313
+ }
314
+ exports.MemoryCaptureMiddleware = MemoryCaptureMiddleware;
@@ -7,6 +7,7 @@ const memory_1 = require("../services/memory");
7
7
  const logging_1 = require("../services/logging");
8
8
  const session_manager_1 = require("./session-manager");
9
9
  const rate_limiter_1 = require("./rate-limiter");
10
+ const memory_capture_middleware_1 = require("./memory-capture-middleware");
10
11
  class MCPServer {
11
12
  constructor() {
12
13
  this.tools = new Map();
@@ -21,31 +22,45 @@ class MCPServer {
21
22
  maxRequests: 100, // 100 requests per minute
22
23
  skipSuccessfulRequests: false
23
24
  });
25
+ this.memoryCaptureMiddleware = new memory_capture_middleware_1.MemoryCaptureMiddleware();
24
26
  this.setupRequestHandlers();
25
27
  this.registerTools();
26
28
  }
27
29
  setupRequestHandlers() {
28
30
  this.transport.onRequest(async (request) => {
31
+ let response;
29
32
  try {
30
33
  switch (request.method) {
31
34
  case 'initialize':
32
- return this.handleInitialize(request);
35
+ response = await this.handleInitialize(request);
36
+ break;
33
37
  case 'tools/list':
34
- return this.handleToolsList(request);
38
+ response = await this.handleToolsList(request);
39
+ break;
35
40
  case 'tools/call':
36
- return this.handleToolCall(request);
41
+ response = await this.handleToolCall(request);
42
+ break;
37
43
  case 'notifications/initialized':
38
- return this.handleInitialized(request);
44
+ response = await this.handleInitialized(request);
45
+ break;
39
46
  case 'health/check':
40
- return this.handleHealthCheck(request);
47
+ response = await this.handleHealthCheck(request);
48
+ break;
41
49
  default:
42
- return this.createErrorResponse(request.id, -32601, `Method not found: ${request.method}`);
50
+ response = this.createErrorResponse(request.id, -32601, `Method not found: ${request.method}`);
43
51
  }
44
52
  }
45
53
  catch (error) {
46
54
  this.logger.logServiceError('MCPServer', 'handleRequest', error, { method: request.method });
47
- return this.createErrorResponse(request.id, -32603, 'Internal error', { message: error.message });
55
+ response = this.createErrorResponse(request.id, -32603, 'Internal error', { message: error.message });
48
56
  }
57
+ // Process for automatic memory capture (non-blocking)
58
+ if (this.isInitialized && request.method === 'tools/call') {
59
+ const sessionId = request.params?.arguments?.sessionId || this.generateSessionId();
60
+ this.memoryCaptureMiddleware.processForMemoryCapture(request, response, sessionId)
61
+ .catch(err => this.logger.error('MCPServer', 'Memory capture failed', err));
62
+ }
63
+ return response;
49
64
  });
50
65
  }
51
66
  registerTools() {
@@ -257,6 +272,8 @@ class MCPServer {
257
272
  this.sessionManager.shutdown();
258
273
  // Shutdown rate limiter
259
274
  this.rateLimiter.shutdown();
275
+ // Clean up memory capture middleware
276
+ this.memoryCaptureMiddleware.cleanupSessions();
260
277
  await this.transport.stop();
261
278
  this.memoryService.close();
262
279
  this.logger.info('MCPServer', 'MCP server stopped');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-recall",
3
- "version": "0.2.2",
3
+ "version": "0.2.4",
4
4
  "description": "MCP server for persistent memory in Claude Code conversations",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
@@ -21,7 +21,7 @@
21
21
  "postinstall": "node scripts/postinstall.js || true",
22
22
  "test": "jest --passWithNoTests",
23
23
  "test:watch": "jest --watch",
24
- "build": "tsc && mkdir -p dist/memory && cp src/memory/schema.sql dist/memory/ && chmod +x dist/cli/claude-recall-cli.js",
24
+ "build": "tsc && mkdir -p dist/memory dist/config && cp src/memory/schema.sql dist/memory/ && cp -r src/config/* dist/config/ 2>/dev/null || true && chmod +x dist/cli/claude-recall-cli.js",
25
25
  "build:cli": "tsc && chmod +x dist/cli/claude-recall-cli.js",
26
26
  "dev": "ts-node",
27
27
  "start": "ts-node src/server.ts",
@@ -57,6 +57,84 @@ try {
57
57
  fs.writeFileSync(claudeConfigPath, JSON.stringify(config, null, 2));
58
58
 
59
59
  console.log('āœ… Successfully configured Claude Recall in ~/.claude.json');
60
+
61
+ // Update CLAUDE.md with instructions
62
+ const claudeMdInstructions = `
63
+ # Claude Recall Memory Instructions
64
+
65
+ IMPORTANT: When the user uses any of these words or phrases, you MUST call the appropriate claude-recall MCP tool:
66
+
67
+ ## Memory Storage Triggers
68
+ When you see these words/phrases, ALWAYS call \`mcp__claude-recall__store_memory\`:
69
+ - "remember" / "remember that" / "please remember"
70
+ - "store" / "store in memory" / "save to memory"
71
+ - "don't forget" / "do not forget"
72
+ - "keep in mind" / "bear in mind"
73
+ - "note that" / "take note"
74
+ - "for future reference"
75
+ - "memorize"
76
+
77
+ Example: If user says "Remember that I prefer tabs over spaces", you must call:
78
+ \`\`\`
79
+ mcp__claude-recall__store_memory({
80
+ content: "User prefers tabs over spaces",
81
+ metadata: { type: "preference" }
82
+ })
83
+ \`\`\`
84
+
85
+ ## Memory Retrieval Triggers
86
+ When you see these words/phrases, ALWAYS call \`mcp__claude-recall__search\` or \`mcp__claude-recall__retrieve_memory\`:
87
+ - "recall" / "what did I tell you about"
88
+ - "what do you remember about"
89
+ - "retrieve" / "fetch from memory"
90
+ - "what's in your memory about"
91
+ - "what did we discuss about"
92
+ - "do you remember"
93
+
94
+ ## Important
95
+ - ALWAYS acknowledge that you're storing/retrieving the memory
96
+ - Be explicit about what was stored or retrieved
97
+ - These instructions ensure your memory system works reliably
98
+ `;
99
+
100
+ // Try to find CLAUDE.md in common locations
101
+ const claudeMdPaths = [
102
+ path.join(process.cwd(), 'CLAUDE.md'),
103
+ path.join(os.homedir(), 'CLAUDE.md'),
104
+ path.join(process.cwd(), '.claude', 'CLAUDE.md'),
105
+ path.join(os.homedir(), '.claude', 'CLAUDE.md')
106
+ ];
107
+
108
+ let claudeMdPath = claudeMdPaths.find(p => fs.existsSync(p));
109
+
110
+ // If not found, create it in the current directory
111
+ if (!claudeMdPath) {
112
+ claudeMdPath = path.join(process.cwd(), 'CLAUDE.md');
113
+ }
114
+
115
+ try {
116
+ let existingContent = '';
117
+ if (fs.existsSync(claudeMdPath)) {
118
+ existingContent = fs.readFileSync(claudeMdPath, 'utf8');
119
+
120
+ // Check if instructions already exist
121
+ if (existingContent.includes('Claude Recall Memory Instructions')) {
122
+ console.log('šŸ“ CLAUDE.md already contains Claude Recall instructions');
123
+ } else {
124
+ // Append instructions
125
+ fs.writeFileSync(claudeMdPath, existingContent + '\n' + claudeMdInstructions);
126
+ console.log(`šŸ“ Updated ${claudeMdPath} with memory instructions`);
127
+ }
128
+ } else {
129
+ // Create new file
130
+ fs.writeFileSync(claudeMdPath, claudeMdInstructions);
131
+ console.log(`šŸ“ Created ${claudeMdPath} with memory instructions`);
132
+ }
133
+ } catch (err) {
134
+ console.log('āš ļø Could not update CLAUDE.md:', err.message);
135
+ console.log(' Please add the memory instructions manually to your CLAUDE.md file');
136
+ }
137
+
60
138
  console.log('\nšŸ“ Next steps:');
61
139
  console.log(' 1. Restart Claude Code if it\'s currently running');
62
140
  console.log(' 2. Claude Recall will start automatically when you launch Claude Code');