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:
Alex Newman
2025-12-16 17:57:40 -05:00
committed by GitHub
parent 78cb5c38dc
commit db3794762f
20 changed files with 988 additions and 508 deletions
@@ -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:
+1 -1
View File
@@ -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
+5 -5
View File
@@ -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,21 +81,17 @@ 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"
}
} }
``` ```
@@ -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"
```
+149 -94
View File
@@ -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 -1
View File
@@ -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
View File
@@ -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`);
+47 -203
View File
@@ -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,190 +31,50 @@ 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(
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)
console.log('🔄 Importing summaries...');
for (const summary of exportData.summaries) {
const exists = checkSummary.get(summary.sdk_session_id);
if (exists) {
stats.summariesSkipped++;
continue;
}
insertSummary.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
);
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('📊 Summary:');
console.log(` Sessions: ${stats.sessionsImported} imported, ${stats.sessionsSkipped} skipped`);
console.log(` Summaries: ${stats.summariesImported} imported, ${stats.summariesSkipped} skipped`);
console.log(` Observations: ${stats.observationsImported} imported, ${stats.observationsSkipped} skipped`);
console.log(` Prompts: ${stats.promptsImported} imported, ${stats.promptsSkipped} skipped`);
} finally {
db.close();
} }
console.log('🔄 Importing via worker API...');
// Send import request to worker
const response = await fetch(`${WORKER_URL}/api/import`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
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);
}
const result = await response.json();
const stats = result.stats;
console.log('\n✅ Import complete!');
console.log('📊 Summary:');
console.log(` Sessions: ${stats.sessionsImported} imported, ${stats.sessionsSkipped} skipped`);
console.log(` Summaries: ${stats.summariesImported} imported, ${stats.summariesSkipped} skipped`);
console.log(` Observations: ${stats.observationsImported} imported, ${stats.observationsSkipped} skipped`);
console.log(` Prompts: ${stats.promptsImported} imported, ${stats.promptsSkipped} skipped`);
} }
// CLI interface // CLI interface
+238
View File
@@ -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 };
}
} }
+12 -1
View File
@@ -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
});
});
} }