/**
* DatabaseManager: Single long-lived database connection
*
* Responsibility:
* - Manage single database connection for worker lifetime
* - Provide centralized access to SessionStore and SessionSearch
* - High-level database operations
* - ChromaSync integration
*/
import { SessionStore } from '../storage/DataStore.js';
import { SessionSearch } from '../storage/SessionSearch.js';
import { ChromaSync } from '../vector/VectorSync.js';
import { logger } from '../../utils/logger.js';
import type { DBSession } from '../engine-types.js';
export class DatabaseManager {
private sessionStore: SessionStore | null = null;
private sessionSearch: SessionSearch | null = null;
private chromaSync: ChromaSync | null = null;
/**
* Initialize database connection (once, stays open)
*/
async initialize(): Promise<void> {
// Open database connection (ONCE)
this.sessionStore = new SessionStore();
this.sessionSearch = new SessionSearch();
// Initialize ChromaSync (lazy - connects on first search, not at startup)
this.chromaSync = new ChromaSync('claude-recall');
logger.info('DB', 'Database initialized');
}
/**
* Close database connection and cleanup all resources
*/
async close(): Promise<void> {
// Close ChromaSync first (terminates uvx/python processes)
if (this.chromaSync) {
await this.chromaSync.close();
this.chromaSync = null;
}
if (this.sessionStore) {
this.sessionStore.close();
this.sessionStore = null;
}
if (this.sessionSearch) {
this.sessionSearch.close();
this.sessionSearch = null;
}
logger.info('DB', 'Database closed');
}
/**
* Check if database is initialized
*/
isInitialized(): boolean {
return this.sessionStore !== null;
}
/**
* Get SessionStore instance (throws if not initialized)
*/
getSessionStore(): SessionStore {
if (!this.sessionStore) {
throw new Error('Database not initialized');
}
return this.sessionStore;
}
/**
* Get SessionSearch instance (throws if not initialized)
*/
getSessionSearch(): SessionSearch {
if (!this.sessionSearch) {
throw new Error('Database not initialized');
}
return this.sessionSearch;
}
/**
* Get ChromaSync instance (throws if not initialized)
*/
getChromaSync(): ChromaSync {
if (!this.chromaSync) {
throw new Error('ChromaSync not initialized');
}
return this.chromaSync;
}
// REMOVED: cleanupOrphanedSessions - violates "EVERYTHING SHOULD SAVE ALWAYS"
// Worker restarts don't make sessions orphaned. Sessions are managed by hooks
// and exist independently of worker state.
/**
* Get session by ID (throws if not found)
*/
getSessionById(sessionDbId: number): {
id: number;
content_session_id: string;
memory_session_id: string | null;
project: string;
user_prompt: string;
} {
const session = this.getSessionStore().getSessionById(sessionDbId);
if (!session) {
throw new Error(`Session ${sessionDbId} not found`);
}
return session;
}
}