import { useState, useEffect } from 'react'; import type { MemoryFile } from '../types'; const KNOWN_FILES = [ { filename: 'MEMORY.md', description: 'Index of all memory files' }, { filename: 'user-profile.md', description: 'Identity, preferences, style' }, { filename: 'active-threads.md', description: 'Ongoing conversations by channel' }, { filename: 'pending-tasks.md', description: 'Tasks, reminders, deadlines' }, { filename: 'learned-today.md', description: 'Facts learned today' }, { filename: 'contacts.md', description: 'People the user mentions' } ]; function formatFileSize(bytes: number): string { if (bytes < 1024) return `${bytes}B`; if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)}KB`; return `${(bytes / (1024 * 1024)).toFixed(1)}MB`; } function formatDate(ts: number): string { return new Date(ts).toLocaleString(); } export default function MemoryPage() { const [files, setFiles] = useState([]); const [activeFile, setActiveFile] = useState(null); const [content, setContent] = useState(''); const [editContent, setEditContent] = useState(''); const [isEditing, setIsEditing] = useState(false); const [isSaving, setIsSaving] = useState(false); const [loadingContent, setLoadingContent] = useState(false); const [error, setError] = useState(null); const [saveSuccess, setSaveSuccess] = useState(false); useEffect(() => { fetch('/api/memory') .then((r) => r.json()) .then((data: MemoryFile[]) => { if (Array.isArray(data)) { setFiles(data); } else { // Fallback: use known files list with dummy metadata setFiles( KNOWN_FILES.map((f) => ({ filename: f.filename, size: 0, modified_at: Date.now() })) ); } }) .catch(() => { setFiles( KNOWN_FILES.map((f) => ({ filename: f.filename, size: 0, modified_at: Date.now() })) ); }); }, []); const loadFile = (filename: string) => { setActiveFile(filename); setIsEditing(false); setError(null); setLoadingContent(true); fetch(`/api/memory/${encodeURIComponent(filename)}`) .then((r) => { if (!r.ok) throw new Error(`HTTP ${r.status}`); return r.json(); }) .then((data: { filename: string; content: string }) => { setContent(data.content ?? ''); setEditContent(data.content ?? ''); }) .catch((err) => { setContent(''); setError(`Failed to load file: ${err.message}`); }) .finally(() => setLoadingContent(false)); }; const startEdit = () => { setEditContent(content); setIsEditing(true); setSaveSuccess(false); }; const cancelEdit = () => { setIsEditing(false); setEditContent(content); }; const saveFile = async () => { if (!activeFile) return; setIsSaving(true); setError(null); try { const res = await fetch(`/api/memory/${encodeURIComponent(activeFile)}`, { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ content: editContent }) }); if (!res.ok) throw new Error(`HTTP ${res.status}`); setContent(editContent); setIsEditing(false); setSaveSuccess(true); // Update file list size setFiles((prev) => prev.map((f) => f.filename === activeFile ? { ...f, size: new Blob([editContent]).size, modified_at: Date.now() } : f ) ); setTimeout(() => setSaveSuccess(false), 3000); } catch (err) { setError(`Save failed: ${(err as Error).message}`); } finally { setIsSaving(false); } }; const getFileDescription = (filename: string) => KNOWN_FILES.find((f) => f.filename === filename)?.description ?? ''; return (
{/* File list */}

Memory

{files.length} files

{files.map((file) => ( ))}
{/* Content area */}
{activeFile ? ( <> {/* File header */}

{activeFile}

{getFileDescription(activeFile) && (

{getFileDescription(activeFile)}

)}
{saveSuccess && ( Saved successfully )} {error && {error}} {isEditing ? ( <> ) : ( )}
{/* Content */}
{loadingContent ? (
Loading...
) : isEditing ? (