claude-self-reflect 2.4.8 → 2.4.9
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.
|
@@ -770,4 +770,48 @@ After importing:
|
|
|
770
770
|
4. **Restart MCP After Import**: Ensures new collections are recognized
|
|
771
771
|
5. **Verify with Search**: Test that new content is searchable
|
|
772
772
|
|
|
773
|
+
## Quick Import for Current Project (NEW in v2.4.8)
|
|
774
|
+
|
|
775
|
+
For rapid updates when working on a single project, use the optimized quick import:
|
|
776
|
+
|
|
777
|
+
### Quick Import Script
|
|
778
|
+
```bash
|
|
779
|
+
# Import only recent conversations (last 2 hours by default)
|
|
780
|
+
cd /path/to/your/project
|
|
781
|
+
source ~/claude-self-reflect/venv/bin/activate
|
|
782
|
+
python ~/claude-self-reflect/scripts/import-latest.py
|
|
783
|
+
|
|
784
|
+
# Customize time window
|
|
785
|
+
export IMPORT_HOURS_BACK=4 # Import last 4 hours
|
|
786
|
+
python ~/claude-self-reflect/scripts/import-latest.py
|
|
787
|
+
```
|
|
788
|
+
|
|
789
|
+
### PreCompact Hook Integration
|
|
790
|
+
To automatically update conversations before compacting:
|
|
791
|
+
|
|
792
|
+
```bash
|
|
793
|
+
# Install the hook (one-time setup)
|
|
794
|
+
cp ~/claude-self-reflect/scripts/precompact-hook.sh ~/.claude/hooks/precompact
|
|
795
|
+
# Or source it from your existing precompact hook:
|
|
796
|
+
echo "source ~/claude-self-reflect/scripts/precompact-hook.sh" >> ~/.claude/hooks/precompact
|
|
797
|
+
```
|
|
798
|
+
|
|
799
|
+
### Performance Expectations
|
|
800
|
+
- **Full import**: 2-7 minutes (all projects, all history)
|
|
801
|
+
- **Quick import**: 30-60 seconds (current project, recent files only)
|
|
802
|
+
- **Target**: <10 seconds (future optimization)
|
|
803
|
+
|
|
804
|
+
### When to Use Quick Import
|
|
805
|
+
- Before starting a new Claude session
|
|
806
|
+
- After significant conversation progress
|
|
807
|
+
- Via PreCompact hook (automatic)
|
|
808
|
+
- When recent conversations aren't in search results
|
|
809
|
+
|
|
810
|
+
### Troubleshooting Quick Import
|
|
811
|
+
If quick import fails:
|
|
812
|
+
1. Ensure you're in a project directory with Claude logs
|
|
813
|
+
2. Check virtual environment is activated
|
|
814
|
+
3. Verify project has a collection: `python scripts/check-collections.py`
|
|
815
|
+
4. For first-time projects, run full import once
|
|
816
|
+
|
|
773
817
|
Remember: You're not just a search tool - you're a memory augmentation system that helps maintain continuity, prevent repeated work, and leverage collective knowledge across all Claude conversations.
|
package/package.json
CHANGED
|
@@ -37,6 +37,60 @@ VOYAGE_API_KEY = os.getenv("VOYAGE_KEY")
|
|
|
37
37
|
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
|
|
38
38
|
logger = logging.getLogger(__name__)
|
|
39
39
|
|
|
40
|
+
# State management functions
|
|
41
|
+
def load_state():
|
|
42
|
+
"""Load the import state from file."""
|
|
43
|
+
if os.path.exists(STATE_FILE):
|
|
44
|
+
try:
|
|
45
|
+
with open(STATE_FILE, 'r') as f:
|
|
46
|
+
state = json.load(f)
|
|
47
|
+
# Ensure the expected structure exists
|
|
48
|
+
if "imported_files" not in state:
|
|
49
|
+
state["imported_files"] = {}
|
|
50
|
+
return state
|
|
51
|
+
except Exception as e:
|
|
52
|
+
logger.warning(f"Failed to load state file: {e}")
|
|
53
|
+
return {"imported_files": {}}
|
|
54
|
+
|
|
55
|
+
def save_state(state):
|
|
56
|
+
"""Save the import state to file."""
|
|
57
|
+
try:
|
|
58
|
+
# Ensure directory exists
|
|
59
|
+
os.makedirs(os.path.dirname(STATE_FILE), exist_ok=True)
|
|
60
|
+
# Write atomically by using a temp file
|
|
61
|
+
temp_file = STATE_FILE + ".tmp"
|
|
62
|
+
with open(temp_file, 'w') as f:
|
|
63
|
+
json.dump(state, f, indent=2)
|
|
64
|
+
os.replace(temp_file, STATE_FILE)
|
|
65
|
+
logger.debug(f"Saved state with {len(state['imported_files'])} files")
|
|
66
|
+
except Exception as e:
|
|
67
|
+
logger.error(f"Failed to save state file: {e}")
|
|
68
|
+
|
|
69
|
+
def should_import_file(file_path, state):
|
|
70
|
+
"""Check if a file should be imported based on modification time."""
|
|
71
|
+
str_path = str(file_path)
|
|
72
|
+
file_mtime = os.path.getmtime(file_path)
|
|
73
|
+
|
|
74
|
+
if str_path in state["imported_files"]:
|
|
75
|
+
last_imported = state["imported_files"][str_path].get("last_imported", 0)
|
|
76
|
+
last_modified = state["imported_files"][str_path].get("last_modified", 0)
|
|
77
|
+
|
|
78
|
+
# Skip if file hasn't been modified since last import
|
|
79
|
+
if file_mtime <= last_modified and last_imported > 0:
|
|
80
|
+
logger.info(f"Skipping unchanged file: {file_path.name}")
|
|
81
|
+
return False
|
|
82
|
+
|
|
83
|
+
return True
|
|
84
|
+
|
|
85
|
+
def update_file_state(file_path, state, chunks_imported):
|
|
86
|
+
"""Update the state for an imported file."""
|
|
87
|
+
str_path = str(file_path)
|
|
88
|
+
state["imported_files"][str_path] = {
|
|
89
|
+
"last_modified": os.path.getmtime(file_path),
|
|
90
|
+
"last_imported": datetime.now().timestamp(),
|
|
91
|
+
"chunks_imported": chunks_imported
|
|
92
|
+
}
|
|
93
|
+
|
|
40
94
|
# Initialize embedding provider
|
|
41
95
|
embedding_provider = None
|
|
42
96
|
embedding_dimension = None
|
|
@@ -120,7 +174,7 @@ def chunk_conversation(messages: List[Dict[str, Any]], chunk_size: int = 10) ->
|
|
|
120
174
|
|
|
121
175
|
return chunks
|
|
122
176
|
|
|
123
|
-
def import_project(project_path: Path, collection_name: str) -> int:
|
|
177
|
+
def import_project(project_path: Path, collection_name: str, state: dict) -> int:
|
|
124
178
|
"""Import all conversations from a project."""
|
|
125
179
|
jsonl_files = list(project_path.glob("*.jsonl"))
|
|
126
180
|
|
|
@@ -143,6 +197,10 @@ def import_project(project_path: Path, collection_name: str) -> int:
|
|
|
143
197
|
total_chunks = 0
|
|
144
198
|
|
|
145
199
|
for jsonl_file in jsonl_files:
|
|
200
|
+
# Check if file should be imported
|
|
201
|
+
if not should_import_file(jsonl_file, state):
|
|
202
|
+
continue
|
|
203
|
+
|
|
146
204
|
logger.info(f"Processing file: {jsonl_file.name}")
|
|
147
205
|
try:
|
|
148
206
|
# Read JSONL file and extract messages
|
|
@@ -241,7 +299,11 @@ def import_project(project_path: Path, collection_name: str) -> int:
|
|
|
241
299
|
|
|
242
300
|
total_chunks += len(points)
|
|
243
301
|
|
|
244
|
-
|
|
302
|
+
file_chunks = len(chunks)
|
|
303
|
+
logger.info(f"Imported {file_chunks} chunks from {jsonl_file.name}")
|
|
304
|
+
|
|
305
|
+
# Update state for this file
|
|
306
|
+
update_file_state(jsonl_file, state, file_chunks)
|
|
245
307
|
|
|
246
308
|
except Exception as e:
|
|
247
309
|
logger.error(f"Failed to import {jsonl_file}: {e}")
|
|
@@ -258,6 +320,10 @@ def main():
|
|
|
258
320
|
logger.error(f"Logs directory not found: {LOGS_DIR}")
|
|
259
321
|
return
|
|
260
322
|
|
|
323
|
+
# Load existing state
|
|
324
|
+
state = load_state()
|
|
325
|
+
logger.info(f"Loaded state with {len(state['imported_files'])} previously imported files")
|
|
326
|
+
|
|
261
327
|
# Find all project directories
|
|
262
328
|
project_dirs = [d for d in logs_path.iterdir() if d.is_dir()]
|
|
263
329
|
|
|
@@ -274,9 +340,15 @@ def main():
|
|
|
274
340
|
collection_name = f"conv_{hashlib.md5(project_dir.name.encode()).hexdigest()[:8]}{collection_suffix}"
|
|
275
341
|
|
|
276
342
|
logger.info(f"Importing project: {project_dir.name} -> {collection_name}")
|
|
277
|
-
chunks = import_project(project_dir, collection_name)
|
|
343
|
+
chunks = import_project(project_dir, collection_name, state)
|
|
278
344
|
total_imported += chunks
|
|
279
345
|
logger.info(f"Imported {chunks} chunks from {project_dir.name}")
|
|
346
|
+
|
|
347
|
+
# Save state after each project to avoid losing progress
|
|
348
|
+
save_state(state)
|
|
349
|
+
|
|
350
|
+
# Final save (redundant but ensures state is saved)
|
|
351
|
+
save_state(state)
|
|
280
352
|
|
|
281
353
|
logger.info(f"Import complete! Total chunks imported: {total_imported}")
|
|
282
354
|
|