import { Action, ActionPanel, Clipboard, Icon, List, useNavigation } from "@vicinae/api"; import { useCallback, useEffect, useMemo, useState } from "react"; import { runAutoDelete } from "./lib/cleanup"; import { ChatView } from "./lib/components/ChatView"; import { sessionToPlainText } from "./lib/markdown"; import { getLamPreferences } from "./lib/preferences"; import { clearSessions, deleteSession, listSessions, loadSession } from "./lib/sessions"; import type { SessionSummary } from "./lib/types"; import { formatRelativeTime, truncate } from "./lib/utils"; /** * Browse and manage past conversations. * * Loading a transcript is deferred until the user actually opens one: the * index holds only summaries, so this view stays fast no matter how much * history has piled up. */ export default function SessionsCommand() { const { push } = useNavigation(); const [sessions, setSessions] = useState(undefined); const preferences = useMemo(() => getLamPreferences(), []); const refresh = useCallback(() => { void listSessions() .then(setSessions) .catch(() => setSessions([])); }, []); // Opening the list is the other moment the user is asking about their history, // so it is the other moment expired conversations should be gone. No `keepId`: // nothing is open here to spare. The refresh afterwards is what stops the list // rendering a row that was just deleted from underneath it. useEffect(() => { let cancelled = false; void (async () => { await runAutoDelete({ maxAgeMs: preferences.autoDeleteMs }); if (!cancelled) refresh(); })(); return () => { cancelled = true; }; }, [preferences.autoDeleteMs, refresh]); const openSession = useCallback( (id: string) => { void loadSession(id).then((session) => { if (session) push(); }); }, [push], ); const remove = useCallback( (id: string) => { void deleteSession(id).then(refresh); }, [refresh], ); const copyConversation = useCallback((id: string) => { // Loads the full transcript rather than copying the index preview. void loadSession(id).then((session) => { if (session) void Clipboard.copy(sessionToPlainText(session.turns)); }); }, []); const removeAll = useCallback(() => { void clearSessions().then(refresh); }, [refresh]); const loaded = sessions !== undefined; const items = sessions ?? []; return ( {loaded && items.length === 0 ? ( ) : null} {items.map((summary) => ( openSession(summary.id)} /> copyConversation(summary.id)} /> remove(summary.id)} /> } /> ))} ); }