/** * Session history management * @module nopy.history */ import fs from 'node:fs'; import path from 'node:path'; import { describeSession, type NopySession } from './nopy.session.js'; /** Default number of sessions to keep in history */ export const DEFAULT_HISTORY_SIZE = 10; /** History file name */ export const HISTORY_FILE = '.nopy.history.json'; /** * A session entry in history */ export interface HistoryEntry { /** Unique identifier (timestamp-based) */ id: string; /** Human-readable name (timestamp + cube names) */ name: string; /** ISO timestamp when session was executed */ timestamp: string; /** The full session data */ session: NopySession; } /** * History file structure */ export interface SessionHistory { /** Array of session entries, newest first */ entries: HistoryEntry[]; } /** * Gets the path to the history file */ export function getHistoryPath(): string { return path.resolve(process.cwd(), HISTORY_FILE); } /** * Loads the session history from disk * * @returns The session history or empty history if file doesn't exist */ export function loadHistory(): SessionHistory { const historyPath = getHistoryPath(); if (!fs.existsSync(historyPath)) { return { entries: [] }; } try { const content = fs.readFileSync(historyPath, 'utf-8'); return JSON.parse(content) as SessionHistory; } catch { return { entries: [] }; } } /** * Saves the session history to disk * * @param history - The history to save */ export function saveHistory(history: SessionHistory): void { const historyPath = getHistoryPath(); fs.writeFileSync(historyPath, JSON.stringify(history, null, 2), 'utf-8'); } /** * Generates a unique ID for a history entry */ function generateEntryId(): string { return Date.now().toString(36) + Math.random().toString(36).substring(2, 7); } /** * Adds a session to the history * * @param session - The session to add * @param maxEntries - Maximum number of entries to keep * @returns The created history entry */ export function addToHistory( session: NopySession, maxEntries: number = DEFAULT_HISTORY_SIZE ): HistoryEntry { const history = loadHistory(); const timestamp = new Date().toISOString(); const entry: HistoryEntry = { id: generateEntryId(), name: describeSession(session, timestamp), timestamp, session, }; // Add to beginning (newest first) history.entries.unshift(entry); // Trim to max size if (history.entries.length > maxEntries) { history.entries = history.entries.slice(0, maxEntries); } saveHistory(history); return entry; } /** * Gets the most recent session from history * * @returns The last session or undefined if history is empty */ export function getLastSession(): HistoryEntry | undefined { const history = loadHistory(); return history.entries[0]; } /** * Gets a session by ID * * @param id - The session ID * @returns The session entry or undefined */ export function getSessionById(id: string): HistoryEntry | undefined { const history = loadHistory(); return history.entries.find((e) => e.id === id); } /** * Lists all sessions in history * * @returns Array of history entries, newest first */ export function listHistory(): HistoryEntry[] { const history = loadHistory(); return history.entries; } /** * Clears all session history */ export function clearHistory(): void { saveHistory({ entries: [] }); } /** * Removes a specific session from history * * @param id - The session ID to remove * @returns true if removed, false if not found */ export function removeFromHistory(id: string): boolean { const history = loadHistory(); const initialLength = history.entries.length; history.entries = history.entries.filter((e) => e.id !== id); if (history.entries.length < initialLength) { saveHistory(history); return true; } return false; } /** * Formats history entries for display * * @param entries - History entries to format * @returns Formatted string for console output */ export function formatHistoryList(entries: HistoryEntry[]): string { if (entries.length === 0) { return 'No sessions in history.'; } const lines = ['', 'Session History:', '']; entries.forEach((entry, index) => { const marker = index === 0 ? '→' : ' '; lines.push(` ${marker} [${index + 1}] ${entry.name}`); lines.push(` ID: ${entry.id}`); }); lines.push(''); lines.push(`Total: ${entries.length} session(s)`); lines.push(''); return lines.join('\n'); }