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 +16 -17
- package/installer/cli.js +2 -0
- package/installer/setup-wizard.js +120 -12
- package/mcp-server/src/server.py +19 -5
- package/package.json +1 -1
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
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
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
|
-
|
|
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
|
-
|
|
295
|
-
|
|
365
|
+
debugLog(`Running: ${pythonCmd} -m venv venv in ${mcpPath}`);
|
|
366
|
+
|
|
296
367
|
const result = spawnSync(pythonCmd, ['-m', 'venv', 'venv'], {
|
|
297
368
|
cwd: mcpPath,
|
|
298
|
-
|
|
369
|
+
encoding: 'utf8'
|
|
299
370
|
});
|
|
300
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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('
|
|
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
|
}
|
package/mcp-server/src/server.py
CHANGED
|
@@ -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=
|
|
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=
|
|
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=
|
|
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
|
-
|
|
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}")
|