diff --git a/src-tauri/src/commands.rs b/src-tauri/src/commands.rs index 030e0ab..32c96ea 100644 --- a/src-tauri/src/commands.rs +++ b/src-tauri/src/commands.rs @@ -1464,6 +1464,7 @@ pub async fn close_application(app_handle: AppHandle) -> Result<(), String> { pub struct MemoryFileInfo { pub path: String, pub heading: Option, + pub last_modified: Option, // Unix timestamp in seconds as a string } #[derive(serde::Serialize)] @@ -1535,7 +1536,11 @@ async fn list_memory_files_via_wsl() -> Result { let mut files = Vec::new(); for path in paths { let heading = read_wsl_file_first_heading(&path); - files.push(MemoryFileInfo { path, heading }); + files.push(MemoryFileInfo { + path, + heading, + last_modified: None, + }); } Ok(MemoryFilesResponse { files }) @@ -1605,14 +1610,23 @@ async fn list_memory_files_native() -> Result { // Sort files alphabetically memory_paths.sort(); - // Read first heading from each file + // Read first heading and modification time from each file let files = memory_paths .into_iter() .map(|path| { let heading = fs::read_to_string(&path) .ok() .and_then(|content| extract_first_heading(&content)); - MemoryFileInfo { path, heading } + let last_modified = fs::metadata(&path) + .ok() + .and_then(|m| m.modified().ok()) + .and_then(|t| t.duration_since(std::time::UNIX_EPOCH).ok()) + .map(|d| d.as_secs().to_string()); + MemoryFileInfo { + path, + heading, + last_modified, + } }) .collect(); diff --git a/src/lib/components/MemoryBrowserPanel.svelte b/src/lib/components/MemoryBrowserPanel.svelte index 72d1bb3..b9088fc 100644 --- a/src/lib/components/MemoryBrowserPanel.svelte +++ b/src/lib/components/MemoryBrowserPanel.svelte @@ -14,6 +14,7 @@ interface MemoryFileInfo { path: string; heading: string | null; + last_modified?: string; // Unix timestamp in seconds as a string, optional for backwards compat } interface MemoryFilesResponse { @@ -65,6 +66,16 @@ return file.heading ?? getFileName(file.path); } + function formatLastModified(ts: string | undefined): string { + if (!ts) return ""; + const date = new Date(Number(ts) * 1000); + return date.toLocaleDateString(undefined, { + year: "numeric", + month: "short", + day: "numeric", + }); + } + async function sendMemoryCommand() { const conversationId = get(claudeStore.activeConversationId); if (!conversationId) return; @@ -205,7 +216,12 @@ d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z" /> - {getDisplayName(file)} +
+ {getDisplayName(file)} + {#if file.last_modified} + {formatLastModified(file.last_modified)} + {/if} +
{/each} @@ -416,7 +432,7 @@ .file-item { display: flex; - align-items: center; + align-items: flex-start; gap: 0.75rem; padding: 0.75rem 1rem; background: var(--bg-secondary); @@ -445,6 +461,13 @@ flex-shrink: 0; } + .file-info { + display: flex; + flex-direction: column; + gap: 0.125rem; + overflow: hidden; + } + .file-name { font-size: 0.875rem; font-weight: 500; @@ -453,6 +476,15 @@ white-space: nowrap; } + .file-date { + font-size: 0.75rem; + color: var(--text-secondary); + } + + .file-item.active .file-date { + color: rgba(255, 255, 255, 0.75); + } + .file-viewer { display: flex; flex-direction: column;