From 0954f0051f2c600bd9a2a29e60f769c14554c3b4 Mon Sep 17 00:00:00 2001 From: insign <1113045+insign@users.noreply.github.com> Date: Thu, 26 Feb 2026 03:09:57 +0000 Subject: [PATCH] feat: Add ability to view specific history by ID or path - Refactor `ContextManager::show_history` to extract printing logic - Implement `ContextManager::view_history` to search and display contexts - Update CLI handler to call `view_history` when `ask history` has arguments - Supports partial ID matching, exact path matching, and `.` for current directory --- src/cli/mod.rs | 3 ++ src/context/manager.rs | 71 +++++++++++++++++++++++++++++++++++++++--- 2 files changed, 69 insertions(+), 5 deletions(-) diff --git a/src/cli/mod.rs b/src/cli/mod.rs index be205cf..1765ad1 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -129,6 +129,9 @@ pub async fn run(update_notification: Option) } if args.history_subcommand { + if !args.query.is_empty() { + return ContextManager::view_history(&config, &args.query[0]); + } return ContextManager::list_global(&config); } diff --git a/src/context/manager.rs b/src/context/manager.rs index a39228c..571f1ae 100644 --- a/src/context/manager.rs +++ b/src/context/manager.rs @@ -134,6 +134,62 @@ impl ContextManager { Ok(()) } + /// View a specific history by ID or path + pub fn view_history(config: &Config, id_or_path: &str) -> Result<()> { + let storage_path = config.context_storage_path(); + let storage = ContextStorage::new(storage_path)?; + let contexts = storage.list()?; + + if contexts.is_empty() { + println!("{}", "No global context history found.".yellow()); + return Ok(()); + } + + // 1. Try exact path match + let path_match = contexts.iter().find(|ctx| ctx.pwd == id_or_path); + if let Some(ctx) = path_match { + return Self::print_entry(Some(ctx), None); + } + + // 2. Try resolving "." to current directory + if id_or_path == "." { + let current_dir = std::env::current_dir()? + .to_string_lossy() + .to_string(); + let current_match = contexts.iter().find(|ctx| ctx.pwd == current_dir); + if let Some(ctx) = current_match { + return Self::print_entry(Some(ctx), None); + } + } + + // 3. Try ID prefix match + let id_matches: Vec<_> = contexts + .iter() + .filter(|ctx| ctx.id.starts_with(id_or_path)) + .collect(); + + if id_matches.len() == 1 { + return Self::print_entry(Some(id_matches[0]), None); + } else if id_matches.len() > 1 { + println!( + "{}", + format!("Multiple contexts match '{}':", id_or_path).yellow() + ); + for ctx in id_matches { + println!(" {} {}", ctx.id.bright_white(), ctx.pwd.bright_black()); + } + println!(); + println!("{}", "Please provide a longer ID to be specific.".bright_black()); + return Ok(()); + } + + println!( + "{}", + format!("No context found matching '{}'.", id_or_path).red() + ); + Ok(()) + } + /// Clear the current context pub fn clear_current(&self) -> Result<()> { self.storage.delete(&self.context_id) @@ -147,8 +203,11 @@ impl ContextManager { /// Show context history pub fn show_history(&self) -> Result<()> { let entry = self.storage.load(&self.context_id)?; + Self::print_entry(entry.as_ref(), Some(self.max_age_minutes)) + } - match entry { + fn print_entry(ctx: Option<&ContextEntry>, max_age_minutes: Option) -> Result<()> { + match ctx { Some(ctx) => { println!("{} {}", "Context for:".cyan(), ctx.pwd.bright_white()); println!( @@ -164,10 +223,12 @@ impl ContextManager { println!("{} {}", "Messages:".cyan(), ctx.messages.len()); // Show TTL info - if self.max_age_minutes == 0 { - println!("{} {}", "TTL:".cyan(), "permanent".green()); - } else { - println!("{} {} minutes", "TTL:".cyan(), self.max_age_minutes); + if let Some(ttl) = max_age_minutes { + if ttl == 0 { + println!("{} {}", "TTL:".cyan(), "permanent".green()); + } else { + println!("{} {} minutes", "TTL:".cyan(), ttl); + } } println!();