claude-self-reflect 2.3.8 → 2.4.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/README.md CHANGED
@@ -49,23 +49,14 @@ claude-self-reflect setup --voyage-key=YOUR_ACTUAL_KEY_HERE
49
49
 
50
50
  5 minutes. Everything automatic. Just works.
51
51
 
52
- > [!IMPORTANT]
53
- > **Security Update v2.3.3** - This version addresses critical security vulnerabilities. Please update immediately.
54
- >
55
- > ### šŸ”’ Privacy & Data Exchange
56
- >
57
- > | Mode | Data Storage | External API Calls | Data Sent | Search Quality |
58
- > |------|--------------|-------------------|-----------|----------------|
59
- > | **Local (Default)** | Your machine only | None | Nothing leaves your computer | Good - uses efficient local embeddings |
60
- > | **Cloud (Opt-in)** | Your machine | Voyage AI | Conversation text for embedding generation | Better - uses state-of-the-art models |
61
- >
62
- > **Disclaimer**: Cloud mode sends conversation content to Voyage AI for processing. Review their [privacy policy](https://www.voyageai.com/privacy) before enabling.
63
- >
64
- > ### Security Fixes in v2.3.3
65
- > - āœ… Removed hardcoded API keys
66
- > - āœ… Fixed command injection vulnerabilities
67
- > - āœ… Patched vulnerable dependencies
68
- > - āœ… Local embeddings by default using FastEmbed
52
+ ### šŸ”’ Privacy & Data Exchange
53
+
54
+ | Mode | Data Storage | External API Calls | Data Sent | Search Quality |
55
+ |------|--------------|-------------------|-----------|----------------|
56
+ | **Local (Default)** | Your machine only | None | Nothing leaves your computer | Good - uses efficient local embeddings |
57
+ | **Cloud (Opt-in)** | Your machine | Voyage AI | Conversation text for embedding generation | Better - uses state-of-the-art models |
58
+
59
+ **Note**: Cloud mode sends conversation content to Voyage AI for processing. Review their [privacy policy](https://www.voyageai.com/privacy) before enabling.
69
60
 
70
61
  ## The Magic
71
62
 
@@ -223,4 +214,12 @@ Monitor the release at: https://github.com/ramakay/claude-self-reflect/actions
223
214
 
224
215
  Stop reading. Start installing. Your future self will thank you.
225
216
 
217
+ ## Contributors & Acknowledgments
218
+
219
+ Special thanks to our contributors and security researchers:
220
+
221
+ - **[@TheGordon](https://github.com/TheGordon)** - Fixed critical timestamp parsing bug for Claude conversation exports (#10)
222
+ - **[@akamalov](https://github.com/akamalov)** - Highlighted Ubuntu WSL bug and helped educate about filesystem nuances
223
+ - **[@kylesnowschwartz](https://github.com/kylesnowschwartz)** - Comprehensive security review leading to v2.3.3+ security improvements (#6)
224
+
226
225
  MIT License. Built with ā¤ļø for the Claude community.
package/installer/cli.js CHANGED
@@ -118,10 +118,12 @@ function help() {
118
118
  console.log('\nSetup Options:');
119
119
  console.log(' --voyage-key=<key> Provide Voyage AI API key (recommended)');
120
120
  console.log(' --local Run in local mode without API key');
121
+ console.log(' --debug Enable debug output for troubleshooting');
121
122
 
122
123
  console.log('\nExamples:');
123
124
  console.log(' claude-self-reflect setup --voyage-key=pa-1234567890');
124
125
  console.log(' claude-self-reflect setup --local');
126
+ console.log(' claude-self-reflect setup --debug # For troubleshooting');
125
127
 
126
128
  console.log('\nFor more information: https://github.com/ramakay/claude-self-reflect');
127
129
  }
@@ -4,6 +4,7 @@ import { execSync, spawn, spawnSync } from 'child_process';
4
4
  import { fileURLToPath } from 'url';
5
5
  import { dirname, join } from 'path';
6
6
  import fs from 'fs/promises';
7
+ import fsSync from 'fs';
7
8
  import readline from 'readline';
8
9
  import path from 'path';
9
10
 
@@ -37,16 +38,36 @@ function safeExec(command, args = [], options = {}) {
37
38
  const args = process.argv.slice(2);
38
39
  let voyageKey = null;
39
40
  let mcpConfigured = false;
41
+ let debugMode = false;
40
42
 
41
43
  for (const arg of args) {
42
44
  if (arg.startsWith('--voyage-key=')) {
43
45
  voyageKey = arg.split('=')[1];
46
+ } else if (arg === '--debug') {
47
+ debugMode = true;
44
48
  }
45
49
  }
46
50
 
47
51
  // Default to local mode unless Voyage key is provided
48
52
  let localMode = !voyageKey;
49
53
 
54
+ // WSL Detection
55
+ function isWSL() {
56
+ try {
57
+ const osRelease = fsSync.readFileSync('/proc/version', 'utf8');
58
+ return osRelease.toLowerCase().includes('microsoft') || osRelease.toLowerCase().includes('wsl');
59
+ } catch {
60
+ return false;
61
+ }
62
+ }
63
+
64
+ // Debug logging helper
65
+ function debugLog(...args) {
66
+ if (debugMode) {
67
+ console.log('[DEBUG]', ...args);
68
+ }
69
+ }
70
+
50
71
  const isInteractive = process.stdin.isTTY && process.stdout.isTTY;
51
72
 
52
73
  const rl = isInteractive ? readline.createInterface({
@@ -238,6 +259,12 @@ async function checkQdrant() {
238
259
  async function setupPythonEnvironment() {
239
260
  console.log('\nšŸ Setting up Python MCP server...');
240
261
 
262
+ // Detect WSL environment
263
+ if (isWSL()) {
264
+ console.log('🐧 WSL environment detected');
265
+ debugLog('Running on WSL, may need special handling');
266
+ }
267
+
241
268
  const mcpPath = join(projectRoot, 'mcp-server');
242
269
  const scriptsPath = join(projectRoot, 'scripts');
243
270
 
@@ -277,8 +304,7 @@ async function setupPythonEnvironment() {
277
304
  console.log(' Removing and recreating...');
278
305
 
279
306
  // Remove broken venv
280
- const { rmSync } = await import('fs');
281
- rmSync(venvPath, { recursive: true, force: true });
307
+ fsSync.rmSync(venvPath, { recursive: true, force: true });
282
308
  venvExists = false;
283
309
  venvHealthy = false;
284
310
  }
@@ -287,33 +313,115 @@ async function setupPythonEnvironment() {
287
313
  }
288
314
 
289
315
  if (!venvExists || !venvHealthy) {
316
+ // Pre-flight checks before creating venv
317
+ console.log('Checking Python environment...');
318
+ const pythonCmd = process.env.PYTHON_PATH || 'python3';
319
+
320
+ // Check if Python is available and get version
321
+ try {
322
+ const pythonVersion = safeExec(pythonCmd, ['--version'], { stdio: 'pipe' });
323
+ debugLog(`Python version: ${pythonVersion.trim()}`);
324
+ } catch (e) {
325
+ console.log('āŒ Python not found');
326
+ console.log('šŸ“š Fix: Install Python 3.10 or higher');
327
+ return false;
328
+ }
329
+
330
+ // Check if venv module is available
331
+ debugLog('Checking if venv module is available...');
332
+ try {
333
+ const venvCheck = spawnSync(pythonCmd, ['-c', 'import venv; print("venv module OK")'], {
334
+ cwd: mcpPath,
335
+ encoding: 'utf8'
336
+ });
337
+
338
+ if (venvCheck.status !== 0) {
339
+ debugLog(`venv module check failed: ${venvCheck.stderr}`);
340
+
341
+ // WSL-specific guidance
342
+ if (isWSL()) {
343
+ console.log('\nāš ļø WSL-specific issue detected');
344
+ console.log('Common WSL fixes:');
345
+ console.log('1. Install python3-venv: sudo apt install python3.10-venv');
346
+ console.log('2. Use specific Python version: export PYTHON_PATH=python3.10');
347
+ console.log('3. Check WSL Python paths: which python3');
348
+ }
349
+
350
+ throw new Error('venv module not available');
351
+ }
352
+ debugLog('venv module is available');
353
+ } catch (moduleError) {
354
+ console.log('āŒ Python venv module not found');
355
+ console.log('šŸ“š Fix: Install python3-venv package');
356
+ console.log(' Ubuntu/Debian: sudo apt install python3-venv');
357
+ console.log(' WSL Ubuntu: sudo apt install python3.10-venv');
358
+ console.log(' macOS: Should be included with Python');
359
+ return false;
360
+ }
361
+
290
362
  // Create virtual environment
291
363
  console.log('Creating virtual environment...');
292
- const pythonCmd = process.env.PYTHON_PATH || 'python3';
293
364
  try {
294
- // Use spawn with proper path handling instead of shell execution
295
- const { spawnSync } = require('child_process');
365
+ debugLog(`Running: ${pythonCmd} -m venv venv in ${mcpPath}`);
366
+
296
367
  const result = spawnSync(pythonCmd, ['-m', 'venv', 'venv'], {
297
368
  cwd: mcpPath,
298
- stdio: 'inherit'
369
+ encoding: 'utf8'
299
370
  });
300
- if (result.error) throw result.error;
371
+
372
+ if (result.error) {
373
+ debugLog(`spawnSync error: ${result.error.message}`);
374
+ throw result.error;
375
+ }
376
+
377
+ if (result.status !== 0) {
378
+ debugLog(`venv creation failed with status ${result.status}`);
379
+ debugLog(`stdout: ${result.stdout}`);
380
+ debugLog(`stderr: ${result.stderr}`);
381
+
382
+ // Check for common WSL issues
383
+ if (isWSL() && result.stderr && result.stderr.includes('ensurepip')) {
384
+ console.log('\nāš ļø WSL pip installation issue detected');
385
+ console.log('Try: sudo apt install python3-pip python3.10-distutils');
386
+ }
387
+
388
+ throw new Error(`venv creation failed: ${result.stderr}`);
389
+ }
390
+
391
+ console.log('āœ… Virtual environment created');
301
392
  needsInstall = true; // Mark that we need to install dependencies
302
393
  } catch (venvError) {
303
394
  console.log('āš ļø Failed to create venv with python3, trying python...');
304
395
  try {
305
- const { spawnSync } = require('child_process');
306
396
  const result = spawnSync('python', ['-m', 'venv', 'venv'], {
307
397
  cwd: mcpPath,
308
- stdio: 'inherit'
398
+ encoding: 'utf8'
309
399
  });
400
+
310
401
  if (result.error) throw result.error;
402
+ if (result.status !== 0) {
403
+ debugLog(`Python venv creation failed: ${result.stderr}`);
404
+ throw new Error(result.stderr);
405
+ }
406
+
311
407
  needsInstall = true; // Mark that we need to install dependencies
312
- } catch {
408
+ } catch (fallbackError) {
313
409
  console.log('āŒ Failed to create virtual environment');
314
- console.log('šŸ“š Fix: Install python3-venv package');
410
+
411
+ if (debugMode) {
412
+ console.log('\nšŸ” Debug Information:');
413
+ console.log(`Error: ${fallbackError.message}`);
414
+ console.log(`Working directory: ${mcpPath}`);
415
+ console.log(`Python command: ${pythonCmd}`);
416
+ }
417
+
418
+ console.log('\nšŸ“š Troubleshooting:');
419
+ console.log('1. Check Python installation: python3 --version');
420
+ console.log('2. Install venv package:');
315
421
  console.log(' Ubuntu/Debian: sudo apt install python3-venv');
316
- console.log(' macOS: Should be included with Python');
422
+ console.log(' WSL: sudo apt install python3.10-venv python3-pip');
423
+ console.log('3. Try with specific Python: PYTHON_PATH=python3.10 npm run setup');
424
+
317
425
  return false;
318
426
  }
319
427
  }
@@ -222,10 +222,14 @@ async def reflect_on_past(
222
222
 
223
223
  # Process results from native decay search
224
224
  for point in results.points:
225
+ # Clean timestamp for proper parsing
226
+ raw_timestamp = point.payload.get('timestamp', datetime.now().isoformat())
227
+ clean_timestamp = raw_timestamp.replace('Z', '+00:00') if raw_timestamp.endswith('Z') else raw_timestamp
228
+
225
229
  all_results.append(SearchResult(
226
230
  id=str(point.id),
227
231
  score=point.score, # Score already includes decay
228
- timestamp=point.payload.get('timestamp', datetime.now().isoformat()),
232
+ timestamp=clean_timestamp,
229
233
  role=point.payload.get('start_role', point.payload.get('role', 'unknown')),
230
234
  excerpt=(point.payload.get('text', '')[:500] + '...'),
231
235
  project_name=point.payload.get('project', collection_name.replace('conv_', '').replace('_voyage', '').replace('_local', '')),
@@ -283,10 +287,14 @@ async def reflect_on_past(
283
287
 
284
288
  # Convert to SearchResult format
285
289
  for adjusted_score, point in decay_results[:limit]:
290
+ # Clean timestamp for proper parsing
291
+ raw_timestamp = point.payload.get('timestamp', datetime.now().isoformat())
292
+ clean_timestamp = raw_timestamp.replace('Z', '+00:00') if raw_timestamp.endswith('Z') else raw_timestamp
293
+
286
294
  all_results.append(SearchResult(
287
295
  id=str(point.id),
288
296
  score=adjusted_score, # Use adjusted score
289
- timestamp=point.payload.get('timestamp', datetime.now().isoformat()),
297
+ timestamp=clean_timestamp,
290
298
  role=point.payload.get('start_role', point.payload.get('role', 'unknown')),
291
299
  excerpt=(point.payload.get('text', '')[:500] + '...'),
292
300
  project_name=point.payload.get('project', collection_name.replace('conv_', '').replace('_voyage', '').replace('_local', '')),
@@ -304,10 +312,14 @@ async def reflect_on_past(
304
312
  )
305
313
 
306
314
  for point in results:
315
+ # Clean timestamp for proper parsing
316
+ raw_timestamp = point.payload.get('timestamp', datetime.now().isoformat())
317
+ clean_timestamp = raw_timestamp.replace('Z', '+00:00') if raw_timestamp.endswith('Z') else raw_timestamp
318
+
307
319
  all_results.append(SearchResult(
308
320
  id=str(point.id),
309
321
  score=point.score,
310
- timestamp=point.payload.get('timestamp', datetime.now().isoformat()),
322
+ timestamp=clean_timestamp,
311
323
  role=point.payload.get('start_role', point.payload.get('role', 'unknown')),
312
324
  excerpt=(point.payload.get('text', '')[:500] + '...'),
313
325
  project_name=point.payload.get('project', collection_name.replace('conv_', '').replace('_voyage', '').replace('_local', '')),
@@ -330,7 +342,9 @@ async def reflect_on_past(
330
342
  result_text = f"Found {len(all_results)} relevant conversation(s) for '{query}':\n\n"
331
343
  for i, result in enumerate(all_results):
332
344
  result_text += f"**Result {i+1}** (Score: {result.score:.3f})\n"
333
- result_text += f"Time: {datetime.fromisoformat(result.timestamp).strftime('%Y-%m-%d %H:%M:%S')}\n"
345
+ # Handle timezone suffix 'Z' properly
346
+ timestamp_clean = result.timestamp.replace('Z', '+00:00') if result.timestamp.endswith('Z') else result.timestamp
347
+ result_text += f"Time: {datetime.fromisoformat(timestamp_clean).strftime('%Y-%m-%d %H:%M:%S')}\n"
334
348
  result_text += f"Project: {result.project_name}\n"
335
349
  result_text += f"Role: {result.role}\n"
336
350
  result_text += f"Excerpt: {result.excerpt}\n"
@@ -400,4 +414,4 @@ async def store_reflection(
400
414
 
401
415
 
402
416
  # Debug output
403
- print(f"[DEBUG] FastMCP server created with name: {mcp.name}")
417
+ print(f"[DEBUG] FastMCP server created with name: {mcp.name}")
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-self-reflect",
3
- "version": "2.3.8",
3
+ "version": "2.4.0",
4
4
  "description": "Give Claude perfect memory of all your conversations - Installation wizard for Python MCP server",
5
5
  "keywords": [
6
6
  "claude",