feat: add memory system activity display

Implements issue #118 to display auto-memory system operations and
provide a browser for viewing memory files.

Backend changes:
- Detect memory file operations in format_tool_description()
- Add emoji icons (๐Ÿ“/๐Ÿ’พ) for memory Read/Write/Edit operations
- Add list_memory_files() Tauri command to find all memory files
- Add 4 new tests for memory detection logic
- Update Tauri capabilities to allow reading .claude directory

Frontend changes:
- Create MemoryBrowserPanel component with file list and viewer
- Add memory panel to main app layout
- Support Markdown rendering of memory file contents
- Add loading states and error handling

Testing:
- All 354 Rust tests passing
- TypeScript type-checks pass

Co-Authored-By: Hikari <hikari@nhcarrigan.com>
This commit is contained in:
2026-02-07 12:01:31 -08:00
committed by Naomi Carrigan
parent e40ae989f7
commit 89e99b1524
7 changed files with 606 additions and 4 deletions
+64 -3
View File
@@ -1505,10 +1505,21 @@ fn get_tool_state(tool_name: &str) -> CharacterState {
}
fn format_tool_description(name: &str, input: &serde_json::Value) -> String {
// Helper function to check if a path is a memory file
fn is_memory_path(path: &str) -> bool {
path.contains("/.claude/") && (path.contains("/memory/") || path.ends_with("/MEMORY.md"))
}
match name {
"Read" => {
if let Some(path) = input.get("file_path").and_then(|v| v.as_str()) {
format!("Reading file: {}", path)
if is_memory_path(path) {
// Extract just the filename for cleaner display
let filename = path.split('/').last().unwrap_or(path);
format!("๐Ÿ“ Reading memory: {}", filename)
} else {
format!("Reading file: {}", path)
}
} else {
"Reading file...".to_string()
}
@@ -1527,9 +1538,26 @@ fn format_tool_description(name: &str, input: &serde_json::Value) -> String {
"Searching in files...".to_string()
}
}
"Edit" | "Write" => {
"Edit" => {
if let Some(path) = input.get("file_path").and_then(|v| v.as_str()) {
format!("Editing: {}", path)
if is_memory_path(path) {
let filename = path.split('/').last().unwrap_or(path);
format!("๐Ÿ’พ Updating memory: {}", filename)
} else {
format!("Editing: {}", path)
}
} else {
"Editing file...".to_string()
}
}
"Write" => {
if let Some(path) = input.get("file_path").and_then(|v| v.as_str()) {
if is_memory_path(path) {
let filename = path.split('/').last().unwrap_or(path);
format!("๐Ÿ’พ Writing memory: {}", filename)
} else {
format!("Editing: {}", path)
}
} else {
"Editing file...".to_string()
}
@@ -1714,6 +1742,39 @@ mod tests {
assert_eq!(desc, "Using tool: CustomTool");
}
#[test]
fn test_format_tool_description_memory_read() {
let input =
serde_json::json!({"file_path": "/home/user/.claude/projects/test/memory/MEMORY.md"});
let desc = format_tool_description("Read", &input);
assert_eq!(desc, "๐Ÿ“ Reading memory: MEMORY.md");
}
#[test]
fn test_format_tool_description_memory_write() {
let input = serde_json::json!(
{"file_path": "/home/user/.claude/projects/test/memory/notes.md"}
);
let desc = format_tool_description("Write", &input);
assert_eq!(desc, "๐Ÿ’พ Writing memory: notes.md");
}
#[test]
fn test_format_tool_description_memory_edit() {
let input = serde_json::json!(
{"file_path": "/home/user/.claude/projects/test/memory/patterns.md"}
);
let desc = format_tool_description("Edit", &input);
assert_eq!(desc, "๐Ÿ’พ Updating memory: patterns.md");
}
#[test]
fn test_format_tool_description_non_memory_read() {
let input = serde_json::json!({"file_path": "/home/user/code/test.txt"});
let desc = format_tool_description("Read", &input);
assert_eq!(desc, "Reading file: /home/user/code/test.txt");
}
#[test]
fn test_wsl_bridge_new() {
let bridge = WslBridge::new();