30b142d318
This commit fixes the session ID confusion identified in PR #475: PROBLEM: - Using contentSessionId (user's Claude Code session) for SDK resume was wrong - Memory agent conversation should persist across the entire user session - Each SDK call was starting fresh, losing memory agent continuity SOLUTION: 1. Semantic Renaming (clarity): - claudeSessionId → contentSessionId (user's observed session) - sdkSessionId → memorySessionId (memory agent's session for resume) - Database migration 17 renames columns accordingly 2. Memory Session ID Capture: - SDKAgent captures session_id from first SDK message - Persists to database via updateMemorySessionId() - SessionManager loads memorySessionId on session init 3. Resume Logic Fixed: - Only resume if memorySessionId captured from previous interaction - Enables memory agent continuity across user prompts Files changed: 33 (types, database, agents, hooks, routes) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
109 lines
2.9 KiB
TypeScript
109 lines
2.9 KiB
TypeScript
/**
|
|
* 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 '../sqlite/SessionStore.js';
|
|
import { SessionSearch } from '../sqlite/SessionSearch.js';
|
|
import { ChromaSync } from '../sync/ChromaSync.js';
|
|
import { logger } from '../../utils/logger.js';
|
|
import type { DBSession } from '../worker-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-mem');
|
|
|
|
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');
|
|
}
|
|
|
|
/**
|
|
* 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;
|
|
}
|
|
|
|
}
|