Files
claude-mem/src/hooks/new.ts
T
Alex Newman 115270c35e feat: Implement session management and search functionality
- Added SDK session, observation, and summary types to types.ts.
- Refactored worker-service to use SessionStore for session management.
- Created SessionSearch class for FTS5 full-text search and structured queries.
- Implemented SessionStore for CRUD operations on SDK sessions, observations, and summaries.
- Added migrations for database schema updates, including new columns and constraints.
- Enhanced search capabilities with filters for projects, types, concepts, and date ranges.
2025-10-18 20:15:55 -04:00

111 lines
3.6 KiB
TypeScript

import path from 'path';
import { SessionStore } from '../services/sqlite/SessionStore.js';
import { createHookResponse } from './hook-response.js';
export interface UserPromptSubmitInput {
session_id: string;
cwd: string;
prompt: string;
[key: string]: any;
}
/**
* Get worker service port from file
*/
async function getWorkerPort(): Promise<number | null> {
const { readFileSync, existsSync } = await import('fs');
const { join } = await import('path');
const { homedir } = await import('os');
const portFile = join(homedir(), '.claude-mem', 'worker.port');
if (!existsSync(portFile)) {
return null;
}
try {
const portStr = readFileSync(portFile, 'utf8').trim();
return parseInt(portStr, 10);
} catch {
return null;
}
}
/**
* New Hook - UserPromptSubmit
* Initializes SDK memory session via HTTP POST to worker service
*/
export async function newHook(input?: UserPromptSubmitInput): Promise<void> {
if (!input) {
throw new Error('newHook requires input');
}
const { session_id, cwd, prompt } = input;
const project = path.basename(cwd);
const db = new SessionStore();
try {
// Check for any existing session (active, failed, or completed)
let existing = db.findActiveSDKSession(session_id);
let sessionDbId: number;
let isNewSession = false;
if (existing) {
// Session already active, increment prompt counter
sessionDbId = existing.id;
const promptNumber = db.incrementPromptCounter(sessionDbId);
console.error(`[new-hook] Continuing session ${sessionDbId}, prompt #${promptNumber}`);
} else {
// Check for inactive sessions we can reuse
const inactive = db.findAnySDKSession(session_id);
if (inactive) {
// Reactivate the existing session
sessionDbId = inactive.id;
db.reactivateSession(sessionDbId, prompt);
const promptNumber = db.incrementPromptCounter(sessionDbId);
isNewSession = true;
console.error(`[new-hook] Reactivated session ${sessionDbId}, prompt #${promptNumber}`);
} else {
// Create new session
sessionDbId = db.createSDKSession(session_id, project, prompt);
const promptNumber = db.incrementPromptCounter(sessionDbId);
isNewSession = true;
console.error(`[new-hook] Created new session ${sessionDbId}, prompt #${promptNumber}`);
}
}
// Find worker service port
const port = await getWorkerPort();
if (!port) {
console.error('[new-hook] Worker service not running. Start with: npm run worker:start');
console.log(createHookResponse('UserPromptSubmit', true)); // Don't block Claude
return;
}
// Only initialize worker on new sessions
if (isNewSession) {
// Initialize session via HTTP
const response = await fetch(`http://127.0.0.1:${port}/sessions/${sessionDbId}/init`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ project, userPrompt: prompt }),
signal: AbortSignal.timeout(5000)
});
if (!response.ok) {
console.error('[new-hook] Failed to init session:', await response.text());
}
}
console.log(createHookResponse('UserPromptSubmit', true));
} catch (error: any) {
console.error('[new-hook] FATAL ERROR:', error.message);
console.error('[new-hook] Stack:', error.stack);
console.error('[new-hook] Full error:', JSON.stringify(error, Object.getOwnPropertyNames(error)));
console.log(createHookResponse('UserPromptSubmit', true)); // Don't block Claude
} finally {
db.close();
}
}