claude-self-reflect 5.0.7 → 6.0.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.
Files changed (68) hide show
  1. package/.claude/agents/open-source-maintainer.md +1 -1
  2. package/.claude/agents/reflection-specialist.md +2 -2
  3. package/Dockerfile.async-importer +6 -4
  4. package/Dockerfile.importer +6 -6
  5. package/Dockerfile.safe-watcher +8 -8
  6. package/Dockerfile.streaming-importer +8 -1
  7. package/Dockerfile.watcher +8 -16
  8. package/docker-compose.yaml +12 -6
  9. package/installer/.claude/agents/README.md +138 -0
  10. package/package.json +5 -26
  11. package/src/__init__.py +0 -0
  12. package/src/cli/__init__.py +0 -0
  13. package/src/runtime/__init__.py +0 -0
  14. package/src/runtime/import-latest.py +124 -0
  15. package/{scripts → src/runtime}/precompact-hook.sh +1 -1
  16. package/src/runtime/streaming-importer.py +995 -0
  17. package/{scripts → src/runtime}/watcher-loop.sh +1 -1
  18. package/.claude/agents/claude-self-reflect-test.md +0 -1274
  19. package/.claude/agents/reflect-tester.md +0 -300
  20. package/scripts/add-timestamp-indexes.py +0 -134
  21. package/scripts/ast_grep_final_analyzer.py +0 -338
  22. package/scripts/ast_grep_unified_registry.py +0 -710
  23. package/scripts/check-collections.py +0 -29
  24. package/scripts/debug-august-parsing.py +0 -80
  25. package/scripts/debug-import-single.py +0 -91
  26. package/scripts/debug-project-resolver.py +0 -82
  27. package/scripts/debug-temporal-tools.py +0 -135
  28. package/scripts/import-conversations-enhanced.py +0 -672
  29. package/scripts/migrate-to-unified-state.py +0 -426
  30. package/scripts/session_quality_tracker.py +0 -671
  31. package/scripts/update_patterns.py +0 -334
  32. /package/{scripts → src}/importer/__init__.py +0 -0
  33. /package/{scripts → src}/importer/__main__.py +0 -0
  34. /package/{scripts → src}/importer/core/__init__.py +0 -0
  35. /package/{scripts → src}/importer/core/config.py +0 -0
  36. /package/{scripts → src}/importer/core/exceptions.py +0 -0
  37. /package/{scripts → src}/importer/core/models.py +0 -0
  38. /package/{scripts → src}/importer/embeddings/__init__.py +0 -0
  39. /package/{scripts → src}/importer/embeddings/base.py +0 -0
  40. /package/{scripts → src}/importer/embeddings/fastembed_provider.py +0 -0
  41. /package/{scripts → src}/importer/embeddings/validator.py +0 -0
  42. /package/{scripts → src}/importer/embeddings/voyage_provider.py +0 -0
  43. /package/{scripts → src}/importer/main.py +0 -0
  44. /package/{scripts → src}/importer/processors/__init__.py +0 -0
  45. /package/{scripts → src}/importer/processors/ast_extractor.py +0 -0
  46. /package/{scripts → src}/importer/processors/chunker.py +0 -0
  47. /package/{scripts → src}/importer/processors/concept_extractor.py +0 -0
  48. /package/{scripts → src}/importer/processors/conversation_parser.py +0 -0
  49. /package/{scripts → src}/importer/processors/tool_extractor.py +0 -0
  50. /package/{scripts → src}/importer/state/__init__.py +0 -0
  51. /package/{scripts → src}/importer/state/state_manager.py +0 -0
  52. /package/{scripts → src}/importer/storage/__init__.py +0 -0
  53. /package/{scripts → src}/importer/storage/qdrant_storage.py +0 -0
  54. /package/{scripts → src}/importer/utils/__init__.py +0 -0
  55. /package/{scripts → src}/importer/utils/logger.py +0 -0
  56. /package/{scripts → src}/importer/utils/project_normalizer.py +0 -0
  57. /package/{scripts → src/runtime}/delta-metadata-update-safe.py +0 -0
  58. /package/{scripts → src/runtime}/delta-metadata-update.py +0 -0
  59. /package/{scripts → src/runtime}/doctor.py +0 -0
  60. /package/{scripts → src/runtime}/embedding_service.py +0 -0
  61. /package/{scripts → src/runtime}/force-metadata-recovery.py +0 -0
  62. /package/{scripts → src/runtime}/import-conversations-unified.py +0 -0
  63. /package/{scripts → src/runtime}/import_strategies.py +0 -0
  64. /package/{scripts → src/runtime}/message_processors.py +0 -0
  65. /package/{scripts → src/runtime}/metadata_extractor.py +0 -0
  66. /package/{scripts → src/runtime}/streaming-watcher.py +0 -0
  67. /package/{scripts → src/runtime}/unified_state_manager.py +0 -0
  68. /package/{scripts → src/runtime}/utils.py +0 -0
@@ -1,29 +0,0 @@
1
- #!/usr/bin/env python3
2
- """Check Qdrant collections."""
3
-
4
- import os
5
- from qdrant_client import QdrantClient
6
-
7
- # Configuration
8
- QDRANT_URL = os.getenv("QDRANT_URL", "http://localhost:6333")
9
-
10
- def main():
11
- """List all collections."""
12
- client = QdrantClient(url=QDRANT_URL)
13
-
14
- # Get all collections
15
- collections = client.get_collections()
16
-
17
- print("Qdrant Collections:")
18
- print("-" * 60)
19
-
20
- voyage_collections = []
21
- for collection in collections.collections:
22
- print(f"- {collection.name}")
23
- if collection.name.endswith("_voyage"):
24
- voyage_collections.append(collection.name)
25
-
26
- print(f"\nFound {len(voyage_collections)} Voyage collections")
27
-
28
- if __name__ == "__main__":
29
- main()
@@ -1,80 +0,0 @@
1
- #!/usr/bin/env python3
2
- """Debug why August files aren't parsing properly."""
3
-
4
- import json
5
- import sys
6
-
7
- def parse_jsonl_file(file_path):
8
- """Parse JSONL file and extract messages."""
9
- messages = []
10
-
11
- with open(file_path, 'r', encoding='utf-8') as f:
12
- for line_num, line in enumerate(f, 1):
13
- line = line.strip()
14
- if not line:
15
- continue
16
-
17
- try:
18
- data = json.loads(line)
19
-
20
- # Skip summary messages
21
- if data.get('type') == 'summary':
22
- print(f"Line {line_num}: Skipping summary")
23
- continue
24
-
25
- # Handle messages with type user/assistant at root level
26
- if data.get('type') in ['user', 'assistant']:
27
- if 'message' in data and data['message']:
28
- msg = data['message']
29
- if msg.get('role') and msg.get('content'):
30
- content = msg['content']
31
- if isinstance(content, list):
32
- text_parts = []
33
- for item in content:
34
- if isinstance(item, dict) and item.get('type') == 'text':
35
- text_parts.append(item.get('text', ''))
36
- elif isinstance(item, str):
37
- text_parts.append(item)
38
- content = '\n'.join(text_parts)
39
-
40
- if content:
41
- messages.append({
42
- 'role': msg['role'],
43
- 'content': content[:200] + '...' if len(content) > 200 else content,
44
- 'line': line_num
45
- })
46
- print(f"Line {line_num}: Extracted {msg['role']} message ({len(content)} chars)")
47
- else:
48
- print(f"Line {line_num}: Empty content for {msg['role']}")
49
- else:
50
- print(f"Line {line_num}: Missing role or content in message field")
51
- else:
52
- print(f"Line {line_num}: No message field for type={data.get('type')}")
53
- else:
54
- print(f"Line {line_num}: Unknown type={data.get('type')}")
55
-
56
- except Exception as e:
57
- print(f"Line {line_num}: Parse error - {e}")
58
-
59
- return messages
60
-
61
- if __name__ == "__main__":
62
- # Use home directory path
63
- from pathlib import Path
64
- home = Path.home()
65
- file_path = home / ".claude" / "projects" / f"-{home}-projects-claude-self-reflect" / "7b3354ed-d6d2-4eab-b328-1fced4bb63bb.jsonl"
66
- file_path = str(file_path)
67
-
68
- print(f"Parsing: {file_path}")
69
- print("=" * 60)
70
-
71
- messages = parse_jsonl_file(file_path)
72
-
73
- print("\n" + "=" * 60)
74
- print(f"Total messages extracted: {len(messages)}")
75
-
76
- if messages:
77
- print("\nFirst 5 messages:")
78
- for i, msg in enumerate(messages[:5]):
79
- print(f"\n{i+1}. Line {msg['line']}: {msg['role']}")
80
- print(f" Content: {msg['content'][:100]}...")
@@ -1,91 +0,0 @@
1
- #!/usr/bin/env python3
2
- """
3
- Debug import of a single file with summary messages
4
- """
5
-
6
- import json
7
- from pathlib import Path
8
-
9
- # Target file
10
- test_file = Path.home() / '.claude/projects/-Users-ramakrishnanannaswamy-projects-claude-self-reflect/c072a61e-aebb-4c85-960b-c5ffeafa7115.jsonl'
11
-
12
- print(f"Analyzing: {test_file.name}\n")
13
-
14
- # Read and analyze the file
15
- all_messages = []
16
- summary_count = 0
17
- user_count = 0
18
- assistant_count = 0
19
- other_count = 0
20
-
21
- with open(test_file, 'r') as f:
22
- for i, line in enumerate(f, 1):
23
- if line.strip():
24
- try:
25
- data = json.loads(line)
26
- msg_type = data.get('type', 'unknown')
27
-
28
- print(f"Line {i}: type={msg_type}", end="")
29
-
30
- # Check what would be extracted
31
- if msg_type == 'summary':
32
- summary_count += 1
33
- print(f" -> SKIPPED (summary)")
34
- continue
35
-
36
- # Check for messages with type user/assistant
37
- if msg_type in ['user', 'assistant']:
38
- if 'message' in data and data['message']:
39
- msg = data['message']
40
- if msg.get('role') and msg.get('content'):
41
- all_messages.append(msg)
42
- if msg_type == 'user':
43
- user_count += 1
44
- else:
45
- assistant_count += 1
46
-
47
- # Extract a preview of content
48
- content = msg.get('content', '')
49
- if isinstance(content, list) and len(content) > 0:
50
- first_item = content[0]
51
- if isinstance(first_item, dict):
52
- preview = str(first_item.get('content', first_item.get('text', '')))[:50]
53
- else:
54
- preview = str(first_item)[:50]
55
- else:
56
- preview = str(content)[:50]
57
-
58
- print(f" -> EXTRACTED (role={msg['role']}, preview: {preview}...)")
59
- else:
60
- print(f" -> NO role/content in message")
61
- else:
62
- print(f" -> NO message field")
63
- else:
64
- other_count += 1
65
- print(f" -> OTHER TYPE")
66
-
67
- except json.JSONDecodeError as e:
68
- print(f"Line {i}: INVALID JSON - {e}")
69
-
70
- print(f"\n=== SUMMARY ===")
71
- print(f"Total lines: {i}")
72
- print(f"Summaries (skipped): {summary_count}")
73
- print(f"User messages: {user_count}")
74
- print(f"Assistant messages: {assistant_count}")
75
- print(f"Other types: {other_count}")
76
- print(f"Total extracted messages: {len(all_messages)}")
77
-
78
- # Check for Memento content
79
- memento_found = False
80
- for msg in all_messages:
81
- content = str(msg.get('content', ''))
82
- if 'memento' in content.lower():
83
- memento_found = True
84
- break
85
-
86
- print(f"\nMemento content found in messages: {memento_found}")
87
-
88
- if len(all_messages) > 0:
89
- print(f"\n✅ File SHOULD be importable with {len(all_messages)} messages")
90
- else:
91
- print(f"\n❌ File would result in ZERO messages imported")
@@ -1,82 +0,0 @@
1
- #!/usr/bin/env python3
2
- """Test ProjectResolver to see if it's finding collections correctly."""
3
-
4
- import sys
5
- from pathlib import Path
6
- sys.path.insert(0, str(Path(__file__).parent.parent / 'mcp-server' / 'src'))
7
-
8
- from qdrant_client import QdrantClient
9
- from project_resolver import ProjectResolver
10
-
11
- # Connect to Qdrant
12
- client = QdrantClient(url="http://localhost:6333")
13
-
14
- # Create resolver
15
- resolver = ProjectResolver(client)
16
-
17
- # Test projects
18
- test_projects = [
19
- "claude-self-reflect",
20
- "memento",
21
- "cc-enhance",
22
- "all"
23
- ]
24
-
25
- print("=== Testing ProjectResolver ===\n")
26
-
27
- for project in test_projects:
28
- print(f"Project: '{project}'")
29
- collections = resolver.find_collections_for_project(project)
30
- print(f" Found {len(collections)} collections")
31
-
32
- if collections:
33
- # Show first 3 collections
34
- for coll in collections[:3]:
35
- try:
36
- info = client.get_collection(coll)
37
- suffix = "_local" if coll.endswith("_local") else "_voyage"
38
- print(f" - {coll}: {info.points_count} points ({suffix})")
39
- except:
40
- print(f" - {coll}: <error getting info>")
41
- else:
42
- print(" - No collections found!")
43
- print()
44
-
45
- # Also test the normalization directly
46
- print("\n=== Testing Direct Normalization ===")
47
- from shared.normalization import normalize_project_name
48
- import hashlib
49
-
50
- test_paths = [
51
- str(Path.home() / "projects" / "claude-self-reflect"),
52
- str(Path.home() / "projects" / "memento"),
53
- str(Path.home() / "projects" / "cc-enhance")
54
- ]
55
-
56
- for path in test_paths:
57
- normalized = normalize_project_name(path)
58
- name_hash = hashlib.md5(normalized.encode()).hexdigest()[:8]
59
- collection_local = f"conv_{name_hash}_local"
60
- collection_voyage = f"conv_{name_hash}_voyage"
61
-
62
- print(f"Path: {path}")
63
- print(f" Normalized: {normalized}")
64
- print(f" Hash: {name_hash}")
65
- print(f" Expected collections:")
66
- print(f" - {collection_local}")
67
- print(f" - {collection_voyage}")
68
-
69
- # Check if these exist
70
- all_collections = [c.name for c in client.get_collections().collections]
71
- if collection_local in all_collections:
72
- info = client.get_collection(collection_local)
73
- print(f" ✓ {collection_local} exists with {info.points_count} points")
74
- else:
75
- print(f" ✗ {collection_local} not found")
76
-
77
- if collection_voyage in all_collections:
78
- info = client.get_collection(collection_voyage)
79
- print(f" ✓ {collection_voyage} exists with {info.points_count} points")
80
- else:
81
- print(f" ✗ {collection_voyage} not found")
82
- print()
@@ -1,135 +0,0 @@
1
- #!/usr/bin/env python3
2
- """
3
- Debug script for testing temporal tools in Claude Self Reflect.
4
- This script directly tests the temporal tools that should be available via MCP.
5
- """
6
-
7
- import os
8
- import sys
9
- import asyncio
10
- import json
11
- import traceback
12
- from pathlib import Path
13
-
14
- # Add the mcp-server source to Python path
15
- sys.path.append(str(Path(__file__).parent.parent / "mcp-server" / "src"))
16
-
17
- os.environ["QDRANT_URL"] = "http://localhost:6333"
18
-
19
- async def test_temporal_tools():
20
- """Test all temporal tools."""
21
- print("=== TEMPORAL TOOLS DEBUG SCRIPT ===")
22
-
23
- try:
24
- # Import required modules
25
- from server import (
26
- get_recent_work, search_by_recency, get_timeline,
27
- get_all_collections, QDRANT_URL
28
- )
29
- from fastmcp import Context
30
-
31
- print(f"✅ Successfully imported temporal tools")
32
- print(f"✅ Qdrant URL: {QDRANT_URL}")
33
-
34
- # Check if Qdrant is available
35
- collections = await get_all_collections()
36
- print(f"✅ Found {len(collections)} collections: {collections[:5]}...")
37
-
38
- # Create a mock context for testing
39
- class MockContext(Context):
40
- def __init__(self):
41
- pass
42
- async def debug(self, message):
43
- print(f"DEBUG: {message}")
44
- async def error(self, message):
45
- print(f"ERROR: {message}")
46
-
47
- ctx = MockContext()
48
-
49
- # Test 1: get_recent_work with default parameters
50
- print("\n--- Test 1: get_recent_work (default) ---")
51
- try:
52
- result = await get_recent_work(ctx)
53
- print(f"✅ get_recent_work succeeded")
54
- print(f"Result length: {len(result) if result else 0} characters")
55
- if result and len(result) < 500:
56
- print(f"Result: {result}")
57
- except Exception as e:
58
- print(f"❌ get_recent_work failed: {e}")
59
- traceback.print_exc()
60
-
61
- # Test 2: get_recent_work with project='all'
62
- print("\n--- Test 2: get_recent_work (project=all) ---")
63
- try:
64
- result = await get_recent_work(ctx, project="all", limit=5)
65
- print(f"✅ get_recent_work (project=all) succeeded")
66
- print(f"Result length: {len(result) if result else 0} characters")
67
- except Exception as e:
68
- print(f"❌ get_recent_work (project=all) failed: {e}")
69
- traceback.print_exc()
70
-
71
- # Test 3: get_recent_work with different group_by options
72
- for group_by in ["conversation", "day", "session"]:
73
- print(f"\n--- Test 3.{group_by}: get_recent_work (group_by={group_by}) ---")
74
- try:
75
- result = await get_recent_work(ctx, limit=3, group_by=group_by)
76
- print(f"✅ get_recent_work (group_by={group_by}) succeeded")
77
- print(f"Result length: {len(result) if result else 0} characters")
78
- except Exception as e:
79
- print(f"❌ get_recent_work (group_by={group_by}) failed: {e}")
80
- traceback.print_exc()
81
-
82
- # Test 4: search_by_recency with time_range
83
- print("\n--- Test 4: search_by_recency (time_range) ---")
84
- try:
85
- result = await search_by_recency(
86
- ctx,
87
- query="testing debugging",
88
- time_range="last week",
89
- limit=5
90
- )
91
- print(f"✅ search_by_recency (time_range) succeeded")
92
- print(f"Result length: {len(result) if result else 0} characters")
93
- except Exception as e:
94
- print(f"❌ search_by_recency (time_range) failed: {e}")
95
- traceback.print_exc()
96
-
97
- # Test 5: search_by_recency with since/until
98
- print("\n--- Test 5: search_by_recency (since/until) ---")
99
- try:
100
- result = await search_by_recency(
101
- ctx,
102
- query="python script",
103
- since="yesterday",
104
- limit=3
105
- )
106
- print(f"✅ search_by_recency (since/until) succeeded")
107
- print(f"Result length: {len(result) if result else 0} characters")
108
- except Exception as e:
109
- print(f"❌ search_by_recency (since/until) failed: {e}")
110
- traceback.print_exc()
111
-
112
- # Test 6: get_timeline with different granularities
113
- for granularity in ["day", "week"]:
114
- print(f"\n--- Test 6.{granularity}: get_timeline (granularity={granularity}) ---")
115
- try:
116
- result = await get_timeline(
117
- ctx,
118
- time_range="last week",
119
- granularity=granularity,
120
- include_stats=True
121
- )
122
- print(f"✅ get_timeline (granularity={granularity}) succeeded")
123
- print(f"Result length: {len(result) if result else 0} characters")
124
- except Exception as e:
125
- print(f"❌ get_timeline (granularity={granularity}) failed: {e}")
126
- traceback.print_exc()
127
-
128
- print("\n=== TEMPORAL TOOLS TEST COMPLETE ===")
129
-
130
- except Exception as e:
131
- print(f"❌ Critical error during setup: {e}")
132
- traceback.print_exc()
133
-
134
- if __name__ == "__main__":
135
- asyncio.run(test_temporal_tools())