feat: Release v4.0.0 - Plugin data directory and auto-starting worker

BREAKING CHANGES:
- Data directory moved from ~/.claude-mem/ to ${CLAUDE_PLUGIN_ROOT}/data/
- Fresh start required - no migration from v3.x databases
- Worker service now auto-starts on SessionStart hook

New Features:
- MCP Search Server with 6 specialized search tools
- FTS5 full-text search across observations and sessions
- Auto-starting worker service in SessionStart hook
- Citation support for search results (claude-mem:// URIs)

Changes:
- Updated paths.ts to use CLAUDE_PLUGIN_ROOT for data directory
- Added worker auto-start logic to context hook
- Updated worker service to write port file to plugin data dir
- Bumped version to 4.0.0 in package.json and plugin.json
- Created comprehensive CHANGELOG.md documenting v4.0.0 changes
- Updated README.md with v4.0.0 breaking changes and features
- Rebuilt all hooks and worker service

Technical Improvements:
- Improved error handling and graceful degradation
- Structured logging across all components
- Enhanced plugin integration with Claude Code

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Alex Newman
2025-10-19 00:05:56 -04:00
parent 6d68fd44ca
commit 002f7a94b8
16 changed files with 382 additions and 465 deletions
+60
View File
@@ -1,5 +1,8 @@
import path from 'path';
import { existsSync } from 'fs';
import { spawn } from 'child_process';
import { SessionStore } from '../services/sqlite/SessionStore.js';
import { getWorkerPortFilePath, getPackageRoot } from '../shared/paths.js';
export interface SessionStartInput {
session_id?: string;
@@ -10,6 +13,61 @@ export interface SessionStartInput {
[key: string]: any;
}
/**
* Ensure worker service is running
* Auto-starts worker if not running (v4.0.0 feature)
*/
function ensureWorkerRunning(): void {
try {
const portFile = getWorkerPortFilePath();
// Check if worker is already running
if (existsSync(portFile)) {
// Worker appears to be running (port file exists)
return;
}
console.error('[claude-mem] Worker not running, starting...');
// Find worker service path
const packageRoot = getPackageRoot();
const workerPath = path.join(packageRoot, 'dist', 'worker-service.cjs');
if (!existsSync(workerPath)) {
console.error(`[claude-mem] Worker service not found at ${workerPath}`);
return;
}
// Try to start with PM2 first (preferred for production)
const ecosystemPath = path.join(packageRoot, 'ecosystem.config.cjs');
if (existsSync(ecosystemPath)) {
try {
spawn('pm2', ['start', ecosystemPath], {
detached: true,
stdio: 'ignore',
cwd: packageRoot
}).unref();
console.error('[claude-mem] Worker started with PM2');
return;
} catch (pm2Error) {
console.error('[claude-mem] PM2 not available, using direct spawn');
}
}
// Fallback: spawn worker directly
spawn('node', [workerPath], {
detached: true,
stdio: 'ignore',
env: { ...process.env, NODE_ENV: 'production' }
}).unref();
console.error('[claude-mem] Worker started in background');
} catch (error: any) {
// Don't fail the hook if worker start fails
console.error(`[claude-mem] Failed to start worker: ${error.message}`);
}
}
/**
* Context Hook - SessionStart
* Shows user what happened in recent sessions
@@ -17,6 +75,8 @@ export interface SessionStartInput {
* Output: Returns formatted context string to be wrapped in hookSpecificOutput
*/
export function contextHook(input?: SessionStartInput): string {
// v4.0.0: Ensure worker is running before loading context
ensureWorkerRunning();
const cwd = input?.cwd ?? process.cwd();
const project = cwd ? path.basename(cwd) : 'unknown-project';