UNPKG

@nanocollective/nanocoder

Version:

A local-first CLI coding agent that brings the power of agentic coding tools like Claude Code and Gemini CLI to local models or controlled APIs like OpenRouter

133 lines 5.84 kB
import { useEffect, useRef } from 'react'; import { getAppConfig } from '../config/index.js'; import { sessionManager } from '../session/session-manager.js'; import { logWarning } from '../utils/message-queue.js'; /** * Hook to handle automatic session saving. * Updates the current session when currentSessionId is set; otherwise creates a new session. * Clears currentSessionId when messages are cleared. */ export function useSessionAutosave({ messages, currentProvider, currentModel, currentSessionId, setCurrentSessionId, }) { const initPromiseRef = useRef(null); const timeoutRef = useRef(null); const lastSaveRef = useRef(0); // Clear current session when conversation is cleared useEffect(() => { if (messages.length === 0 && currentSessionId !== null) { setCurrentSessionId(null); } }, [messages.length, currentSessionId, setCurrentSessionId]); // Initialize session manager only when autosave is enabled (avoids creating // sessions dir/index and running retention when user has autosave off). // /resume initializes the manager when the user explicitly runs it. useEffect(() => { const config = getAppConfig(); const autoSave = config.sessions?.autoSave ?? true; if (!autoSave) { return; } if (!initPromiseRef.current) { initPromiseRef.current = sessionManager .initialize() .then(() => true) .catch(error => { logWarning(`Session autosave disabled: failed to initialize session storage. ${error instanceof Error ? error.message : String(error)}`); return false; }); } return () => { if (timeoutRef.current) { clearTimeout(timeoutRef.current); } }; }, []); // Auto-save when messages change (debounced by saveInterval) useEffect(() => { const config = getAppConfig(); const sessionConfig = config.sessions; const autoSave = sessionConfig?.autoSave ?? true; const saveInterval = sessionConfig?.saveInterval ?? 30000; const maxMessages = sessionConfig?.maxMessages ?? 1000; if (!autoSave || !initPromiseRef.current || messages.length === 0) { return; } if (timeoutRef.current) { clearTimeout(timeoutRef.current); } const now = Date.now(); const timeSinceLastSave = now - lastSaveRef.current; const saveSession = async () => { try { // Wait for initialization to complete before saving const initialized = await initPromiseRef.current; if (!initialized) return; // Truncate to most recent messages to prevent unbounded session sizes const messagesToSave = messages.length > maxMessages ? messages.slice(-maxMessages) : messages; const userMessages = messagesToSave.filter(msg => msg.role === 'user'); const lastUserMessage = userMessages[userMessages.length - 1]; const title = lastUserMessage ? lastUserMessage.content.substring(0, 50) + (lastUserMessage.content.length > 50 ? '...' : '') : `Session ${new Date().toLocaleDateString()}`; if (currentSessionId) { const session = await sessionManager.readSession(currentSessionId); if (session) { session.messages = messagesToSave; session.messageCount = messagesToSave.length; session.title = title; session.provider = currentProvider; session.model = currentModel; // Don't set lastAccessedAt here — saveSession() handles // the timestamp in both the file and index consistently. await sessionManager.saveSession(session); } else { const newSession = await sessionManager.createSession({ title, messageCount: messagesToSave.length, provider: currentProvider, model: currentModel, workingDirectory: process.cwd(), messages: messagesToSave, }); setCurrentSessionId(newSession.id); } } else { const newSession = await sessionManager.createSession({ title, messageCount: messagesToSave.length, provider: currentProvider, model: currentModel, workingDirectory: process.cwd(), messages: messagesToSave, }); setCurrentSessionId(newSession.id); } lastSaveRef.current = Date.now(); } catch (error) { console.warn('Failed to auto-save session:', error); } }; if (timeSinceLastSave >= saveInterval) { void saveSession(); } else { const delay = saveInterval - timeSinceLastSave; timeoutRef.current = setTimeout(() => { void saveSession(); }, delay); } }, [ messages, currentProvider, currentModel, currentSessionId, setCurrentSessionId, ]); } //# sourceMappingURL=useSessionAutosave.js.map