chore: remove all better-sqlite3 references from codebase (#357)
* fix: export/import scripts now use API instead of direct DB access Export script fix: - Add format=json parameter to SearchManager for raw data output - Add getSdkSessionsBySessionIds method to SessionStore - Add POST /api/sdk-sessions/batch endpoint to DataRoutes - Refactor export-memories.ts to use HTTP API Import script fix: - Add import methods to SessionStore with duplicate detection - Add POST /api/import endpoint to DataRoutes - Refactor import-memories.ts to use HTTP API 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix: update analyze-transformations-smart.js to use bun:sqlite Replace better-sqlite3 import with bun:sqlite to align with v7.1.0 migration. * chore: remove all better-sqlite3 references from codebase - Updated scripts/analyze-transformations-smart.js to use bun:sqlite - Merged PR #332: Refactored import/export scripts to use worker API instead of direct DB access - Updated PM2-to-Bun migration documentation All better-sqlite3 references have been removed from source code. Documentation references remain as appropriate historical context. * build: update plugin artifacts with merged changes Include built artifacts from PR #332 merge and analyze-transformations-smart.js update. --------- Co-authored-by: lee <loyalpartner@163.com> Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -3,6 +3,14 @@ title: "PM2 to Bun Migration"
|
|||||||
description: "Complete technical documentation for the process management and database driver migration in v7.1.0"
|
description: "Complete technical documentation for the process management and database driver migration in v7.1.0"
|
||||||
---
|
---
|
||||||
|
|
||||||
|
<Note>
|
||||||
|
**Historical Migration Documentation**
|
||||||
|
|
||||||
|
This document describes the PM2 to Bun migration that occurred in v7.1.0 (December 2025). If you're installing claude-mem for the first time, this migration has already been completed and you can use the current Bun-based system documented in the main guides.
|
||||||
|
|
||||||
|
This documentation is preserved for users upgrading from versions older than v7.1.0.
|
||||||
|
</Note>
|
||||||
|
|
||||||
# PM2 to Bun Migration: Complete Technical Documentation
|
# PM2 to Bun Migration: Complete Technical Documentation
|
||||||
|
|
||||||
**Version**: 7.1.0
|
**Version**: 7.1.0
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Binary file not shown.
@@ -282,7 +282,7 @@ No results found for "{query}". Try:
|
|||||||
The search service isn't available. Check if the worker is running:
|
The search service isn't available. Check if the worker is running:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
pm2 list
|
npm run worker:status
|
||||||
```
|
```
|
||||||
|
|
||||||
If the worker is stopped, restart it:
|
If the worker is stopped, restart it:
|
||||||
|
|||||||
@@ -113,7 +113,7 @@ Many endpoints share these parameters:
|
|||||||
## Error Handling
|
## Error Handling
|
||||||
|
|
||||||
**Worker not running:**
|
**Worker not running:**
|
||||||
Connection refused error. Response: "The search API isn't available. Check if worker is running: `pm2 list`"
|
Connection refused error. Response: "The search API isn't available. Check if worker is running: `npm run worker:status`"
|
||||||
|
|
||||||
**Invalid endpoint:**
|
**Invalid endpoint:**
|
||||||
```json
|
```json
|
||||||
|
|||||||
@@ -93,7 +93,7 @@ curl -s "http://localhost:37777/api/context/recent?limit=3"
|
|||||||
Response: "No recent sessions found for 'new-project'. This might be a new project."
|
Response: "No recent sessions found for 'new-project'. This might be a new project."
|
||||||
|
|
||||||
**Worker not running:**
|
**Worker not running:**
|
||||||
Connection refused error. Inform user to check if worker is running: `pm2 list`
|
Connection refused error. Inform user to check if worker is running: `npm run worker:status`
|
||||||
|
|
||||||
## Tips
|
## Tips
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
name: troubleshoot
|
name: troubleshoot
|
||||||
description: Diagnose and fix claude-mem installation issues. Checks PM2 worker status, database integrity, service health, dependencies, and provides automated fixes for common problems.
|
description: Diagnose and fix claude-mem installation issues. Checks worker status, database integrity, service health, dependencies, and provides automated fixes for common problems.
|
||||||
---
|
---
|
||||||
|
|
||||||
# Claude-Mem Troubleshooting Skill
|
# Claude-Mem Troubleshooting Skill
|
||||||
@@ -39,7 +39,7 @@ Choose the appropriate operation file for detailed instructions:
|
|||||||
|
|
||||||
### Diagnostic Workflows
|
### Diagnostic Workflows
|
||||||
1. **[Full System Diagnostics](operations/diagnostics.md)** - Comprehensive step-by-step diagnostic workflow
|
1. **[Full System Diagnostics](operations/diagnostics.md)** - Comprehensive step-by-step diagnostic workflow
|
||||||
2. **[Worker Diagnostics](operations/worker.md)** - PM2 worker-specific troubleshooting
|
2. **[Worker Diagnostics](operations/worker.md)** - Bun worker-specific troubleshooting
|
||||||
3. **[Database Diagnostics](operations/database.md)** - Database integrity and data checks
|
3. **[Database Diagnostics](operations/database.md)** - Database integrity and data checks
|
||||||
|
|
||||||
### Issue Resolution
|
### Issue Resolution
|
||||||
@@ -54,9 +54,9 @@ Choose the appropriate operation file for detailed instructions:
|
|||||||
**Fast automated fix (try this first):**
|
**Fast automated fix (try this first):**
|
||||||
```bash
|
```bash
|
||||||
cd ~/.claude/plugins/marketplaces/thedotmack/ && \
|
cd ~/.claude/plugins/marketplaces/thedotmack/ && \
|
||||||
pm2 delete claude-mem-worker 2>/dev/null; \
|
npm run worker:stop; \
|
||||||
npm install && \
|
npm install && \
|
||||||
node_modules/.bin/pm2 start ecosystem.config.cjs && \
|
npm run worker:start && \
|
||||||
sleep 3 && \
|
sleep 3 && \
|
||||||
curl -s http://127.0.0.1:37777/health
|
curl -s http://127.0.0.1:37777/health
|
||||||
```
|
```
|
||||||
@@ -79,7 +79,7 @@ When troubleshooting:
|
|||||||
- **Worker port:** Default 37777 (configurable via `CLAUDE_MEM_WORKER_PORT`)
|
- **Worker port:** Default 37777 (configurable via `CLAUDE_MEM_WORKER_PORT`)
|
||||||
- **Database location:** `~/.claude-mem/claude-mem.db`
|
- **Database location:** `~/.claude-mem/claude-mem.db`
|
||||||
- **Plugin location:** `~/.claude/plugins/marketplaces/thedotmack/`
|
- **Plugin location:** `~/.claude/plugins/marketplaces/thedotmack/`
|
||||||
- **PM2 process name:** `claude-mem-worker`
|
- **Worker PID file:** `~/.claude-mem/worker.pid`
|
||||||
|
|
||||||
## Error Reporting
|
## Error Reporting
|
||||||
|
|
||||||
|
|||||||
@@ -8,9 +8,9 @@ One-command fix sequences for common claude-mem issues.
|
|||||||
|
|
||||||
```bash
|
```bash
|
||||||
cd ~/.claude/plugins/marketplaces/thedotmack/ && \
|
cd ~/.claude/plugins/marketplaces/thedotmack/ && \
|
||||||
pm2 delete claude-mem-worker 2>/dev/null; \
|
npm run worker:stop; \
|
||||||
npm install && \
|
npm install && \
|
||||||
node_modules/.bin/pm2 start ecosystem.config.cjs && \
|
npm run worker:start && \
|
||||||
sleep 3 && \
|
sleep 3 && \
|
||||||
curl -s http://127.0.0.1:37777/health
|
curl -s http://127.0.0.1:37777/health
|
||||||
```
|
```
|
||||||
@@ -20,22 +20,22 @@ curl -s http://127.0.0.1:37777/health
|
|||||||
**What it does:**
|
**What it does:**
|
||||||
1. Stops the worker (if running)
|
1. Stops the worker (if running)
|
||||||
2. Ensures dependencies are installed
|
2. Ensures dependencies are installed
|
||||||
3. Starts worker with local PM2
|
3. Starts worker
|
||||||
4. Waits for startup
|
4. Waits for startup
|
||||||
5. Verifies health
|
5. Verifies health
|
||||||
|
|
||||||
## Fix: Worker Not Running
|
## Fix: Worker Not Running
|
||||||
|
|
||||||
**Use when:** PM2 shows worker as stopped or not listed
|
**Use when:** Worker status shows it's not running
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cd ~/.claude/plugins/marketplaces/thedotmack/ && \
|
cd ~/.claude/plugins/marketplaces/thedotmack/ && \
|
||||||
node_modules/.bin/pm2 start ecosystem.config.cjs && \
|
npm run worker:start && \
|
||||||
sleep 2 && \
|
sleep 2 && \
|
||||||
pm2 status
|
npm run worker:status
|
||||||
```
|
```
|
||||||
|
|
||||||
**Expected output:** Worker shows as "online"
|
**Expected output:** Worker running with PID and health OK
|
||||||
|
|
||||||
## Fix: Dependencies Missing
|
## Fix: Dependencies Missing
|
||||||
|
|
||||||
@@ -44,9 +44,23 @@ pm2 status
|
|||||||
```bash
|
```bash
|
||||||
cd ~/.claude/plugins/marketplaces/thedotmack/ && \
|
cd ~/.claude/plugins/marketplaces/thedotmack/ && \
|
||||||
npm install && \
|
npm install && \
|
||||||
pm2 restart claude-mem-worker
|
npm run worker:restart
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Fix: Stale PID File
|
||||||
|
|
||||||
|
**Use when:** Worker reports running but health check fails
|
||||||
|
|
||||||
|
```bash
|
||||||
|
rm -f ~/.claude-mem/worker.pid && \
|
||||||
|
cd ~/.claude/plugins/marketplaces/thedotmack/ && \
|
||||||
|
npm run worker:start && \
|
||||||
|
sleep 2 && \
|
||||||
|
curl -s http://127.0.0.1:37777/health
|
||||||
|
```
|
||||||
|
|
||||||
|
**Expected output:** `{"status":"ok"}`
|
||||||
|
|
||||||
## Fix: Port Conflict
|
## Fix: Port Conflict
|
||||||
|
|
||||||
**Use when:** Error shows port already in use
|
**Use when:** Error shows port already in use
|
||||||
@@ -54,8 +68,9 @@ pm2 restart claude-mem-worker
|
|||||||
```bash
|
```bash
|
||||||
# Change to port 37778
|
# Change to port 37778
|
||||||
mkdir -p ~/.claude-mem && \
|
mkdir -p ~/.claude-mem && \
|
||||||
echo '{"env":{"CLAUDE_MEM_WORKER_PORT":"37778"}}' > ~/.claude-mem/settings.json && \
|
echo '{"CLAUDE_MEM_WORKER_PORT":"37778"}' > ~/.claude-mem/settings.json && \
|
||||||
pm2 restart claude-mem-worker && \
|
cd ~/.claude/plugins/marketplaces/thedotmack/ && \
|
||||||
|
npm run worker:restart && \
|
||||||
sleep 2 && \
|
sleep 2 && \
|
||||||
curl -s http://127.0.0.1:37778/health
|
curl -s http://127.0.0.1:37778/health
|
||||||
```
|
```
|
||||||
@@ -70,14 +85,16 @@ curl -s http://127.0.0.1:37778/health
|
|||||||
# Backup and test integrity
|
# Backup and test integrity
|
||||||
cp ~/.claude-mem/claude-mem.db ~/.claude-mem/claude-mem.db.backup && \
|
cp ~/.claude-mem/claude-mem.db ~/.claude-mem/claude-mem.db.backup && \
|
||||||
sqlite3 ~/.claude-mem/claude-mem.db "PRAGMA integrity_check;" && \
|
sqlite3 ~/.claude-mem/claude-mem.db "PRAGMA integrity_check;" && \
|
||||||
pm2 restart claude-mem-worker
|
cd ~/.claude/plugins/marketplaces/thedotmack/ && \
|
||||||
|
npm run worker:restart
|
||||||
```
|
```
|
||||||
|
|
||||||
**If integrity check fails, recreate database:**
|
**If integrity check fails, recreate database:**
|
||||||
```bash
|
```bash
|
||||||
# WARNING: This deletes all memory data
|
# WARNING: This deletes all memory data
|
||||||
mv ~/.claude-mem/claude-mem.db ~/.claude-mem/claude-mem.db.old && \
|
mv ~/.claude-mem/claude-mem.db ~/.claude-mem/claude-mem.db.old && \
|
||||||
pm2 restart claude-mem-worker
|
cd ~/.claude/plugins/marketplaces/thedotmack/ && \
|
||||||
|
npm run worker:restart
|
||||||
```
|
```
|
||||||
|
|
||||||
## Fix: Clean Reinstall
|
## Fix: Clean Reinstall
|
||||||
@@ -88,36 +105,49 @@ pm2 restart claude-mem-worker
|
|||||||
# Backup data first
|
# Backup data first
|
||||||
cp ~/.claude-mem/claude-mem.db ~/.claude-mem/claude-mem.db.backup 2>/dev/null
|
cp ~/.claude-mem/claude-mem.db ~/.claude-mem/claude-mem.db.backup 2>/dev/null
|
||||||
|
|
||||||
# Stop and remove worker
|
# Stop worker
|
||||||
pm2 delete claude-mem-worker 2>/dev/null
|
cd ~/.claude/plugins/marketplaces/thedotmack/
|
||||||
|
npm run worker:stop
|
||||||
|
|
||||||
|
# Clean PID file
|
||||||
|
rm -f ~/.claude-mem/worker.pid
|
||||||
|
|
||||||
# Reinstall dependencies
|
# Reinstall dependencies
|
||||||
cd ~/.claude/plugins/marketplaces/thedotmack/ && \
|
|
||||||
rm -rf node_modules && \
|
rm -rf node_modules && \
|
||||||
npm install
|
npm install
|
||||||
|
|
||||||
# Start worker
|
# Start worker
|
||||||
node_modules/.bin/pm2 start ecosystem.config.cjs && \
|
npm run worker:start && \
|
||||||
sleep 3 && \
|
sleep 3 && \
|
||||||
curl -s http://127.0.0.1:37777/health
|
curl -s http://127.0.0.1:37777/health
|
||||||
```
|
```
|
||||||
|
|
||||||
## Fix: Clear PM2 Logs
|
## Fix: Clear Old Logs
|
||||||
|
|
||||||
**Use when:** Logs are too large, want fresh start
|
**Use when:** Want to start with fresh logs
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
pm2 flush claude-mem-worker && \
|
# Archive old logs
|
||||||
pm2 restart claude-mem-worker
|
tar -czf ~/.claude-mem/logs-archive-$(date +%Y-%m-%d).tar.gz ~/.claude-mem/logs/*.log 2>/dev/null
|
||||||
|
|
||||||
|
# Remove logs older than 7 days
|
||||||
|
find ~/.claude-mem/logs/ -name "worker-*.log" -mtime +7 -delete
|
||||||
|
|
||||||
|
# Restart worker for fresh log
|
||||||
|
cd ~/.claude/plugins/marketplaces/thedotmack/
|
||||||
|
npm run worker:restart
|
||||||
```
|
```
|
||||||
|
|
||||||
|
**Note:** Logs auto-rotate daily, manual cleanup rarely needed.
|
||||||
|
|
||||||
## Verification Commands
|
## Verification Commands
|
||||||
|
|
||||||
**After running any fix, verify with these:**
|
**After running any fix, verify with these:**
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Check worker status
|
# Check worker status
|
||||||
pm2 status | grep claude-mem-worker
|
cd ~/.claude/plugins/marketplaces/thedotmack/
|
||||||
|
npm run worker:status
|
||||||
|
|
||||||
# Check health
|
# Check health
|
||||||
curl -s http://127.0.0.1:37777/health
|
curl -s http://127.0.0.1:37777/health
|
||||||
@@ -129,23 +159,48 @@ sqlite3 ~/.claude-mem/claude-mem.db "SELECT COUNT(*) FROM observations;"
|
|||||||
curl -s http://127.0.0.1:37777/api/stats
|
curl -s http://127.0.0.1:37777/api/stats
|
||||||
|
|
||||||
# Check logs for errors
|
# Check logs for errors
|
||||||
pm2 logs claude-mem-worker --lines 20 --nostream | grep -i error
|
grep -i "error" ~/.claude-mem/logs/worker-$(date +%Y-%m-%d).log | tail -20
|
||||||
```
|
```
|
||||||
|
|
||||||
**All checks should pass:**
|
**All checks should pass:**
|
||||||
- Worker status: "online"
|
- Worker status: Shows PID and "Health: OK"
|
||||||
- Health: `{"status":"ok"}`
|
- Health endpoint: `{"status":"ok"}`
|
||||||
- Database: Shows count (may be 0 if new)
|
- Database: Shows count (may be 0 if new)
|
||||||
- Stats: Returns JSON with counts
|
- Stats: Returns JSON with counts
|
||||||
- Logs: No recent errors
|
- Logs: No recent errors
|
||||||
|
|
||||||
|
## One-Line Complete Diagnostic
|
||||||
|
|
||||||
|
**Quick health check:**
|
||||||
|
```bash
|
||||||
|
cd ~/.claude/plugins/marketplaces/thedotmack/ && npm run worker:status && curl -s http://127.0.0.1:37777/health && echo " ✓ All systems OK"
|
||||||
|
```
|
||||||
|
|
||||||
## Troubleshooting the Fixes
|
## Troubleshooting the Fixes
|
||||||
|
|
||||||
**If automated fix fails:**
|
**If automated fix fails:**
|
||||||
1. Run the diagnostic script from [diagnostics.md](diagnostics.md)
|
1. Run the diagnostic script from [diagnostics.md](diagnostics.md)
|
||||||
2. Check specific error in PM2 logs
|
2. Check specific error in worker logs:
|
||||||
|
```bash
|
||||||
|
tail -50 ~/.claude-mem/logs/worker-$(date +%Y-%m-%d).log
|
||||||
|
```
|
||||||
3. Try manual worker start to see detailed error:
|
3. Try manual worker start to see detailed error:
|
||||||
```bash
|
```bash
|
||||||
cd ~/.claude/plugins/marketplaces/thedotmack/
|
cd ~/.claude/plugins/marketplaces/thedotmack/
|
||||||
node plugin/scripts/worker-service.cjs
|
bun plugin/scripts/worker-service.js
|
||||||
```
|
```
|
||||||
|
4. Use the bug report tool:
|
||||||
|
```bash
|
||||||
|
npm run bug-report
|
||||||
|
```
|
||||||
|
|
||||||
|
## Common Error Patterns and Fixes
|
||||||
|
|
||||||
|
| Error Pattern | Likely Cause | Quick Fix |
|
||||||
|
|---------------|--------------|-----------|
|
||||||
|
| `EADDRINUSE` | Port conflict | Change port in settings.json |
|
||||||
|
| `SQLITE_ERROR` | Database corruption | Run integrity check, recreate if needed |
|
||||||
|
| `ENOENT` | Missing files | Run `npm install` |
|
||||||
|
| `Module not found` | Dependency issue | Clean reinstall |
|
||||||
|
| Connection refused | Worker not running | `npm run worker:start` |
|
||||||
|
| Stale PID | Old PID file | Remove `~/.claude-mem/worker.pid` |
|
||||||
|
|||||||
@@ -17,7 +17,8 @@ Quick fixes for frequently encountered claude-mem problems.
|
|||||||
**Fix:**
|
**Fix:**
|
||||||
1. Verify worker is running:
|
1. Verify worker is running:
|
||||||
```bash
|
```bash
|
||||||
pm2 jlist | grep claude-mem-worker
|
cd ~/.claude/plugins/marketplaces/thedotmack/
|
||||||
|
npm run worker:status
|
||||||
```
|
```
|
||||||
|
|
||||||
2. Check database has recent observations:
|
2. Check database has recent observations:
|
||||||
@@ -27,7 +28,8 @@ Quick fixes for frequently encountered claude-mem problems.
|
|||||||
|
|
||||||
3. Restart worker and start new session:
|
3. Restart worker and start new session:
|
||||||
```bash
|
```bash
|
||||||
pm2 restart claude-mem-worker
|
cd ~/.claude/plugins/marketplaces/thedotmack/
|
||||||
|
npm run worker:restart
|
||||||
```
|
```
|
||||||
|
|
||||||
4. Create a test observation: `/skill version-bump` then cancel
|
4. Create a test observation: `/skill version-bump` then cancel
|
||||||
@@ -66,7 +68,7 @@ Quick fixes for frequently encountered claude-mem problems.
|
|||||||
|
|
||||||
3. Verify worker is using correct database path in logs:
|
3. Verify worker is using correct database path in logs:
|
||||||
```bash
|
```bash
|
||||||
pm2 logs claude-mem-worker --lines 50 --nostream | grep "Database"
|
grep "Database" ~/.claude-mem/logs/worker-$(date +%Y-%m-%d).log
|
||||||
```
|
```
|
||||||
|
|
||||||
4. Test viewer connection manually:
|
4. Test viewer connection manually:
|
||||||
@@ -109,34 +111,34 @@ Quick fixes for frequently encountered claude-mem problems.
|
|||||||
## Issue: Worker Not Starting {#worker-not-starting}
|
## Issue: Worker Not Starting {#worker-not-starting}
|
||||||
|
|
||||||
**Symptoms:**
|
**Symptoms:**
|
||||||
- PM2 shows worker as "stopped" or "errored"
|
- Worker status shows not running or error
|
||||||
- Health check fails
|
- Health check fails
|
||||||
- Viewer not accessible
|
- Viewer not accessible
|
||||||
|
|
||||||
**Root cause:**
|
**Root cause:**
|
||||||
- Port already in use
|
- Port already in use
|
||||||
- PM2 not installed or not in PATH
|
- Bun not installed
|
||||||
- Missing dependencies
|
- Missing dependencies
|
||||||
|
|
||||||
**Fix:**
|
**Fix:**
|
||||||
1. Try manual worker start to see error:
|
1. Try manual worker start to see error:
|
||||||
```bash
|
```bash
|
||||||
cd ~/.claude/plugins/marketplaces/thedotmack/
|
cd ~/.claude/plugins/marketplaces/thedotmack/
|
||||||
node plugin/scripts/worker-service.cjs
|
bun plugin/scripts/worker-service.js
|
||||||
# Should start server on port 37777 or show error
|
# Should start server on port 37777 or show error
|
||||||
```
|
```
|
||||||
|
|
||||||
2. If port in use, change it:
|
2. If port in use, change it:
|
||||||
```bash
|
```bash
|
||||||
mkdir -p ~/.claude-mem
|
mkdir -p ~/.claude-mem
|
||||||
echo '{"env":{"CLAUDE_MEM_WORKER_PORT":"37778"}}' > ~/.claude-mem/settings.json
|
echo '{"CLAUDE_MEM_WORKER_PORT":"37778"}' > ~/.claude-mem/settings.json
|
||||||
```
|
```
|
||||||
|
|
||||||
3. If dependencies missing:
|
3. If dependencies missing:
|
||||||
```bash
|
```bash
|
||||||
cd ~/.claude/plugins/marketplaces/thedotmack/
|
cd ~/.claude/plugins/marketplaces/thedotmack/
|
||||||
npm install
|
npm install
|
||||||
pm2 start ecosystem.config.cjs
|
npm run worker:start
|
||||||
```
|
```
|
||||||
|
|
||||||
## Issue: Search Results Empty
|
## Issue: Search Results Empty
|
||||||
@@ -170,7 +172,8 @@ Quick fixes for frequently encountered claude-mem problems.
|
|||||||
|
|
||||||
4. If FTS5 out of sync, restart worker (triggers reindex):
|
4. If FTS5 out of sync, restart worker (triggers reindex):
|
||||||
```bash
|
```bash
|
||||||
pm2 restart claude-mem-worker
|
cd ~/.claude/plugins/marketplaces/thedotmack/
|
||||||
|
npm run worker:restart
|
||||||
```
|
```
|
||||||
|
|
||||||
## Issue: Port Conflicts
|
## Issue: Port Conflicts
|
||||||
@@ -189,8 +192,9 @@ Quick fixes for frequently encountered claude-mem problems.
|
|||||||
2. Either kill the conflicting process or change claude-mem port:
|
2. Either kill the conflicting process or change claude-mem port:
|
||||||
```bash
|
```bash
|
||||||
mkdir -p ~/.claude-mem
|
mkdir -p ~/.claude-mem
|
||||||
echo '{"env":{"CLAUDE_MEM_WORKER_PORT":"37778"}}' > ~/.claude-mem/settings.json
|
echo '{"CLAUDE_MEM_WORKER_PORT":"37778"}' > ~/.claude-mem/settings.json
|
||||||
pm2 restart claude-mem-worker
|
cd ~/.claude/plugins/marketplaces/thedotmack/
|
||||||
|
npm run worker:restart
|
||||||
```
|
```
|
||||||
|
|
||||||
## Issue: Database Corrupted
|
## Issue: Database Corrupted
|
||||||
@@ -214,7 +218,8 @@ Quick fixes for frequently encountered claude-mem problems.
|
|||||||
3. If repair fails, recreate (loses data):
|
3. If repair fails, recreate (loses data):
|
||||||
```bash
|
```bash
|
||||||
rm ~/.claude-mem/claude-mem.db
|
rm ~/.claude-mem/claude-mem.db
|
||||||
pm2 restart claude-mem-worker
|
cd ~/.claude/plugins/marketplaces/thedotmack/
|
||||||
|
npm run worker:restart
|
||||||
# Worker will create new database
|
# Worker will create new database
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
@@ -172,7 +172,8 @@ SELECT
|
|||||||
If FTS5 counts don't match, triggers may have failed. Restart worker to rebuild:
|
If FTS5 counts don't match, triggers may have failed. Restart worker to rebuild:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
pm2 restart claude-mem-worker
|
cd ~/.claude/plugins/marketplaces/thedotmack/
|
||||||
|
npm run worker:restart
|
||||||
```
|
```
|
||||||
|
|
||||||
The worker will rebuild FTS5 indexes on startup if they're out of sync.
|
The worker will rebuild FTS5 indexes on startup if they're out of sync.
|
||||||
@@ -196,7 +197,7 @@ The worker will rebuild FTS5 indexes on startup if they're out of sync.
|
|||||||
1. Create test observation (use any skill and cancel)
|
1. Create test observation (use any skill and cancel)
|
||||||
2. Check worker logs for errors:
|
2. Check worker logs for errors:
|
||||||
```bash
|
```bash
|
||||||
pm2 logs claude-mem-worker --lines 50 --nostream
|
tail -50 ~/.claude-mem/logs/worker-$(date +%Y-%m-%d).log
|
||||||
```
|
```
|
||||||
3. Verify observation appears in database
|
3. Verify observation appears in database
|
||||||
|
|
||||||
@@ -228,9 +229,10 @@ ls -la ~/.claude-mem/claude-mem.db-wal
|
|||||||
ls -la ~/.claude-mem/claude-mem.db-shm
|
ls -la ~/.claude-mem/claude-mem.db-shm
|
||||||
|
|
||||||
# Remove lock files (only if worker is stopped!)
|
# Remove lock files (only if worker is stopped!)
|
||||||
pm2 stop claude-mem-worker
|
cd ~/.claude/plugins/marketplaces/thedotmack/
|
||||||
|
npm run worker:stop
|
||||||
rm ~/.claude-mem/claude-mem.db-wal ~/.claude-mem/claude-mem.db-shm
|
rm ~/.claude-mem/claude-mem.db-wal ~/.claude-mem/claude-mem.db-shm
|
||||||
pm2 start claude-mem-worker
|
npm run worker:start
|
||||||
```
|
```
|
||||||
|
|
||||||
### Issue: Database Growing Too Large
|
### Issue: Database Growing Too Large
|
||||||
@@ -260,7 +262,8 @@ sqlite3 ~/.claude-mem/claude-mem.db "SELECT COUNT(*) FROM observations;"
|
|||||||
3. Archive and start fresh:
|
3. Archive and start fresh:
|
||||||
```bash
|
```bash
|
||||||
mv ~/.claude-mem/claude-mem.db ~/.claude-mem/claude-mem.db.archive
|
mv ~/.claude-mem/claude-mem.db ~/.claude-mem/claude-mem.db.archive
|
||||||
pm2 restart claude-mem-worker
|
cd ~/.claude/plugins/marketplaces/thedotmack/
|
||||||
|
npm run worker:restart
|
||||||
```
|
```
|
||||||
|
|
||||||
## Database Recovery
|
## Database Recovery
|
||||||
@@ -275,9 +278,10 @@ cp ~/.claude-mem/claude-mem.db ~/.claude-mem/claude-mem.db.backup
|
|||||||
### Restore from Backup
|
### Restore from Backup
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
pm2 stop claude-mem-worker
|
cd ~/.claude/plugins/marketplaces/thedotmack/
|
||||||
|
npm run worker:stop
|
||||||
cp ~/.claude-mem/claude-mem.db.backup ~/.claude-mem/claude-mem.db
|
cp ~/.claude-mem/claude-mem.db.backup ~/.claude-mem/claude-mem.db
|
||||||
pm2 start claude-mem-worker
|
npm run worker:start
|
||||||
```
|
```
|
||||||
|
|
||||||
### Export Data
|
### Export Data
|
||||||
@@ -300,8 +304,10 @@ sqlite3 ~/.claude-mem/claude-mem.db -json "SELECT * FROM user_prompts;" > prompt
|
|||||||
**WARNING: Data loss. Backup first!**
|
**WARNING: Data loss. Backup first!**
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
cd ~/.claude/plugins/marketplaces/thedotmack/
|
||||||
|
|
||||||
# Stop worker
|
# Stop worker
|
||||||
pm2 stop claude-mem-worker
|
npm run worker:stop
|
||||||
|
|
||||||
# Backup current database
|
# Backup current database
|
||||||
cp ~/.claude-mem/claude-mem.db ~/.claude-mem/claude-mem.db.old
|
cp ~/.claude-mem/claude-mem.db ~/.claude-mem/claude-mem.db.old
|
||||||
@@ -310,7 +316,7 @@ cp ~/.claude-mem/claude-mem.db ~/.claude-mem/claude-mem.db.old
|
|||||||
rm ~/.claude-mem/claude-mem.db
|
rm ~/.claude-mem/claude-mem.db
|
||||||
|
|
||||||
# Start worker (creates new database)
|
# Start worker (creates new database)
|
||||||
pm2 start claude-mem-worker
|
npm run worker:start
|
||||||
```
|
```
|
||||||
|
|
||||||
## Database Statistics
|
## Database Statistics
|
||||||
|
|||||||
@@ -6,29 +6,42 @@ Comprehensive step-by-step diagnostic workflow for claude-mem issues.
|
|||||||
|
|
||||||
Run these checks systematically to identify the root cause:
|
Run these checks systematically to identify the root cause:
|
||||||
|
|
||||||
### 1. Check PM2 Worker Status
|
### 1. Check Worker Status
|
||||||
|
|
||||||
First, verify if the worker service is running:
|
First, verify if the worker service is running:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Check if PM2 is available
|
# Check worker status using npm script
|
||||||
which pm2 || echo "PM2 not found in PATH"
|
cd ~/.claude/plugins/marketplaces/thedotmack/
|
||||||
|
npm run worker:status
|
||||||
|
|
||||||
# List PM2 processes
|
# Or check health endpoint directly
|
||||||
pm2 jlist 2>&1
|
curl -s http://127.0.0.1:37777/health
|
||||||
|
|
||||||
# If pm2 is not found, try the local installation
|
|
||||||
~/.claude/plugins/marketplaces/thedotmack/node_modules/.bin/pm2 jlist 2>&1
|
|
||||||
```
|
```
|
||||||
|
|
||||||
**Expected output:** JSON array with `claude-mem-worker` process showing `"status": "online"`
|
**Expected output from npm run worker:status:**
|
||||||
|
```
|
||||||
|
✓ Worker is running (PID: 12345)
|
||||||
|
Port: 37777
|
||||||
|
Uptime: 45m
|
||||||
|
Health: OK
|
||||||
|
```
|
||||||
|
|
||||||
**If worker not running or status is not "online":**
|
**Expected output from health endpoint:** `{"status":"ok"}`
|
||||||
|
|
||||||
|
**If worker not running:**
|
||||||
```bash
|
```bash
|
||||||
cd ~/.claude/plugins/marketplaces/thedotmack/
|
cd ~/.claude/plugins/marketplaces/thedotmack/
|
||||||
pm2 start ecosystem.config.cjs
|
npm run worker:start
|
||||||
# Or use local pm2:
|
```
|
||||||
node_modules/.bin/pm2 start ecosystem.config.cjs
|
|
||||||
|
**If health endpoint fails but worker reports running:**
|
||||||
|
Check for stale PID file:
|
||||||
|
```bash
|
||||||
|
cat ~/.claude-mem/worker.pid
|
||||||
|
ps -p $(cat ~/.claude-mem/worker.pid 2>/dev/null | grep -o '"pid":[0-9]*' | grep -o '[0-9]*') 2>/dev/null || echo "Stale PID - worker not actually running"
|
||||||
|
rm ~/.claude-mem/worker.pid
|
||||||
|
npm run worker:start
|
||||||
```
|
```
|
||||||
|
|
||||||
### 2. Check Worker Service Health
|
### 2. Check Worker Service Health
|
||||||
@@ -98,10 +111,12 @@ cd ~/.claude/plugins/marketplaces/thedotmack/
|
|||||||
# Check for critical packages
|
# Check for critical packages
|
||||||
ls node_modules/@anthropic-ai/claude-agent-sdk 2>&1 | head -1
|
ls node_modules/@anthropic-ai/claude-agent-sdk 2>&1 | head -1
|
||||||
ls node_modules/express 2>&1 | head -1
|
ls node_modules/express 2>&1 | head -1
|
||||||
ls node_modules/pm2 2>&1 | head -1
|
|
||||||
|
# Check if Bun is available
|
||||||
|
bun --version 2>&1
|
||||||
```
|
```
|
||||||
|
|
||||||
**Expected:** All critical packages present
|
**Expected:** All critical packages present, Bun installed
|
||||||
|
|
||||||
**If dependencies missing:**
|
**If dependencies missing:**
|
||||||
```bash
|
```bash
|
||||||
@@ -114,17 +129,26 @@ npm install
|
|||||||
Review recent worker logs for errors:
|
Review recent worker logs for errors:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# View last 50 lines of worker logs
|
# View logs using npm script
|
||||||
pm2 logs claude-mem-worker --lines 50 --nostream
|
|
||||||
|
|
||||||
# Or use local pm2:
|
|
||||||
cd ~/.claude/plugins/marketplaces/thedotmack/
|
cd ~/.claude/plugins/marketplaces/thedotmack/
|
||||||
node_modules/.bin/pm2 logs claude-mem-worker --lines 50 --nostream
|
npm run worker:logs
|
||||||
|
|
||||||
|
# View today's log file directly
|
||||||
|
cat ~/.claude-mem/logs/worker-$(date +%Y-%m-%d).log
|
||||||
|
|
||||||
|
# Last 50 lines
|
||||||
|
tail -50 ~/.claude-mem/logs/worker-$(date +%Y-%m-%d).log
|
||||||
|
|
||||||
# Check for specific errors
|
# Check for specific errors
|
||||||
pm2 logs claude-mem-worker --lines 100 --nostream | grep -i "error\|exception\|failed"
|
grep -iE "error|exception|failed" ~/.claude-mem/logs/worker-$(date +%Y-%m-%d).log | tail -20
|
||||||
```
|
```
|
||||||
|
|
||||||
|
**Common error patterns to look for:**
|
||||||
|
- `SQLITE_ERROR` - Database issues
|
||||||
|
- `EADDRINUSE` - Port conflict
|
||||||
|
- `ENOENT` - Missing files
|
||||||
|
- `Module not found` - Dependency issues
|
||||||
|
|
||||||
### 6. Test Viewer UI
|
### 6. Test Viewer UI
|
||||||
|
|
||||||
Check if the web viewer is accessible:
|
Check if the web viewer is accessible:
|
||||||
@@ -167,6 +191,8 @@ echo "=== Claude-Mem Troubleshooting Report ==="
|
|||||||
echo ""
|
echo ""
|
||||||
echo "1. Environment"
|
echo "1. Environment"
|
||||||
echo " OS: $(uname -s)"
|
echo " OS: $(uname -s)"
|
||||||
|
echo " Node version: $(node --version 2>/dev/null || echo 'N/A')"
|
||||||
|
echo " Bun version: $(bun --version 2>/dev/null || echo 'N/A')"
|
||||||
echo ""
|
echo ""
|
||||||
echo "2. Plugin Installation"
|
echo "2. Plugin Installation"
|
||||||
echo " Plugin directory exists: $([ -d ~/.claude/plugins/marketplaces/thedotmack ] && echo 'YES' || echo 'NO')"
|
echo " Plugin directory exists: $([ -d ~/.claude/plugins/marketplaces/thedotmack ] && echo 'YES' || echo 'NO')"
|
||||||
@@ -179,20 +205,28 @@ echo " Observation count: $(sqlite3 ~/.claude-mem/claude-mem.db 'SELECT COUNT(
|
|||||||
echo " Session count: $(sqlite3 ~/.claude-mem/claude-mem.db 'SELECT COUNT(*) FROM sessions;' 2>/dev/null || echo 'N/A')"
|
echo " Session count: $(sqlite3 ~/.claude-mem/claude-mem.db 'SELECT COUNT(*) FROM sessions;' 2>/dev/null || echo 'N/A')"
|
||||||
echo ""
|
echo ""
|
||||||
echo "4. Worker Service"
|
echo "4. Worker Service"
|
||||||
PM2_PATH=$(which pm2 2>/dev/null || echo "~/.claude/plugins/marketplaces/thedotmack/node_modules/.bin/pm2")
|
echo " Worker PID file: $([ -f ~/.claude-mem/worker.pid ] && echo 'EXISTS' || echo 'MISSING')"
|
||||||
echo " PM2 path: $PM2_PATH"
|
if [ -f ~/.claude-mem/worker.pid ]; then
|
||||||
WORKER_STATUS=$($PM2_PATH jlist 2>/dev/null | grep -o '"name":"claude-mem-worker".*"status":"[^"]*"' | grep -o 'status":"[^"]*"' | cut -d'"' -f3 || echo 'not running')
|
WORKER_PID=$(cat ~/.claude-mem/worker.pid 2>/dev/null | grep -o '"pid":[0-9]*' | grep -o '[0-9]*')
|
||||||
echo " Worker status: $WORKER_STATUS"
|
echo " Worker PID: $WORKER_PID"
|
||||||
|
echo " Process running: $(ps -p $WORKER_PID >/dev/null 2>&1 && echo 'YES' || echo 'NO (stale PID)')"
|
||||||
|
fi
|
||||||
echo " Health check: $(curl -s http://127.0.0.1:37777/health 2>/dev/null || echo 'FAILED')"
|
echo " Health check: $(curl -s http://127.0.0.1:37777/health 2>/dev/null || echo 'FAILED')"
|
||||||
echo ""
|
echo ""
|
||||||
echo "5. Configuration"
|
echo "5. Configuration"
|
||||||
echo " Port setting: $(cat ~/.claude-mem/settings.json 2>/dev/null | grep CLAUDE_MEM_WORKER_PORT || echo 'default (37777)')"
|
echo " Port setting: $(cat ~/.claude-mem/settings.json 2>/dev/null | grep CLAUDE_MEM_WORKER_PORT || echo 'default (37777)')"
|
||||||
echo " Observation count: $(cat ~/.claude-mem/settings.json 2>/dev/null | grep CLAUDE_MEM_CONTEXT_OBSERVATIONS || echo 'default (50)')"
|
echo " Observation count: $(cat ~/.claude-mem/settings.json 2>/dev/null | grep CLAUDE_MEM_CONTEXT_OBSERVATIONS || echo 'default (50)')"
|
||||||
|
echo " Model: $(cat ~/.claude-mem/settings.json 2>/dev/null | grep CLAUDE_MEM_MODEL || echo 'default (claude-sonnet-4-5)')"
|
||||||
echo ""
|
echo ""
|
||||||
echo "6. Recent Activity"
|
echo "6. Recent Activity"
|
||||||
echo " Latest observation: $(sqlite3 ~/.claude-mem/claude-mem.db 'SELECT created_at FROM observations ORDER BY created_at DESC LIMIT 1;' 2>/dev/null || echo 'N/A')"
|
echo " Latest observation: $(sqlite3 ~/.claude-mem/claude-mem.db 'SELECT created_at FROM observations ORDER BY created_at DESC LIMIT 1;' 2>/dev/null || echo 'N/A')"
|
||||||
echo " Latest session: $(sqlite3 ~/.claude-mem/claude-mem.db 'SELECT created_at FROM sessions ORDER BY created_at DESC LIMIT 1;' 2>/dev/null || echo 'N/A')"
|
echo " Latest session: $(sqlite3 ~/.claude-mem/claude-mem.db 'SELECT created_at FROM sessions ORDER BY created_at DESC LIMIT 1;' 2>/dev/null || echo 'N/A')"
|
||||||
echo ""
|
echo ""
|
||||||
|
echo "7. Logs"
|
||||||
|
echo " Today's log file: $([ -f ~/.claude-mem/logs/worker-$(date +%Y-%m-%d).log ] && echo 'EXISTS' || echo 'MISSING')"
|
||||||
|
echo " Log file size: $(du -h ~/.claude-mem/logs/worker-$(date +%Y-%m-%d).log 2>/dev/null | cut -f1 || echo 'N/A')"
|
||||||
|
echo " Recent errors: $(grep -c -i "error" ~/.claude-mem/logs/worker-$(date +%Y-%m-%d).log 2>/dev/null || echo '0')"
|
||||||
|
echo ""
|
||||||
echo "=== End Report ==="
|
echo "=== End Report ==="
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -201,18 +235,75 @@ Save this as `/tmp/claude-mem-diagnostics.sh` and run:
|
|||||||
bash /tmp/claude-mem-diagnostics.sh
|
bash /tmp/claude-mem-diagnostics.sh
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Quick Diagnostic One-Liners
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Full status check
|
||||||
|
npm run worker:status && curl -s http://127.0.0.1:37777/health && echo " - All systems OK"
|
||||||
|
|
||||||
|
# Database stats
|
||||||
|
echo "DB: $(du -h ~/.claude-mem/claude-mem.db | cut -f1) | Obs: $(sqlite3 ~/.claude-mem/claude-mem.db 'SELECT COUNT(*) FROM observations;' 2>/dev/null) | Sessions: $(sqlite3 ~/.claude-mem/claude-mem.db 'SELECT COUNT(*) FROM sessions;' 2>/dev/null)"
|
||||||
|
|
||||||
|
# Recent errors
|
||||||
|
grep -i "error" ~/.claude-mem/logs/worker-$(date +%Y-%m-%d).log 2>/dev/null | tail -5 || echo "No recent errors"
|
||||||
|
|
||||||
|
# Port check
|
||||||
|
lsof -i :37777 || echo "Port 37777 is free"
|
||||||
|
|
||||||
|
# Worker process check
|
||||||
|
ps aux | grep -E "bun.*worker-service" | grep -v grep || echo "Worker not running"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Automated Fix Sequence
|
||||||
|
|
||||||
|
If diagnostics show issues, run this automated fix sequence:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
#!/bin/bash
|
||||||
|
echo "Running automated fix sequence..."
|
||||||
|
|
||||||
|
# 1. Stop worker if running
|
||||||
|
echo "1. Stopping worker..."
|
||||||
|
cd ~/.claude/plugins/marketplaces/thedotmack/
|
||||||
|
npm run worker:stop
|
||||||
|
|
||||||
|
# 2. Clean stale PID if exists
|
||||||
|
echo "2. Cleaning stale PID file..."
|
||||||
|
rm -f ~/.claude-mem/worker.pid
|
||||||
|
|
||||||
|
# 3. Reinstall dependencies
|
||||||
|
echo "3. Reinstalling dependencies..."
|
||||||
|
npm install
|
||||||
|
|
||||||
|
# 4. Start worker
|
||||||
|
echo "4. Starting worker..."
|
||||||
|
npm run worker:start
|
||||||
|
|
||||||
|
# 5. Wait for startup
|
||||||
|
echo "5. Waiting for worker to start..."
|
||||||
|
sleep 3
|
||||||
|
|
||||||
|
# 6. Verify health
|
||||||
|
echo "6. Verifying health..."
|
||||||
|
curl -s http://127.0.0.1:37777/health || echo "Worker health check FAILED"
|
||||||
|
|
||||||
|
echo "Fix sequence complete!"
|
||||||
|
```
|
||||||
|
|
||||||
## Reporting Issues
|
## Reporting Issues
|
||||||
|
|
||||||
If troubleshooting doesn't resolve the issue, collect this information for a bug report:
|
If troubleshooting doesn't resolve the issue, run the built-in bug report tool:
|
||||||
|
|
||||||
1. Full diagnostic report (run script above)
|
```bash
|
||||||
2. Worker logs: `pm2 logs claude-mem-worker --lines 100 --nostream`
|
cd ~/.claude/plugins/marketplaces/thedotmack/
|
||||||
3. Your setup:
|
npm run bug-report
|
||||||
- Claude version: Check with Claude
|
```
|
||||||
- OS: `uname -a`
|
|
||||||
- Node version: `node --version`
|
|
||||||
- Plugin version: In package.json
|
|
||||||
4. Steps to reproduce the issue
|
|
||||||
5. Expected vs actual behavior
|
|
||||||
|
|
||||||
Post to: https://github.com/thedotmack/claude-mem/issues
|
This will collect:
|
||||||
|
1. Full diagnostic report
|
||||||
|
2. Worker logs
|
||||||
|
3. System information
|
||||||
|
4. Configuration details
|
||||||
|
5. Database stats
|
||||||
|
|
||||||
|
Post the generated report to: https://github.com/thedotmack/claude-mem/issues
|
||||||
|
|||||||
@@ -6,30 +6,29 @@ Essential commands for troubleshooting claude-mem.
|
|||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Check worker status
|
# Check worker status
|
||||||
pm2 status | grep claude-mem-worker
|
cd ~/.claude/plugins/marketplaces/thedotmack/
|
||||||
pm2 jlist | grep claude-mem-worker # JSON format
|
npm run worker:status
|
||||||
|
|
||||||
# Start worker
|
# Start worker
|
||||||
cd ~/.claude/plugins/marketplaces/thedotmack/
|
npm run worker:start
|
||||||
pm2 start ecosystem.config.cjs
|
|
||||||
|
|
||||||
# Restart worker
|
# Restart worker
|
||||||
pm2 restart claude-mem-worker
|
npm run worker:restart
|
||||||
|
|
||||||
# Stop worker
|
# Stop worker
|
||||||
pm2 stop claude-mem-worker
|
npm run worker:stop
|
||||||
|
|
||||||
# Delete worker (for clean restart)
|
|
||||||
pm2 delete claude-mem-worker
|
|
||||||
|
|
||||||
# View logs
|
# View logs
|
||||||
pm2 logs claude-mem-worker
|
npm run worker:logs
|
||||||
|
|
||||||
# View last N lines
|
# View today's log file
|
||||||
pm2 logs claude-mem-worker --lines 50 --nostream
|
cat ~/.claude-mem/logs/worker-$(date +%Y-%m-%d).log
|
||||||
|
|
||||||
# Clear logs
|
# Last 50 lines
|
||||||
pm2 flush claude-mem-worker
|
tail -50 ~/.claude-mem/logs/worker-$(date +%Y-%m-%d).log
|
||||||
|
|
||||||
|
# Follow logs in real-time
|
||||||
|
tail -f ~/.claude-mem/logs/worker-$(date +%Y-%m-%d).log
|
||||||
```
|
```
|
||||||
|
|
||||||
## Health Checks
|
## Health Checks
|
||||||
@@ -82,22 +81,18 @@ cat ~/.claude-mem/settings.json
|
|||||||
cat ~/.claude/settings.json
|
cat ~/.claude/settings.json
|
||||||
|
|
||||||
# Change worker port
|
# Change worker port
|
||||||
echo '{"env":{"CLAUDE_MEM_WORKER_PORT":"37778"}}' > ~/.claude-mem/settings.json
|
echo '{"CLAUDE_MEM_WORKER_PORT":"37778"}' > ~/.claude-mem/settings.json
|
||||||
|
|
||||||
# Change context observation count
|
# Change context observation count
|
||||||
# Edit ~/.claude-mem/settings.json and add:
|
# Edit ~/.claude-mem/settings.json and add:
|
||||||
{
|
{
|
||||||
"env": {
|
|
||||||
"CLAUDE_MEM_CONTEXT_OBSERVATIONS": "25"
|
"CLAUDE_MEM_CONTEXT_OBSERVATIONS": "25"
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
# Change AI model
|
# Change AI model
|
||||||
{
|
{
|
||||||
"env": {
|
|
||||||
"CLAUDE_MEM_MODEL": "claude-sonnet-4-5"
|
"CLAUDE_MEM_MODEL": "claude-sonnet-4-5"
|
||||||
}
|
}
|
||||||
}
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Plugin Management
|
## Plugin Management
|
||||||
@@ -132,16 +127,19 @@ curl -v http://127.0.0.1:37777/health
|
|||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Search logs for errors
|
# Search logs for errors
|
||||||
pm2 logs claude-mem-worker --lines 100 --nostream | grep -i "error"
|
grep -i "error" ~/.claude-mem/logs/worker-$(date +%Y-%m-%d).log
|
||||||
|
|
||||||
# Search for specific keyword
|
# Search for specific keyword
|
||||||
pm2 logs claude-mem-worker --lines 100 --nostream | grep "keyword"
|
grep "keyword" ~/.claude-mem/logs/worker-$(date +%Y-%m-%d).log
|
||||||
|
|
||||||
|
# Search across all log files
|
||||||
|
grep -i "error" ~/.claude-mem/logs/worker-*.log
|
||||||
|
|
||||||
|
# Last 100 error lines
|
||||||
|
grep -i "error" ~/.claude-mem/logs/worker-$(date +%Y-%m-%d).log | tail -100
|
||||||
|
|
||||||
# Follow logs in real-time
|
# Follow logs in real-time
|
||||||
pm2 logs claude-mem-worker
|
tail -f ~/.claude-mem/logs/worker-$(date +%Y-%m-%d).log
|
||||||
|
|
||||||
# Show only error logs
|
|
||||||
pm2 logs claude-mem-worker --err
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## File Locations
|
## File Locations
|
||||||
@@ -160,11 +158,11 @@ pm2 logs claude-mem-worker --err
|
|||||||
# Chroma vector database
|
# Chroma vector database
|
||||||
~/.claude-mem/chroma/
|
~/.claude-mem/chroma/
|
||||||
|
|
||||||
# Usage logs
|
# Worker logs (daily rotation)
|
||||||
~/.claude-mem/usage-logs/
|
~/.claude-mem/logs/worker-*.log
|
||||||
|
|
||||||
# PM2 logs
|
# Worker PID file
|
||||||
~/.pm2/logs/
|
~/.claude-mem/worker.pid
|
||||||
```
|
```
|
||||||
|
|
||||||
## System Information
|
## System Information
|
||||||
@@ -179,8 +177,8 @@ node --version
|
|||||||
# NPM version
|
# NPM version
|
||||||
npm --version
|
npm --version
|
||||||
|
|
||||||
# PM2 version
|
# Bun version
|
||||||
pm2 --version
|
bun --version
|
||||||
|
|
||||||
# SQLite version
|
# SQLite version
|
||||||
sqlite3 --version
|
sqlite3 --version
|
||||||
@@ -188,3 +186,22 @@ sqlite3 --version
|
|||||||
# Check disk space
|
# Check disk space
|
||||||
df -h ~/.claude-mem/
|
df -h ~/.claude-mem/
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## One-Line Diagnostics
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Full worker status check
|
||||||
|
npm run worker:status && curl -s http://127.0.0.1:37777/health
|
||||||
|
|
||||||
|
# Quick health check
|
||||||
|
curl -s http://127.0.0.1:37777/health && echo " - Worker is healthy"
|
||||||
|
|
||||||
|
# Database stats
|
||||||
|
echo "Observations: $(sqlite3 ~/.claude-mem/claude-mem.db 'SELECT COUNT(*) FROM observations;')" && echo "Sessions: $(sqlite3 ~/.claude-mem/claude-mem.db 'SELECT COUNT(*) FROM sessions;')"
|
||||||
|
|
||||||
|
# Recent errors
|
||||||
|
grep -i "error" ~/.claude-mem/logs/worker-$(date +%Y-%m-%d).log | tail -10
|
||||||
|
|
||||||
|
# Port check
|
||||||
|
lsof -i :37777 || echo "Port 37777 is free"
|
||||||
|
```
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
# Worker Service Diagnostics
|
# Worker Service Diagnostics
|
||||||
|
|
||||||
PM2 worker-specific troubleshooting for claude-mem.
|
Bun worker-specific troubleshooting for claude-mem.
|
||||||
|
|
||||||
## PM2 Worker Overview
|
## Worker Overview
|
||||||
|
|
||||||
The claude-mem worker is a persistent background service managed by PM2. It:
|
The claude-mem worker is a persistent background service managed by Bun. It:
|
||||||
- Runs Express.js server on port 37777 (default)
|
- Runs Express.js server on port 37777 (default)
|
||||||
- Processes observations asynchronously
|
- Processes observations asynchronously
|
||||||
- Serves the viewer UI
|
- Serves the viewer UI
|
||||||
@@ -15,36 +15,41 @@ The claude-mem worker is a persistent background service managed by PM2. It:
|
|||||||
### Basic Status Check
|
### Basic Status Check
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# List all PM2 processes
|
# Check worker status using npm script
|
||||||
pm2 list
|
cd ~/.claude/plugins/marketplaces/thedotmack/
|
||||||
|
npm run worker:status
|
||||||
|
|
||||||
# JSON format (parseable)
|
# Or check health endpoint directly
|
||||||
pm2 jlist
|
curl -s http://127.0.0.1:37777/health
|
||||||
|
|
||||||
# Filter for claude-mem-worker
|
|
||||||
pm2 status | grep claude-mem-worker
|
|
||||||
```
|
```
|
||||||
|
|
||||||
**Expected output:**
|
**Expected npm run worker:status output:**
|
||||||
```
|
```
|
||||||
│ claude-mem-worker │ online │ 12345 │ 0 │ 45m │ 0% │ 85.6mb │
|
✓ Worker is running (PID: 12345)
|
||||||
|
Port: 37777
|
||||||
|
Uptime: 45m
|
||||||
|
Health: OK
|
||||||
```
|
```
|
||||||
|
|
||||||
**Status meanings:**
|
**Expected health endpoint output:**
|
||||||
- `online` - Worker running correctly
|
```json
|
||||||
- `stopped` - Worker stopped (normal shutdown)
|
{"status":"ok"}
|
||||||
- `errored` - Worker crashed (check logs)
|
```
|
||||||
- `stopping` - Worker shutting down
|
|
||||||
- Not listed - Worker never started
|
**Status indicators:**
|
||||||
|
- `Worker is running` - Worker running correctly
|
||||||
|
- `Worker is not running` - Worker stopped or crashed
|
||||||
|
- Connection refused - Worker not running
|
||||||
|
- Timeout - Worker hung (restart needed)
|
||||||
|
|
||||||
### Detailed Worker Info
|
### Detailed Worker Info
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Show detailed information
|
# View PID file
|
||||||
pm2 show claude-mem-worker
|
cat ~/.claude-mem/worker.pid
|
||||||
|
|
||||||
# JSON format
|
# Check process details
|
||||||
pm2 jlist | grep -A 20 '"name":"claude-mem-worker"'
|
ps aux | grep "bun.*worker-service"
|
||||||
```
|
```
|
||||||
|
|
||||||
## Worker Health Endpoint
|
## Worker Health Endpoint
|
||||||
@@ -72,30 +77,37 @@ curl -s http://127.0.0.1:$PORT/health
|
|||||||
### View Recent Logs
|
### View Recent Logs
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Last 50 lines
|
# View logs using npm script
|
||||||
pm2 logs claude-mem-worker --lines 50 --nostream
|
cd ~/.claude/plugins/marketplaces/thedotmack/
|
||||||
|
npm run worker:logs
|
||||||
|
|
||||||
# Last 200 lines
|
# View today's log file directly
|
||||||
pm2 logs claude-mem-worker --lines 200 --nostream
|
cat ~/.claude-mem/logs/worker-$(date +%Y-%m-%d).log
|
||||||
|
|
||||||
|
# Last 50 lines of today's log
|
||||||
|
tail -50 ~/.claude-mem/logs/worker-$(date +%Y-%m-%d).log
|
||||||
|
|
||||||
# Follow logs in real-time
|
# Follow logs in real-time
|
||||||
pm2 logs claude-mem-worker
|
tail -f ~/.claude-mem/logs/worker-$(date +%Y-%m-%d).log
|
||||||
```
|
```
|
||||||
|
|
||||||
### Search Logs for Errors
|
### Search Logs for Errors
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Find errors
|
# Find errors in today's log
|
||||||
pm2 logs claude-mem-worker --lines 500 --nostream | grep -i "error"
|
grep -i "error" ~/.claude-mem/logs/worker-$(date +%Y-%m-%d).log
|
||||||
|
|
||||||
# Find exceptions
|
# Find exceptions
|
||||||
pm2 logs claude-mem-worker --lines 500 --nostream | grep -i "exception"
|
grep -i "exception" ~/.claude-mem/logs/worker-$(date +%Y-%m-%d).log
|
||||||
|
|
||||||
# Find failed requests
|
# Find failed requests
|
||||||
pm2 logs claude-mem-worker --lines 500 --nostream | grep -i "failed"
|
grep -i "failed" ~/.claude-mem/logs/worker-$(date +%Y-%m-%d).log
|
||||||
|
|
||||||
# All error patterns
|
# All error patterns
|
||||||
pm2 logs claude-mem-worker --lines 500 --nostream | grep -iE "error|exception|failed|crash"
|
grep -iE "error|exception|failed|crash" ~/.claude-mem/logs/worker-$(date +%Y-%m-%d).log
|
||||||
|
|
||||||
|
# Search across all log files
|
||||||
|
grep -iE "error|exception|failed|crash" ~/.claude-mem/logs/worker-*.log
|
||||||
```
|
```
|
||||||
|
|
||||||
### Common Log Patterns
|
### Common Log Patterns
|
||||||
@@ -122,8 +134,8 @@ Port 37777 already in use
|
|||||||
|
|
||||||
**Crashes:**
|
**Crashes:**
|
||||||
```
|
```
|
||||||
PM2 | App [claude-mem-worker] exited with code [1]
|
Worker process exited with code 1
|
||||||
PM2 | App [claude-mem-worker] will restart in 100ms
|
Worker restarting...
|
||||||
```
|
```
|
||||||
|
|
||||||
## Starting the Worker
|
## Starting the Worker
|
||||||
@@ -132,37 +144,26 @@ PM2 | App [claude-mem-worker] will restart in 100ms
|
|||||||
|
|
||||||
```bash
|
```bash
|
||||||
cd ~/.claude/plugins/marketplaces/thedotmack/
|
cd ~/.claude/plugins/marketplaces/thedotmack/
|
||||||
pm2 start ecosystem.config.cjs
|
npm run worker:start
|
||||||
```
|
|
||||||
|
|
||||||
### Start with Local PM2
|
|
||||||
|
|
||||||
If `pm2` command not in PATH:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
cd ~/.claude/plugins/marketplaces/thedotmack/
|
|
||||||
node_modules/.bin/pm2 start ecosystem.config.cjs
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### Force Restart
|
### Force Restart
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Restart if already running
|
# Restart worker (stops and starts)
|
||||||
pm2 restart claude-mem-worker
|
cd ~/.claude/plugins/marketplaces/thedotmack/
|
||||||
|
npm run worker:restart
|
||||||
|
|
||||||
# Delete and start fresh
|
# Or manually stop and start
|
||||||
pm2 delete claude-mem-worker
|
npm run worker:stop
|
||||||
pm2 start ecosystem.config.cjs
|
npm run worker:start
|
||||||
```
|
```
|
||||||
|
|
||||||
## Stopping the Worker
|
## Stopping the Worker
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Graceful stop
|
cd ~/.claude/plugins/marketplaces/thedotmack/
|
||||||
pm2 stop claude-mem-worker
|
npm run worker:stop
|
||||||
|
|
||||||
# Delete completely (also removes from PM2 list)
|
|
||||||
pm2 delete claude-mem-worker
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Worker Not Starting
|
## Worker Not Starting
|
||||||
@@ -172,23 +173,22 @@ pm2 delete claude-mem-worker
|
|||||||
1. **Try manual start to see error:**
|
1. **Try manual start to see error:**
|
||||||
```bash
|
```bash
|
||||||
cd ~/.claude/plugins/marketplaces/thedotmack/
|
cd ~/.claude/plugins/marketplaces/thedotmack/
|
||||||
node plugin/scripts/worker-service.cjs
|
bun plugin/scripts/worker-service.js
|
||||||
```
|
```
|
||||||
This runs the worker directly without PM2, showing full error output.
|
This runs the worker directly, showing full error output.
|
||||||
|
|
||||||
2. **Check PM2 itself:**
|
2. **Check Bun installation:**
|
||||||
```bash
|
```bash
|
||||||
which pm2
|
which bun
|
||||||
pm2 --version
|
bun --version
|
||||||
```
|
```
|
||||||
If PM2 not found, dependencies not installed.
|
If Bun not found, run: `npm install` (auto-installs Bun)
|
||||||
|
|
||||||
3. **Check dependencies:**
|
3. **Check dependencies:**
|
||||||
```bash
|
```bash
|
||||||
cd ~/.claude/plugins/marketplaces/thedotmack/
|
cd ~/.claude/plugins/marketplaces/thedotmack/
|
||||||
ls node_modules/@anthropic-ai/claude-agent-sdk
|
ls node_modules/@anthropic-ai/claude-agent-sdk
|
||||||
ls node_modules/express
|
ls node_modules/express
|
||||||
ls node_modules/pm2
|
|
||||||
```
|
```
|
||||||
|
|
||||||
4. **Check port availability:**
|
4. **Check port availability:**
|
||||||
@@ -197,42 +197,57 @@ pm2 delete claude-mem-worker
|
|||||||
```
|
```
|
||||||
If port in use, either kill that process or change claude-mem port.
|
If port in use, either kill that process or change claude-mem port.
|
||||||
|
|
||||||
|
5. **Check PID file:**
|
||||||
|
```bash
|
||||||
|
cat ~/.claude-mem/worker.pid
|
||||||
|
```
|
||||||
|
If worker PID exists but process is dead, remove stale PID:
|
||||||
|
```bash
|
||||||
|
rm ~/.claude-mem/worker.pid
|
||||||
|
npm run worker:start
|
||||||
|
```
|
||||||
|
|
||||||
### Common Fixes
|
### Common Fixes
|
||||||
|
|
||||||
**Dependencies missing:**
|
**Dependencies missing:**
|
||||||
```bash
|
```bash
|
||||||
cd ~/.claude/plugins/marketplaces/thedotmack/
|
cd ~/.claude/plugins/marketplaces/thedotmack/
|
||||||
npm install
|
npm install
|
||||||
pm2 start ecosystem.config.cjs
|
npm run worker:start
|
||||||
```
|
```
|
||||||
|
|
||||||
**Port conflict:**
|
**Port conflict:**
|
||||||
```bash
|
```bash
|
||||||
echo '{"env":{"CLAUDE_MEM_WORKER_PORT":"37778"}}' > ~/.claude-mem/settings.json
|
echo '{"CLAUDE_MEM_WORKER_PORT":"37778"}' > ~/.claude-mem/settings.json
|
||||||
pm2 restart claude-mem-worker
|
npm run worker:restart
|
||||||
```
|
```
|
||||||
|
|
||||||
**Corrupted PM2:**
|
**Stale PID file:**
|
||||||
```bash
|
```bash
|
||||||
pm2 kill # Stop PM2 daemon
|
rm ~/.claude-mem/worker.pid
|
||||||
cd ~/.claude/plugins/marketplaces/thedotmack/
|
npm run worker:start
|
||||||
pm2 start ecosystem.config.cjs
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Worker Crashing Repeatedly
|
## Worker Crashing Repeatedly
|
||||||
|
|
||||||
If worker keeps restarting (check with `pm2 status` showing high restart count):
|
If worker keeps restarting (check logs for repeated startup messages):
|
||||||
|
|
||||||
### Find the Cause
|
### Find the Cause
|
||||||
|
|
||||||
1. **Check error logs:**
|
1. **Check error logs:**
|
||||||
```bash
|
```bash
|
||||||
pm2 logs claude-mem-worker --err --lines 100 --nostream
|
grep -i "error" ~/.claude-mem/logs/worker-$(date +%Y-%m-%d).log | tail -100
|
||||||
```
|
```
|
||||||
|
|
||||||
2. **Look for crash pattern:**
|
2. **Look for crash pattern:**
|
||||||
```bash
|
```bash
|
||||||
pm2 logs claude-mem-worker --lines 200 --nostream | grep -A 5 "exited with code"
|
grep -A 5 "exited with code" ~/.claude-mem/logs/worker-$(date +%Y-%m-%d).log
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **Run worker in foreground to see crashes:**
|
||||||
|
```bash
|
||||||
|
cd ~/.claude/plugins/marketplaces/thedotmack/
|
||||||
|
bun plugin/scripts/worker-service.js
|
||||||
```
|
```
|
||||||
|
|
||||||
### Common Crash Causes
|
### Common Crash Causes
|
||||||
@@ -246,43 +261,71 @@ If fails, backup and recreate database.
|
|||||||
**Out of memory:**
|
**Out of memory:**
|
||||||
Check if database is too large or memory leak. Restart:
|
Check if database is too large or memory leak. Restart:
|
||||||
```bash
|
```bash
|
||||||
pm2 restart claude-mem-worker
|
npm run worker:restart
|
||||||
```
|
```
|
||||||
|
|
||||||
**Port conflict race condition:**
|
**Port conflict race condition:**
|
||||||
Another process grabbing port intermittently. Change port:
|
Another process grabbing port intermittently. Change port:
|
||||||
```bash
|
```bash
|
||||||
echo '{"env":{"CLAUDE_MEM_WORKER_PORT":"37778"}}' > ~/.claude-mem/settings.json
|
echo '{"CLAUDE_MEM_WORKER_PORT":"37778"}' > ~/.claude-mem/settings.json
|
||||||
pm2 restart claude-mem-worker
|
npm run worker:restart
|
||||||
```
|
```
|
||||||
|
|
||||||
## PM2 Management Commands
|
## Worker Management Commands
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# List processes
|
# Check status
|
||||||
pm2 list
|
npm run worker:status
|
||||||
pm2 jlist # JSON format
|
|
||||||
|
|
||||||
# Show detailed info
|
# Start worker
|
||||||
pm2 show claude-mem-worker
|
npm run worker:start
|
||||||
|
|
||||||
# Monitor resources
|
# Stop worker
|
||||||
pm2 monit
|
npm run worker:stop
|
||||||
|
|
||||||
# Clear logs
|
# Restart worker
|
||||||
pm2 flush claude-mem-worker
|
npm run worker:restart
|
||||||
|
|
||||||
# Restart PM2 daemon
|
# View logs
|
||||||
pm2 kill
|
npm run worker:logs
|
||||||
pm2 resurrect # Restore saved processes
|
|
||||||
|
|
||||||
# Save current process list
|
# Check health endpoint
|
||||||
pm2 save
|
curl -s http://127.0.0.1:37777/health
|
||||||
|
|
||||||
# Update PM2
|
# View PID
|
||||||
npm install -g pm2
|
cat ~/.claude-mem/worker.pid
|
||||||
|
|
||||||
|
# View today's log file
|
||||||
|
cat ~/.claude-mem/logs/worker-$(date +%Y-%m-%d).log
|
||||||
|
|
||||||
|
# List all log files
|
||||||
|
ls -lh ~/.claude-mem/logs/worker-*.log
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Log File Management
|
||||||
|
|
||||||
|
Worker logs are stored in `~/.claude-mem/logs/` with daily rotation:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# View today's log
|
||||||
|
cat ~/.claude-mem/logs/worker-$(date +%Y-%m-%d).log
|
||||||
|
|
||||||
|
# View yesterday's log
|
||||||
|
cat ~/.claude-mem/logs/worker-$(date -d "yesterday" +%Y-%m-%d).log # Linux
|
||||||
|
cat ~/.claude-mem/logs/worker-$(date -v-1d +%Y-%m-%d).log # macOS
|
||||||
|
|
||||||
|
# List all logs
|
||||||
|
ls -lh ~/.claude-mem/logs/
|
||||||
|
|
||||||
|
# Clean old logs (older than 7 days)
|
||||||
|
find ~/.claude-mem/logs/ -name "worker-*.log" -mtime +7 -delete
|
||||||
|
|
||||||
|
# Archive logs
|
||||||
|
tar -czf ~/claude-mem-logs-backup-$(date +%Y-%m-%d).tar.gz ~/.claude-mem/logs/
|
||||||
|
```
|
||||||
|
|
||||||
|
**Note:** Logs auto-rotate daily. No manual flush required.
|
||||||
|
|
||||||
## Testing Worker Endpoints
|
## Testing Worker Endpoints
|
||||||
|
|
||||||
Once worker is running, test all endpoints:
|
Once worker is running, test all endpoints:
|
||||||
@@ -298,10 +341,22 @@ curl -s http://127.0.0.1:37777/ | head -20
|
|||||||
curl -s http://127.0.0.1:37777/api/stats
|
curl -s http://127.0.0.1:37777/api/stats
|
||||||
|
|
||||||
# Search API
|
# Search API
|
||||||
curl -s "http://127.0.0.1:37777/api/search/observations?q=test&format=index"
|
curl -s "http://127.0.0.1:37777/api/search?query=test&limit=5"
|
||||||
|
|
||||||
# Prompts API
|
# Recent context
|
||||||
curl -s "http://127.0.0.1:37777/api/prompts?limit=5"
|
curl -s "http://127.0.0.1:37777/api/context/recent?limit=3"
|
||||||
```
|
```
|
||||||
|
|
||||||
All should return appropriate responses (HTML for viewer, JSON for APIs).
|
All should return appropriate responses (HTML for viewer, JSON for APIs).
|
||||||
|
|
||||||
|
## Troubleshooting Quick Reference
|
||||||
|
|
||||||
|
| Problem | Command | Expected Result |
|
||||||
|
|---------|---------|----------------|
|
||||||
|
| Check if running | `npm run worker:status` | Shows PID and uptime |
|
||||||
|
| Worker not running | `npm run worker:start` | Worker starts successfully |
|
||||||
|
| Worker crashed | `npm run worker:restart` | Worker restarts |
|
||||||
|
| View recent errors | `grep -i error ~/.claude-mem/logs/worker-$(date +%Y-%m-%d).log \| tail -20` | Shows recent errors |
|
||||||
|
| Port in use | `lsof -i :37777` | Shows process using port |
|
||||||
|
| Stale PID | `rm ~/.claude-mem/worker.pid && npm run worker:start` | Removes stale PID and starts |
|
||||||
|
| Dependencies missing | `npm install && npm run worker:start` | Installs deps and starts |
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
#!/usr/bin/env node
|
#!/usr/bin/env node
|
||||||
|
|
||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
import Database from 'better-sqlite3';
|
import { Database } from 'bun:sqlite';
|
||||||
import readline from 'readline';
|
import readline from 'readline';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import { homedir } from 'os';
|
import { homedir } from 'os';
|
||||||
|
|||||||
+12
-27
@@ -5,8 +5,7 @@
|
|||||||
* Example: npx tsx scripts/export-memories.ts "windows" windows-memories.json --project=claude-mem
|
* Example: npx tsx scripts/export-memories.ts "windows" windows-memories.json --project=claude-mem
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import Database from 'better-sqlite3';
|
import { writeFileSync } from 'fs';
|
||||||
import { existsSync, writeFileSync } from 'fs';
|
|
||||||
import { homedir } from 'os';
|
import { homedir } from 'os';
|
||||||
import { join } from 'path';
|
import { join } from 'path';
|
||||||
import { SettingsDefaultsManager } from '../src/shared/SettingsDefaultsManager';
|
import { SettingsDefaultsManager } from '../src/shared/SettingsDefaultsManager';
|
||||||
@@ -127,33 +126,19 @@ async function exportMemories(query: string, outputFile: string, project?: strin
|
|||||||
if (s.sdk_session_id) sdkSessionIds.add(s.sdk_session_id);
|
if (s.sdk_session_id) sdkSessionIds.add(s.sdk_session_id);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Get SDK sessions metadata from database
|
// Get SDK sessions metadata via API
|
||||||
// (We need this because the API doesn't expose sdk_sessions table directly)
|
|
||||||
console.log('📡 Fetching SDK sessions metadata...');
|
console.log('📡 Fetching SDK sessions metadata...');
|
||||||
const sessions: SdkSessionRecord[] = [];
|
let sessions: SdkSessionRecord[] = [];
|
||||||
if (sdkSessionIds.size > 0) {
|
if (sdkSessionIds.size > 0) {
|
||||||
// Read directly from database for sdk_sessions table
|
const sessionsResponse = await fetch(`${baseUrl}/api/sdk-sessions/batch`, {
|
||||||
const Database = (await import('better-sqlite3')).default;
|
method: 'POST',
|
||||||
const dbPath = join(homedir(), '.claude-mem', 'claude-mem.db');
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify({ sdkSessionIds: Array.from(sdkSessionIds) })
|
||||||
if (!existsSync(dbPath)) {
|
});
|
||||||
console.error(`❌ Database not found at: ${dbPath}`);
|
if (sessionsResponse.ok) {
|
||||||
console.error('💡 Has claude-mem been initialized? Try running a session first.');
|
sessions = await sessionsResponse.json();
|
||||||
process.exit(1);
|
} else {
|
||||||
}
|
console.warn(`⚠️ Failed to fetch SDK sessions: ${sessionsResponse.status}`);
|
||||||
|
|
||||||
const db = new Database(dbPath, { readonly: true });
|
|
||||||
|
|
||||||
try {
|
|
||||||
const placeholders = Array.from(sdkSessionIds).map(() => '?').join(',');
|
|
||||||
const sessionQuery = `
|
|
||||||
SELECT * FROM sdk_sessions
|
|
||||||
WHERE sdk_session_id IN (${placeholders})
|
|
||||||
ORDER BY started_at_epoch DESC
|
|
||||||
`;
|
|
||||||
sessions.push(...db.prepare(sessionQuery).all(...Array.from(sdkSessionIds)));
|
|
||||||
} finally {
|
|
||||||
db.close();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
console.log(`✅ Found ${sessions.length} SDK sessions`);
|
console.log(`✅ Found ${sessions.length} SDK sessions`);
|
||||||
|
|||||||
+36
-192
@@ -3,37 +3,21 @@
|
|||||||
* Import memories from a JSON export file with duplicate prevention
|
* Import memories from a JSON export file with duplicate prevention
|
||||||
* Usage: npx tsx scripts/import-memories.ts <input-file>
|
* Usage: npx tsx scripts/import-memories.ts <input-file>
|
||||||
* Example: npx tsx scripts/import-memories.ts windows-memories.json
|
* Example: npx tsx scripts/import-memories.ts windows-memories.json
|
||||||
|
*
|
||||||
|
* This script uses the worker API instead of direct database access.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import Database from 'better-sqlite3';
|
|
||||||
import { existsSync, readFileSync } from 'fs';
|
import { existsSync, readFileSync } from 'fs';
|
||||||
import { homedir } from 'os';
|
|
||||||
import { join } from 'path';
|
|
||||||
|
|
||||||
interface ImportStats {
|
const WORKER_PORT = process.env.CLAUDE_MEM_WORKER_PORT || 37777;
|
||||||
sessionsImported: number;
|
const WORKER_URL = `http://127.0.0.1:${WORKER_PORT}`;
|
||||||
sessionsSkipped: number;
|
|
||||||
summariesImported: number;
|
|
||||||
summariesSkipped: number;
|
|
||||||
observationsImported: number;
|
|
||||||
observationsSkipped: number;
|
|
||||||
promptsImported: number;
|
|
||||||
promptsSkipped: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
function importMemories(inputFile: string) {
|
async function importMemories(inputFile: string) {
|
||||||
if (!existsSync(inputFile)) {
|
if (!existsSync(inputFile)) {
|
||||||
console.error(`❌ Input file not found: ${inputFile}`);
|
console.error(`❌ Input file not found: ${inputFile}`);
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
const dbPath = join(homedir(), '.claude-mem', 'claude-mem.db');
|
|
||||||
|
|
||||||
if (!existsSync(dbPath)) {
|
|
||||||
console.error(`❌ Database not found at: ${dbPath}`);
|
|
||||||
process.exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read and parse export file
|
// Read and parse export file
|
||||||
const exportData = JSON.parse(readFileSync(inputFile, 'utf-8'));
|
const exportData = JSON.parse(readFileSync(inputFile, 'utf-8'));
|
||||||
|
|
||||||
@@ -47,179 +31,43 @@ function importMemories(inputFile: string) {
|
|||||||
console.log(` • ${exportData.totalPrompts} prompts`);
|
console.log(` • ${exportData.totalPrompts} prompts`);
|
||||||
console.log('');
|
console.log('');
|
||||||
|
|
||||||
const db = new Database(dbPath);
|
// Check if worker is running
|
||||||
const stats: ImportStats = {
|
|
||||||
sessionsImported: 0,
|
|
||||||
sessionsSkipped: 0,
|
|
||||||
summariesImported: 0,
|
|
||||||
summariesSkipped: 0,
|
|
||||||
observationsImported: 0,
|
|
||||||
observationsSkipped: 0,
|
|
||||||
promptsImported: 0,
|
|
||||||
promptsSkipped: 0
|
|
||||||
};
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Prepare statements for duplicate checking
|
const healthCheck = await fetch(`${WORKER_URL}/api/stats`);
|
||||||
const checkSession = db.prepare('SELECT id FROM sdk_sessions WHERE claude_session_id = ?');
|
if (!healthCheck.ok) {
|
||||||
const checkSummary = db.prepare('SELECT id FROM session_summaries WHERE sdk_session_id = ?');
|
throw new Error('Worker not responding');
|
||||||
const checkObservation = db.prepare(`
|
}
|
||||||
SELECT id FROM observations
|
} catch (error) {
|
||||||
WHERE sdk_session_id = ?
|
console.error(`❌ Worker not running at ${WORKER_URL}`);
|
||||||
AND title = ?
|
console.error(' Please ensure the claude-mem worker is running.');
|
||||||
AND created_at_epoch = ?
|
process.exit(1);
|
||||||
`);
|
|
||||||
const checkPrompt = db.prepare(`
|
|
||||||
SELECT id FROM user_prompts
|
|
||||||
WHERE claude_session_id = ?
|
|
||||||
AND prompt_number = ?
|
|
||||||
`);
|
|
||||||
|
|
||||||
// Prepare insert statements
|
|
||||||
const insertSession = db.prepare(`
|
|
||||||
INSERT INTO sdk_sessions (
|
|
||||||
claude_session_id, sdk_session_id, project, user_prompt,
|
|
||||||
started_at, started_at_epoch, completed_at, completed_at_epoch,
|
|
||||||
status
|
|
||||||
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
||||||
`);
|
|
||||||
|
|
||||||
const insertSummary = db.prepare(`
|
|
||||||
INSERT INTO session_summaries (
|
|
||||||
sdk_session_id, project, request, investigated, learned,
|
|
||||||
completed, next_steps, files_read, files_edited, notes,
|
|
||||||
prompt_number, discovery_tokens, created_at, created_at_epoch
|
|
||||||
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
||||||
`);
|
|
||||||
|
|
||||||
const insertObservation = db.prepare(`
|
|
||||||
INSERT INTO observations (
|
|
||||||
sdk_session_id, project, text, type, title, subtitle,
|
|
||||||
facts, narrative, concepts, files_read, files_modified,
|
|
||||||
prompt_number, discovery_tokens, created_at, created_at_epoch
|
|
||||||
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
||||||
`);
|
|
||||||
|
|
||||||
const insertPrompt = db.prepare(`
|
|
||||||
INSERT INTO user_prompts (
|
|
||||||
claude_session_id, prompt_number, prompt_text,
|
|
||||||
created_at, created_at_epoch
|
|
||||||
) VALUES (?, ?, ?, ?, ?)
|
|
||||||
`);
|
|
||||||
|
|
||||||
// Import in transaction
|
|
||||||
db.transaction(() => {
|
|
||||||
// 1. Import sessions first (dependency for everything else)
|
|
||||||
console.log('🔄 Importing sessions...');
|
|
||||||
for (const session of exportData.sessions) {
|
|
||||||
const exists = checkSession.get(session.claude_session_id);
|
|
||||||
if (exists) {
|
|
||||||
stats.sessionsSkipped++;
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
insertSession.run(
|
console.log('🔄 Importing via worker API...');
|
||||||
session.claude_session_id,
|
|
||||||
session.sdk_session_id,
|
|
||||||
session.project,
|
|
||||||
session.user_prompt,
|
|
||||||
session.started_at,
|
|
||||||
session.started_at_epoch,
|
|
||||||
session.completed_at,
|
|
||||||
session.completed_at_epoch,
|
|
||||||
session.status
|
|
||||||
);
|
|
||||||
stats.sessionsImported++;
|
|
||||||
}
|
|
||||||
console.log(` ✅ Imported: ${stats.sessionsImported}, Skipped: ${stats.sessionsSkipped}`);
|
|
||||||
|
|
||||||
// 2. Import summaries (depends on sessions)
|
// Send import request to worker
|
||||||
console.log('🔄 Importing summaries...');
|
const response = await fetch(`${WORKER_URL}/api/import`, {
|
||||||
for (const summary of exportData.summaries) {
|
method: 'POST',
|
||||||
const exists = checkSummary.get(summary.sdk_session_id);
|
headers: {
|
||||||
if (exists) {
|
'Content-Type': 'application/json'
|
||||||
stats.summariesSkipped++;
|
},
|
||||||
continue;
|
body: JSON.stringify({
|
||||||
|
sessions: exportData.sessions || [],
|
||||||
|
summaries: exportData.summaries || [],
|
||||||
|
observations: exportData.observations || [],
|
||||||
|
prompts: exportData.prompts || []
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
const errorText = await response.text();
|
||||||
|
console.error(`❌ Import failed: ${response.status} ${response.statusText}`);
|
||||||
|
console.error(` ${errorText}`);
|
||||||
|
process.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
insertSummary.run(
|
const result = await response.json();
|
||||||
summary.sdk_session_id,
|
const stats = result.stats;
|
||||||
summary.project,
|
|
||||||
summary.request,
|
|
||||||
summary.investigated,
|
|
||||||
summary.learned,
|
|
||||||
summary.completed,
|
|
||||||
summary.next_steps,
|
|
||||||
summary.files_read,
|
|
||||||
summary.files_edited,
|
|
||||||
summary.notes,
|
|
||||||
summary.prompt_number,
|
|
||||||
summary.discovery_tokens || 0,
|
|
||||||
summary.created_at,
|
|
||||||
summary.created_at_epoch
|
|
||||||
);
|
|
||||||
stats.summariesImported++;
|
|
||||||
}
|
|
||||||
console.log(` ✅ Imported: ${stats.summariesImported}, Skipped: ${stats.summariesSkipped}`);
|
|
||||||
|
|
||||||
// 3. Import observations (depends on sessions)
|
|
||||||
console.log('🔄 Importing observations...');
|
|
||||||
for (const obs of exportData.observations) {
|
|
||||||
const exists = checkObservation.get(
|
|
||||||
obs.sdk_session_id,
|
|
||||||
obs.title,
|
|
||||||
obs.created_at_epoch
|
|
||||||
);
|
|
||||||
if (exists) {
|
|
||||||
stats.observationsSkipped++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
insertObservation.run(
|
|
||||||
obs.sdk_session_id,
|
|
||||||
obs.project,
|
|
||||||
obs.text,
|
|
||||||
obs.type,
|
|
||||||
obs.title,
|
|
||||||
obs.subtitle,
|
|
||||||
obs.facts,
|
|
||||||
obs.narrative,
|
|
||||||
obs.concepts,
|
|
||||||
obs.files_read,
|
|
||||||
obs.files_modified,
|
|
||||||
obs.prompt_number,
|
|
||||||
obs.discovery_tokens || 0,
|
|
||||||
obs.created_at,
|
|
||||||
obs.created_at_epoch
|
|
||||||
);
|
|
||||||
stats.observationsImported++;
|
|
||||||
}
|
|
||||||
console.log(` ✅ Imported: ${stats.observationsImported}, Skipped: ${stats.observationsSkipped}`);
|
|
||||||
|
|
||||||
// 4. Import prompts (depends on sessions)
|
|
||||||
console.log('🔄 Importing prompts...');
|
|
||||||
for (const prompt of exportData.prompts) {
|
|
||||||
const exists = checkPrompt.get(
|
|
||||||
prompt.claude_session_id,
|
|
||||||
prompt.prompt_number
|
|
||||||
);
|
|
||||||
if (exists) {
|
|
||||||
stats.promptsSkipped++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
insertPrompt.run(
|
|
||||||
prompt.claude_session_id,
|
|
||||||
prompt.prompt_number,
|
|
||||||
prompt.prompt_text,
|
|
||||||
prompt.created_at,
|
|
||||||
prompt.created_at_epoch
|
|
||||||
);
|
|
||||||
stats.promptsImported++;
|
|
||||||
}
|
|
||||||
console.log(` ✅ Imported: ${stats.promptsImported}, Skipped: ${stats.promptsSkipped}`);
|
|
||||||
|
|
||||||
})();
|
|
||||||
|
|
||||||
console.log('\n✅ Import complete!');
|
console.log('\n✅ Import complete!');
|
||||||
console.log('📊 Summary:');
|
console.log('📊 Summary:');
|
||||||
@@ -227,10 +75,6 @@ function importMemories(inputFile: string) {
|
|||||||
console.log(` Summaries: ${stats.summariesImported} imported, ${stats.summariesSkipped} skipped`);
|
console.log(` Summaries: ${stats.summariesImported} imported, ${stats.summariesSkipped} skipped`);
|
||||||
console.log(` Observations: ${stats.observationsImported} imported, ${stats.observationsSkipped} skipped`);
|
console.log(` Observations: ${stats.observationsImported} imported, ${stats.observationsSkipped} skipped`);
|
||||||
console.log(` Prompts: ${stats.promptsImported} imported, ${stats.promptsSkipped} skipped`);
|
console.log(` Prompts: ${stats.promptsImported} imported, ${stats.promptsSkipped} skipped`);
|
||||||
|
|
||||||
} finally {
|
|
||||||
db.close();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// CLI interface
|
// CLI interface
|
||||||
|
|||||||
@@ -1039,6 +1039,36 @@ export class SessionStore {
|
|||||||
return stmt.get(id) || null;
|
return stmt.get(id) || null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get SDK sessions by SDK session IDs
|
||||||
|
* Used for exporting session metadata
|
||||||
|
*/
|
||||||
|
getSdkSessionsBySessionIds(sdkSessionIds: string[]): {
|
||||||
|
id: number;
|
||||||
|
claude_session_id: string;
|
||||||
|
sdk_session_id: string;
|
||||||
|
project: string;
|
||||||
|
user_prompt: string;
|
||||||
|
started_at: string;
|
||||||
|
started_at_epoch: number;
|
||||||
|
completed_at: string | null;
|
||||||
|
completed_at_epoch: number | null;
|
||||||
|
status: string;
|
||||||
|
}[] {
|
||||||
|
if (sdkSessionIds.length === 0) return [];
|
||||||
|
|
||||||
|
const placeholders = sdkSessionIds.map(() => '?').join(',');
|
||||||
|
const stmt = this.db.prepare(`
|
||||||
|
SELECT id, claude_session_id, sdk_session_id, project, user_prompt,
|
||||||
|
started_at, started_at_epoch, completed_at, completed_at_epoch, status
|
||||||
|
FROM sdk_sessions
|
||||||
|
WHERE sdk_session_id IN (${placeholders})
|
||||||
|
ORDER BY started_at_epoch DESC
|
||||||
|
`);
|
||||||
|
|
||||||
|
return stmt.all(...sdkSessionIds) as any[];
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Find active SDK session for a Claude session
|
* Find active SDK session for a Claude session
|
||||||
*/
|
*/
|
||||||
@@ -1795,4 +1825,212 @@ export class SessionStore {
|
|||||||
close(): void {
|
close(): void {
|
||||||
this.db.close();
|
this.db.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ===========================================
|
||||||
|
// Import Methods (for import-memories script)
|
||||||
|
// ===========================================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Import SDK session with duplicate checking
|
||||||
|
* Returns: { imported: boolean, id: number }
|
||||||
|
*/
|
||||||
|
importSdkSession(session: {
|
||||||
|
claude_session_id: string;
|
||||||
|
sdk_session_id: string;
|
||||||
|
project: string;
|
||||||
|
user_prompt: string;
|
||||||
|
started_at: string;
|
||||||
|
started_at_epoch: number;
|
||||||
|
completed_at: string | null;
|
||||||
|
completed_at_epoch: number | null;
|
||||||
|
status: string;
|
||||||
|
}): { imported: boolean; id: number } {
|
||||||
|
// Check if session already exists
|
||||||
|
const existing = this.db.prepare(
|
||||||
|
'SELECT id FROM sdk_sessions WHERE claude_session_id = ?'
|
||||||
|
).get(session.claude_session_id) as { id: number } | undefined;
|
||||||
|
|
||||||
|
if (existing) {
|
||||||
|
return { imported: false, id: existing.id };
|
||||||
|
}
|
||||||
|
|
||||||
|
const stmt = this.db.prepare(`
|
||||||
|
INSERT INTO sdk_sessions (
|
||||||
|
claude_session_id, sdk_session_id, project, user_prompt,
|
||||||
|
started_at, started_at_epoch, completed_at, completed_at_epoch, status
|
||||||
|
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||||
|
`);
|
||||||
|
|
||||||
|
const result = stmt.run(
|
||||||
|
session.claude_session_id,
|
||||||
|
session.sdk_session_id,
|
||||||
|
session.project,
|
||||||
|
session.user_prompt,
|
||||||
|
session.started_at,
|
||||||
|
session.started_at_epoch,
|
||||||
|
session.completed_at,
|
||||||
|
session.completed_at_epoch,
|
||||||
|
session.status
|
||||||
|
);
|
||||||
|
|
||||||
|
return { imported: true, id: result.lastInsertRowid as number };
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Import session summary with duplicate checking
|
||||||
|
* Returns: { imported: boolean, id: number }
|
||||||
|
*/
|
||||||
|
importSessionSummary(summary: {
|
||||||
|
sdk_session_id: string;
|
||||||
|
project: string;
|
||||||
|
request: string | null;
|
||||||
|
investigated: string | null;
|
||||||
|
learned: string | null;
|
||||||
|
completed: string | null;
|
||||||
|
next_steps: string | null;
|
||||||
|
files_read: string | null;
|
||||||
|
files_edited: string | null;
|
||||||
|
notes: string | null;
|
||||||
|
prompt_number: number | null;
|
||||||
|
discovery_tokens: number;
|
||||||
|
created_at: string;
|
||||||
|
created_at_epoch: number;
|
||||||
|
}): { imported: boolean; id: number } {
|
||||||
|
// Check if summary already exists for this session
|
||||||
|
const existing = this.db.prepare(
|
||||||
|
'SELECT id FROM session_summaries WHERE sdk_session_id = ?'
|
||||||
|
).get(summary.sdk_session_id) as { id: number } | undefined;
|
||||||
|
|
||||||
|
if (existing) {
|
||||||
|
return { imported: false, id: existing.id };
|
||||||
|
}
|
||||||
|
|
||||||
|
const stmt = this.db.prepare(`
|
||||||
|
INSERT INTO session_summaries (
|
||||||
|
sdk_session_id, project, request, investigated, learned,
|
||||||
|
completed, next_steps, files_read, files_edited, notes,
|
||||||
|
prompt_number, discovery_tokens, created_at, created_at_epoch
|
||||||
|
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||||
|
`);
|
||||||
|
|
||||||
|
const result = stmt.run(
|
||||||
|
summary.sdk_session_id,
|
||||||
|
summary.project,
|
||||||
|
summary.request,
|
||||||
|
summary.investigated,
|
||||||
|
summary.learned,
|
||||||
|
summary.completed,
|
||||||
|
summary.next_steps,
|
||||||
|
summary.files_read,
|
||||||
|
summary.files_edited,
|
||||||
|
summary.notes,
|
||||||
|
summary.prompt_number,
|
||||||
|
summary.discovery_tokens || 0,
|
||||||
|
summary.created_at,
|
||||||
|
summary.created_at_epoch
|
||||||
|
);
|
||||||
|
|
||||||
|
return { imported: true, id: result.lastInsertRowid as number };
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Import observation with duplicate checking
|
||||||
|
* Duplicates are identified by sdk_session_id + title + created_at_epoch
|
||||||
|
* Returns: { imported: boolean, id: number }
|
||||||
|
*/
|
||||||
|
importObservation(obs: {
|
||||||
|
sdk_session_id: string;
|
||||||
|
project: string;
|
||||||
|
text: string | null;
|
||||||
|
type: string;
|
||||||
|
title: string | null;
|
||||||
|
subtitle: string | null;
|
||||||
|
facts: string | null;
|
||||||
|
narrative: string | null;
|
||||||
|
concepts: string | null;
|
||||||
|
files_read: string | null;
|
||||||
|
files_modified: string | null;
|
||||||
|
prompt_number: number | null;
|
||||||
|
discovery_tokens: number;
|
||||||
|
created_at: string;
|
||||||
|
created_at_epoch: number;
|
||||||
|
}): { imported: boolean; id: number } {
|
||||||
|
// Check if observation already exists
|
||||||
|
const existing = this.db.prepare(`
|
||||||
|
SELECT id FROM observations
|
||||||
|
WHERE sdk_session_id = ? AND title = ? AND created_at_epoch = ?
|
||||||
|
`).get(obs.sdk_session_id, obs.title, obs.created_at_epoch) as { id: number } | undefined;
|
||||||
|
|
||||||
|
if (existing) {
|
||||||
|
return { imported: false, id: existing.id };
|
||||||
|
}
|
||||||
|
|
||||||
|
const stmt = this.db.prepare(`
|
||||||
|
INSERT INTO observations (
|
||||||
|
sdk_session_id, project, text, type, title, subtitle,
|
||||||
|
facts, narrative, concepts, files_read, files_modified,
|
||||||
|
prompt_number, discovery_tokens, created_at, created_at_epoch
|
||||||
|
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||||
|
`);
|
||||||
|
|
||||||
|
const result = stmt.run(
|
||||||
|
obs.sdk_session_id,
|
||||||
|
obs.project,
|
||||||
|
obs.text,
|
||||||
|
obs.type,
|
||||||
|
obs.title,
|
||||||
|
obs.subtitle,
|
||||||
|
obs.facts,
|
||||||
|
obs.narrative,
|
||||||
|
obs.concepts,
|
||||||
|
obs.files_read,
|
||||||
|
obs.files_modified,
|
||||||
|
obs.prompt_number,
|
||||||
|
obs.discovery_tokens || 0,
|
||||||
|
obs.created_at,
|
||||||
|
obs.created_at_epoch
|
||||||
|
);
|
||||||
|
|
||||||
|
return { imported: true, id: result.lastInsertRowid as number };
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Import user prompt with duplicate checking
|
||||||
|
* Duplicates are identified by claude_session_id + prompt_number
|
||||||
|
* Returns: { imported: boolean, id: number }
|
||||||
|
*/
|
||||||
|
importUserPrompt(prompt: {
|
||||||
|
claude_session_id: string;
|
||||||
|
prompt_number: number;
|
||||||
|
prompt_text: string;
|
||||||
|
created_at: string;
|
||||||
|
created_at_epoch: number;
|
||||||
|
}): { imported: boolean; id: number } {
|
||||||
|
// Check if prompt already exists
|
||||||
|
const existing = this.db.prepare(`
|
||||||
|
SELECT id FROM user_prompts
|
||||||
|
WHERE claude_session_id = ? AND prompt_number = ?
|
||||||
|
`).get(prompt.claude_session_id, prompt.prompt_number) as { id: number } | undefined;
|
||||||
|
|
||||||
|
if (existing) {
|
||||||
|
return { imported: false, id: existing.id };
|
||||||
|
}
|
||||||
|
|
||||||
|
const stmt = this.db.prepare(`
|
||||||
|
INSERT INTO user_prompts (
|
||||||
|
claude_session_id, prompt_number, prompt_text,
|
||||||
|
created_at, created_at_epoch
|
||||||
|
) VALUES (?, ?, ?, ?, ?)
|
||||||
|
`);
|
||||||
|
|
||||||
|
const result = stmt.run(
|
||||||
|
prompt.claude_session_id,
|
||||||
|
prompt.prompt_number,
|
||||||
|
prompt.prompt_text,
|
||||||
|
prompt.created_at,
|
||||||
|
prompt.created_at_epoch
|
||||||
|
);
|
||||||
|
|
||||||
|
return { imported: true, id: result.lastInsertRowid as number };
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -87,7 +87,7 @@ export class SearchManager {
|
|||||||
try {
|
try {
|
||||||
// Normalize URL-friendly params to internal format
|
// Normalize URL-friendly params to internal format
|
||||||
const normalized = this.normalizeParams(args);
|
const normalized = this.normalizeParams(args);
|
||||||
const { query, type, obs_type, concepts, files, ...options } = normalized;
|
const { query, type, obs_type, concepts, files, format, ...options } = normalized;
|
||||||
let observations: ObservationSearchResult[] = [];
|
let observations: ObservationSearchResult[] = [];
|
||||||
let sessions: SessionSummarySearchResult[] = [];
|
let sessions: SessionSummarySearchResult[] = [];
|
||||||
let prompts: UserPromptSearchResult[] = [];
|
let prompts: UserPromptSearchResult[] = [];
|
||||||
@@ -200,6 +200,17 @@ export class SearchManager {
|
|||||||
|
|
||||||
const totalResults = observations.length + sessions.length + prompts.length;
|
const totalResults = observations.length + sessions.length + prompts.length;
|
||||||
|
|
||||||
|
// JSON format: return raw data for programmatic access (e.g., export scripts)
|
||||||
|
if (format === 'json') {
|
||||||
|
return {
|
||||||
|
observations,
|
||||||
|
sessions,
|
||||||
|
prompts,
|
||||||
|
totalResults,
|
||||||
|
query: query || ''
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
if (totalResults === 0) {
|
if (totalResults === 0) {
|
||||||
return {
|
return {
|
||||||
content: [{
|
content: [{
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ export class DataRoutes extends BaseRouteHandler {
|
|||||||
app.get('/api/observation/:id', this.handleGetObservationById.bind(this));
|
app.get('/api/observation/:id', this.handleGetObservationById.bind(this));
|
||||||
app.post('/api/observations/batch', this.handleGetObservationsByIds.bind(this));
|
app.post('/api/observations/batch', this.handleGetObservationsByIds.bind(this));
|
||||||
app.get('/api/session/:id', this.handleGetSessionById.bind(this));
|
app.get('/api/session/:id', this.handleGetSessionById.bind(this));
|
||||||
|
app.post('/api/sdk-sessions/batch', this.handleGetSdkSessionsByIds.bind(this));
|
||||||
app.get('/api/prompt/:id', this.handleGetPromptById.bind(this));
|
app.get('/api/prompt/:id', this.handleGetPromptById.bind(this));
|
||||||
|
|
||||||
// Metadata endpoints
|
// Metadata endpoints
|
||||||
@@ -49,6 +50,9 @@ export class DataRoutes extends BaseRouteHandler {
|
|||||||
// Processing status endpoints
|
// Processing status endpoints
|
||||||
app.get('/api/processing-status', this.handleGetProcessingStatus.bind(this));
|
app.get('/api/processing-status', this.handleGetProcessingStatus.bind(this));
|
||||||
app.post('/api/processing', this.handleSetProcessing.bind(this));
|
app.post('/api/processing', this.handleSetProcessing.bind(this));
|
||||||
|
|
||||||
|
// Import endpoint
|
||||||
|
app.post('/api/import', this.handleImport.bind(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -146,6 +150,24 @@ export class DataRoutes extends BaseRouteHandler {
|
|||||||
res.json(sessions[0]);
|
res.json(sessions[0]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get SDK sessions by SDK session IDs
|
||||||
|
* POST /api/sdk-sessions/batch
|
||||||
|
* Body: { sdkSessionIds: string[] }
|
||||||
|
*/
|
||||||
|
private handleGetSdkSessionsByIds = this.wrapHandler((req: Request, res: Response): void => {
|
||||||
|
const { sdkSessionIds } = req.body;
|
||||||
|
|
||||||
|
if (!Array.isArray(sdkSessionIds)) {
|
||||||
|
this.badRequest(res, 'sdkSessionIds must be an array');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const store = this.dbManager.getSessionStore();
|
||||||
|
const sessions = store.getSdkSessionsBySessionIds(sdkSessionIds);
|
||||||
|
res.json(sessions);
|
||||||
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get user prompt by ID
|
* Get user prompt by ID
|
||||||
* GET /api/prompt/:id
|
* GET /api/prompt/:id
|
||||||
@@ -267,4 +289,79 @@ export class DataRoutes extends BaseRouteHandler {
|
|||||||
|
|
||||||
return { offset, limit, project };
|
return { offset, limit, project };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Import memories from export file
|
||||||
|
* POST /api/import
|
||||||
|
* Body: { sessions: [], summaries: [], observations: [], prompts: [] }
|
||||||
|
*/
|
||||||
|
private handleImport = this.wrapHandler((req: Request, res: Response): void => {
|
||||||
|
const { sessions, summaries, observations, prompts } = req.body;
|
||||||
|
|
||||||
|
const stats = {
|
||||||
|
sessionsImported: 0,
|
||||||
|
sessionsSkipped: 0,
|
||||||
|
summariesImported: 0,
|
||||||
|
summariesSkipped: 0,
|
||||||
|
observationsImported: 0,
|
||||||
|
observationsSkipped: 0,
|
||||||
|
promptsImported: 0,
|
||||||
|
promptsSkipped: 0
|
||||||
|
};
|
||||||
|
|
||||||
|
const store = this.dbManager.getSessionStore();
|
||||||
|
|
||||||
|
// Import sessions first (dependency for everything else)
|
||||||
|
if (Array.isArray(sessions)) {
|
||||||
|
for (const session of sessions) {
|
||||||
|
const result = store.importSdkSession(session);
|
||||||
|
if (result.imported) {
|
||||||
|
stats.sessionsImported++;
|
||||||
|
} else {
|
||||||
|
stats.sessionsSkipped++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Import summaries (depends on sessions)
|
||||||
|
if (Array.isArray(summaries)) {
|
||||||
|
for (const summary of summaries) {
|
||||||
|
const result = store.importSessionSummary(summary);
|
||||||
|
if (result.imported) {
|
||||||
|
stats.summariesImported++;
|
||||||
|
} else {
|
||||||
|
stats.summariesSkipped++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Import observations (depends on sessions)
|
||||||
|
if (Array.isArray(observations)) {
|
||||||
|
for (const obs of observations) {
|
||||||
|
const result = store.importObservation(obs);
|
||||||
|
if (result.imported) {
|
||||||
|
stats.observationsImported++;
|
||||||
|
} else {
|
||||||
|
stats.observationsSkipped++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Import prompts (depends on sessions)
|
||||||
|
if (Array.isArray(prompts)) {
|
||||||
|
for (const prompt of prompts) {
|
||||||
|
const result = store.importUserPrompt(prompt);
|
||||||
|
if (result.imported) {
|
||||||
|
stats.promptsImported++;
|
||||||
|
} else {
|
||||||
|
stats.promptsSkipped++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
res.json({
|
||||||
|
success: true,
|
||||||
|
stats
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user