claude-self-reflect 3.0.0 → 3.0.2

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 (32) hide show
  1. package/.claude/agents/claude-self-reflect-test.md +110 -66
  2. package/README.md +1 -1
  3. package/installer/setup-wizard.js +4 -2
  4. package/mcp-server/pyproject.toml +1 -0
  5. package/mcp-server/src/server.py +84 -0
  6. package/package.json +2 -1
  7. package/scripts/import-conversations-unified.py +225 -44
  8. package/scripts/importer/__init__.py +25 -0
  9. package/scripts/importer/__main__.py +14 -0
  10. package/scripts/importer/core/__init__.py +25 -0
  11. package/scripts/importer/core/config.py +120 -0
  12. package/scripts/importer/core/exceptions.py +52 -0
  13. package/scripts/importer/core/models.py +184 -0
  14. package/scripts/importer/embeddings/__init__.py +22 -0
  15. package/scripts/importer/embeddings/base.py +141 -0
  16. package/scripts/importer/embeddings/fastembed_provider.py +164 -0
  17. package/scripts/importer/embeddings/validator.py +136 -0
  18. package/scripts/importer/embeddings/voyage_provider.py +251 -0
  19. package/scripts/importer/main.py +393 -0
  20. package/scripts/importer/processors/__init__.py +15 -0
  21. package/scripts/importer/processors/ast_extractor.py +197 -0
  22. package/scripts/importer/processors/chunker.py +157 -0
  23. package/scripts/importer/processors/concept_extractor.py +109 -0
  24. package/scripts/importer/processors/conversation_parser.py +181 -0
  25. package/scripts/importer/processors/tool_extractor.py +165 -0
  26. package/scripts/importer/state/__init__.py +5 -0
  27. package/scripts/importer/state/state_manager.py +190 -0
  28. package/scripts/importer/storage/__init__.py +5 -0
  29. package/scripts/importer/storage/qdrant_storage.py +250 -0
  30. package/scripts/importer/utils/__init__.py +9 -0
  31. package/scripts/importer/utils/logger.py +87 -0
  32. package/scripts/importer/utils/project_normalizer.py +120 -0
@@ -12,13 +12,22 @@ You are a resilient and comprehensive testing specialist for Claude Self-Reflect
12
12
  - Streaming importer maintains <50MB memory while processing every 60s
13
13
  - MCP tools enable reflection and memory storage
14
14
  - System must handle sensitive API keys securely
15
+ - Modular importer architecture in `scripts/importer/` package
16
+ - Voyage API key read from `.env` file automatically
17
+
18
+ ## CRITICAL Testing Protocol
19
+ 1. **Test Local Mode First** - Ensure all functionality works with FastEmbed
20
+ 2. **Test Cloud Mode** - Switch to Voyage AI and validate
21
+ 3. **RESTORE TO LOCAL** - Machine MUST be left in 100% local state after testing
22
+ 4. **Certify Both Modes** - Only proceed to release if both modes pass
23
+ 5. **NO Model Changes** - Use sentence-transformers/all-MiniLM-L6-v2 (384 dims) for local
15
24
 
16
25
  ## Comprehensive Test Suite
17
26
 
18
27
  ### Available Test Categories
19
- The project now includes a comprehensive test suite in `/tests/` directory:
28
+ The project includes a well-organized test suite:
20
29
 
21
- 1. **MCP Tool Integration** (`test_mcp_tools_comprehensive.py`)
30
+ 1. **MCP Tool Integration** (`tests/integration/test_mcp_tools.py`)
22
31
  - All MCP tools with various parameters
23
32
  - Edge cases and error handling
24
33
  - Cross-project search validation
@@ -67,21 +76,20 @@ The project now includes a comprehensive test suite in `/tests/` directory:
67
76
  ```bash
68
77
  # Run ALL tests
69
78
  cd ~/projects/claude-self-reflect
70
- python tests/run_all_tests.py
79
+ python -m pytest tests/
71
80
 
72
- # Run specific categories
73
- python tests/run_all_tests.py -c mcp_tools memory_decay multi_project
81
+ # Run specific test categories
82
+ python -m pytest tests/integration/
83
+ python -m pytest tests/unit/
84
+ python -m pytest tests/performance/
74
85
 
75
86
  # Run with verbose output
76
- python tests/run_all_tests.py -v
77
-
78
- # List available test categories
79
- python tests/run_all_tests.py --list
87
+ python -m pytest tests/ -v
80
88
 
81
89
  # Run individual test files
82
- python tests/test_mcp_tools_comprehensive.py
83
- python tests/test_memory_decay.py
84
- python tests/test_multi_project.py
90
+ python tests/integration/test_mcp_tools.py
91
+ python tests/integration/test_collection_naming.py
92
+ python tests/integration/test_system_integration.py
85
93
  ```
86
94
 
87
95
  ### Test Results Location
@@ -367,77 +375,113 @@ if [ -n "$VOYAGE_KEY" ]; then
367
375
  fi
368
376
  ```
369
377
 
370
- ### Complete Cloud Embedding Test with Backup/Restore
378
+ ### CRITICAL: Verify Actual Imports (Not Just API Connection!)
371
379
  ```bash
372
- echo "=== Testing Cloud Embeddings (Voyage AI) with Full Backup ==="
373
-
374
- # Step 1: Backup current state
375
- echo "1. Backing up current local environment..."
376
- docker exec claude-reflection-qdrant qdrant-backup create /qdrant/backup/local-backup-$(date +%s) 2>/dev/null || echo "Backup command not available"
377
- cp config/imported-files.json config/imported-files.json.local-backup
378
- echo "Current embedding mode: ${PREFER_LOCAL_EMBEDDINGS:-true}"
379
-
380
- # Step 2: Check prerequisites
381
- if [ -z "$VOYAGE_KEY" ]; then
382
- echo "⚠️ WARNING: VOYAGE_KEY not set"
383
- echo "To test cloud mode, set: export VOYAGE_KEY='your-key'"
384
- echo "Skipping cloud test..."
385
- exit 0
380
+ echo "=== REAL Cloud Embedding Import Test ==="
381
+
382
+ # Step 1: Verify prerequisites
383
+ if [ ! -f .env ] || [ -z "$(grep VOYAGE_KEY .env)" ]; then
384
+ echo "❌ FAIL: No VOYAGE_KEY in .env file"
385
+ exit 1
386
386
  fi
387
387
 
388
- # Step 3: Switch to cloud mode
389
- echo "2. Switching to Voyage AI cloud embeddings..."
388
+ # Extract API key
389
+ export VOYAGE_KEY=$(grep VOYAGE_KEY .env | cut -d= -f2)
390
+ echo "✅ Found Voyage key: ${VOYAGE_KEY:0:10}..."
391
+
392
+ # Step 2: Count existing collections before test
393
+ BEFORE_LOCAL=$(curl -s http://localhost:6333/collections | jq -r '.result.collections[].name' | grep "_local" | wc -l)
394
+ BEFORE_VOYAGE=$(curl -s http://localhost:6333/collections | jq -r '.result.collections[].name' | grep "_voyage" | wc -l)
395
+ echo "Before: $BEFORE_LOCAL local, $BEFORE_VOYAGE voyage collections"
396
+
397
+ # Step 3: Create NEW test conversation for import
398
+ TEST_PROJECT="test-voyage-$(date +%s)"
399
+ TEST_DIR=~/.claude/projects/$TEST_PROJECT
400
+ mkdir -p $TEST_DIR
401
+ TEST_FILE=$TEST_DIR/voyage-test.jsonl
402
+
403
+ cat > $TEST_FILE << 'EOF'
404
+ {"type":"conversation","uuid":"voyage-test-001","name":"Voyage Import Test","messages":[{"role":"human","content":"Testing actual Voyage AI import"},{"role":"assistant","content":[{"type":"text","text":"This should create a real Voyage collection with 1024-dim vectors"}]}],"conversation_id":"voyage-test-001","created_at":"2025-09-08T00:00:00Z"}
405
+ EOF
406
+
407
+ echo "✅ Created test file: $TEST_FILE"
408
+
409
+ # Step 4: Switch to Voyage mode and import
410
+ echo "Switching to Voyage mode..."
390
411
  export PREFER_LOCAL_EMBEDDINGS=false
391
- docker compose --profile watch stop streaming-importer
392
- docker compose --profile watch up -d streaming-importer
412
+ export USE_VOYAGE=true
393
413
 
394
- # Step 4: Create test conversation
395
- TEST_FILE=~/.claude/projects/claude-self-reflect/cloud-test-$(date +%s).jsonl
396
- echo '{"type":"conversation","uuid":"cloud-test-'$(date +%s)'","name":"Cloud Embedding Test","messages":[{"role":"human","content":"Testing Voyage AI cloud embeddings for v2.5.0"},{"role":"assistant","content":[{"type":"text","text":"This tests 1024-dimensional vectors with Voyage AI"}]}]}' > $TEST_FILE
414
+ # Run import directly with modular importer
415
+ cd ~/projects/claude-self-reflect
416
+ source venv/bin/activate
417
+ python -c "
418
+ import os
419
+ os.environ['VOYAGE_KEY'] = '$VOYAGE_KEY'
420
+ os.environ['PREFER_LOCAL_EMBEDDINGS'] = 'false'
421
+ os.environ['USE_VOYAGE'] = 'true'
422
+
423
+ from scripts.importer.main import ImporterContainer
424
+ container = ImporterContainer()
425
+ processor = container.processor()
426
+
427
+ # Process test file
428
+ import json
429
+ with open('$TEST_FILE') as f:
430
+ data = json.load(f)
431
+
432
+ result = processor.process_conversation(
433
+ conversation_data=data,
434
+ file_path='$TEST_FILE',
435
+ project_path='$TEST_PROJECT'
436
+ )
437
+ print(f'Import result: {result}')
438
+ "
397
439
 
398
- # Step 5: Wait for import and verify
399
- echo "3. Waiting for cloud import cycle (70s)..."
400
- sleep 70
440
+ # Step 5: Verify actual Voyage collection created
441
+ echo "Verifying Voyage collection..."
442
+ sleep 5
443
+ AFTER_VOYAGE=$(curl -s http://localhost:6333/collections | jq -r '.result.collections[].name' | grep "_voyage" | wc -l)
401
444
 
402
- # Step 6: Verify cloud collection created
403
- CLOUD_COLS=$(curl -s http://localhost:6333/collections | jq -r '.result.collections[].name' | grep "_voyage")
404
- if [ -n "$CLOUD_COLS" ]; then
405
- echo "✅ PASS: Cloud collections created:"
406
- echo "$CLOUD_COLS"
445
+ if [ "$AFTER_VOYAGE" -gt "$BEFORE_VOYAGE" ]; then
446
+ echo "✅ SUCCESS: New Voyage collection created!"
447
+
448
+ # Get the new collection name
449
+ NEW_COL=$(curl -s http://localhost:6333/collections | jq -r '.result.collections[].name' | grep "_voyage" | tail -1)
450
+
451
+ # Verify dimensions
452
+ DIMS=$(curl -s http://localhost:6333/collections/$NEW_COL | jq '.result.config.params.vectors.size')
453
+ POINTS=$(curl -s http://localhost:6333/collections/$NEW_COL | jq '.result.points_count')
407
454
 
408
- # Check vector dimensions
409
- FIRST_COL=$(echo "$CLOUD_COLS" | head -1)
410
- DIMS=$(curl -s http://localhost:6333/collections/$FIRST_COL | jq '.result.config.params.vectors.size')
411
- if [ "$DIMS" = "1024" ]; then
412
- echo " PASS: Correct dimensions (1024) for Voyage AI"
455
+ echo "Collection: $NEW_COL"
456
+ echo "Dimensions: $DIMS (expected 1024)"
457
+ echo "Points: $POINTS"
458
+
459
+ if [ "$DIMS" = "1024" ] && [ "$POINTS" -gt "0" ]; then
460
+ echo "✅ PASS: Voyage import actually worked!"
413
461
  else
414
- echo "❌ FAIL: Wrong dimensions: $DIMS (expected 1024)"
462
+ echo "❌ FAIL: Wrong dimensions or no points"
415
463
  fi
416
464
  else
417
- echo "❌ FAIL: No cloud collections found"
465
+ echo "❌ FAIL: No new Voyage collection created - import didn't work!"
418
466
  fi
419
467
 
420
- # Step 7: Test MCP with cloud embeddings
421
- echo "4. Testing MCP search with cloud embeddings..."
422
- # Note: MCP must also use PREFER_LOCAL_EMBEDDINGS=false
423
-
424
- # Step 8: Restore local mode
425
- echo "5. Restoring local FastEmbed mode..."
468
+ # Step 6: Restore to local mode
469
+ echo "Restoring local mode..."
426
470
  export PREFER_LOCAL_EMBEDDINGS=true
427
- docker compose --profile watch stop streaming-importer
428
- docker compose --profile watch up -d streaming-importer
471
+ export USE_VOYAGE=false
429
472
 
430
- # Step 9: Verify restoration
431
- sleep 10
432
- LOCAL_COLS=$(curl -s http://localhost:6333/collections | jq -r '.result.collections[].name' | grep "_local" | wc -l)
433
- echo "✅ Restored: Found $LOCAL_COLS local collections"
434
-
435
- # Step 10: Cleanup
436
- rm -f $TEST_FILE
437
- cp config/imported-files.json.local-backup config/imported-files.json
438
- echo "✅ Cloud embedding test complete and restored to local mode"
473
+ # Step 7: Cleanup
474
+ rm -rf $TEST_DIR
475
+ echo "✅ Test complete and cleaned up"
439
476
  ```
440
477
 
478
+ ### Verification Checklist for Real Imports
479
+ 1. **Check Collection Suffix**: `_voyage` for cloud, `_local` for FastEmbed
480
+ 2. **Verify Dimensions**: 1024 for Voyage, 384 for FastEmbed
481
+ 3. **Count Points**: Must have >0 points for successful import
482
+ 4. **Check Logs**: Look for actual embedding API calls
483
+ 5. **Verify State File**: Check imported-files.json for record
484
+
441
485
  ## Success Criteria
442
486
 
443
487
  ### System Functionality
package/README.md CHANGED
@@ -108,7 +108,7 @@ See your conversation indexing progress directly in your statusline:
108
108
  ### Active Indexing (50% with backlog)
109
109
  ![Statusline showing 50% indexed with 7h backlog](docs/images/statusbar-2.png)
110
110
 
111
- Works with [Claude Code Statusline](https://github.com/sirmalloc/ccstatusline) - shows progress bars, percentages, and indexing lag in real-time!
111
+ Works with [Claude Code Statusline](https://github.com/sirmalloc/ccstatusline) - shows progress bars, percentages, and indexing lag in real-time! The statusline also displays MCP connection status (✓ Connected) and collection counts (28/29 indexed).
112
112
 
113
113
  ## Key Features
114
114
 
@@ -2,11 +2,13 @@
2
2
 
3
3
  // This is the new Docker-based setup wizard
4
4
  // It runs everything in Docker to avoid Python environment issues
5
- import { fileURLToPath } from 'url';
5
+ import { fileURLToPath, pathToFileURL } from 'url';
6
6
  import { dirname, join } from 'path';
7
7
 
8
8
  const __filename = fileURLToPath(import.meta.url);
9
9
  const __dirname = dirname(__filename);
10
10
 
11
11
  // Simply forward to the Docker-based wizard
12
- import(join(__dirname, 'setup-wizard-docker.js'));
12
+ // Fix for Windows: Use pathToFileURL for dynamic imports (Issue #51)
13
+ const wizardPath = join(__dirname, 'setup-wizard-docker.js');
14
+ import(pathToFileURL(wizardPath).href);
@@ -15,6 +15,7 @@ dependencies = [
15
15
  "pydantic>=2.11.7,<3.0.0", # Updated for fastmcp 2.10.6 compatibility
16
16
  "pydantic-settings>=2.0.0,<3.0.0",
17
17
  "fastembed>=0.4.0,<1.0.0",
18
+ "dependency-injector>=4.0.0,<5.0.0",
18
19
  ]
19
20
 
20
21
  [project.scripts]
@@ -143,6 +143,90 @@ mcp = FastMCP(
143
143
  # Create Qdrant client
144
144
  qdrant_client = AsyncQdrantClient(url=QDRANT_URL)
145
145
 
146
+ # Add MCP Resources for system status
147
+ @mcp.resource("status://import-stats")
148
+ async def get_import_stats():
149
+ """Current import statistics and progress."""
150
+ await update_indexing_status()
151
+
152
+ return json.dumps({
153
+ "indexed_conversations": indexing_status["indexed_conversations"],
154
+ "total_conversations": indexing_status["total_conversations"],
155
+ "percentage": indexing_status["percentage"],
156
+ "backlog_count": indexing_status["backlog_count"],
157
+ "last_check": datetime.fromtimestamp(indexing_status["last_check"]).isoformat() if indexing_status["last_check"] else None
158
+ }, indent=2)
159
+
160
+ @mcp.resource("status://collection-list")
161
+ async def get_collection_list():
162
+ """List of all Qdrant collections with metadata."""
163
+ try:
164
+ collections = await qdrant_client.get_collections()
165
+ collection_data = []
166
+
167
+ for collection in collections.collections:
168
+ # Get collection info
169
+ info = await qdrant_client.get_collection(collection_name=collection.name)
170
+ collection_data.append({
171
+ "name": collection.name,
172
+ "points_count": info.points_count,
173
+ "indexed_vectors_count": info.indexed_vectors_count,
174
+ "status": info.status,
175
+ "config": {
176
+ "vector_size": info.config.params.vectors.size if hasattr(info.config.params.vectors, 'size') else 384,
177
+ "distance": str(info.config.params.vectors.distance) if hasattr(info.config.params.vectors, 'distance') else "Cosine"
178
+ }
179
+ })
180
+
181
+ return json.dumps({
182
+ "total_collections": len(collection_data),
183
+ "collections": collection_data
184
+ }, indent=2)
185
+ except Exception as e:
186
+ return json.dumps({"error": str(e)}, indent=2)
187
+
188
+ @mcp.resource("status://system-health")
189
+ async def get_system_health():
190
+ """System health and configuration information."""
191
+ try:
192
+ # Check Qdrant connectivity
193
+ qdrant_info = await qdrant_client.get_collections()
194
+ qdrant_healthy = True
195
+ qdrant_version = "Connected"
196
+ except:
197
+ qdrant_healthy = False
198
+ qdrant_version = "Disconnected"
199
+
200
+ # Check embedding configuration
201
+ embedding_info = {}
202
+ if embedding_manager:
203
+ embedding_info = {
204
+ "model_type": embedding_manager.model_type,
205
+ "model_name": embedding_manager.model_name,
206
+ "dimension": embedding_manager.dimension
207
+ }
208
+
209
+ return json.dumps({
210
+ "timestamp": datetime.now(timezone.utc).isoformat(),
211
+ "qdrant": {
212
+ "healthy": qdrant_healthy,
213
+ "url": QDRANT_URL,
214
+ "version": qdrant_version
215
+ },
216
+ "embeddings": embedding_info,
217
+ "configuration": {
218
+ "memory_decay_enabled": ENABLE_MEMORY_DECAY,
219
+ "decay_weight": DECAY_WEIGHT,
220
+ "decay_scale_days": DECAY_SCALE_DAYS,
221
+ "prefer_local_embeddings": PREFER_LOCAL_EMBEDDINGS
222
+ },
223
+ "indexing_status": {
224
+ "indexed": indexing_status["indexed_conversations"],
225
+ "total": indexing_status["total_conversations"],
226
+ "percentage": indexing_status["percentage"]
227
+ }
228
+ }, indent=2)
229
+
146
230
  # Track indexing status (updated periodically)
147
231
  indexing_status = {
148
232
  "last_check": 0,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-self-reflect",
3
- "version": "3.0.0",
3
+ "version": "3.0.2",
4
4
  "description": "Give Claude perfect memory of all your conversations - Installation wizard for Python MCP server",
5
5
  "keywords": [
6
6
  "claude",
@@ -41,6 +41,7 @@
41
41
  "mcp-server/run-mcp-clean.sh",
42
42
  "mcp-server/run-mcp-docker.sh",
43
43
  "scripts/import-*.py",
44
+ "scripts/importer/**/*.py",
44
45
  "scripts/delta-metadata-update-safe.py",
45
46
  "scripts/force-metadata-recovery.py",
46
47
  ".claude/agents/*.md",