diff --git a/crates/chat-cli/src/cli/chat/command.rs b/crates/chat-cli/src/cli/chat/command.rs index 43d07f1169..8a0261e3b4 100644 --- a/crates/chat-cli/src/cli/chat/command.rs +++ b/crates/chat-cli/src/cli/chat/command.rs @@ -180,7 +180,8 @@ impl ContextSubcommand { help Show an explanation for the context command show [--expand] Display the context rule configuration and matched files - --expand: Print out each matched file's content + --expand: Print out each matched file's content, hook + configurations and last conversation summary add [--global] [--force] <> Add context rules (filenames or glob patterns) diff --git a/crates/chat-cli/src/cli/chat/conversation_state.rs b/crates/chat-cli/src/cli/chat/conversation_state.rs index 1f22c4013f..b5b039094b 100644 --- a/crates/chat-cli/src/cli/chat/conversation_state.rs +++ b/crates/chat-cli/src/cli/chat/conversation_state.rs @@ -143,6 +143,10 @@ impl ConversationState { } } + pub fn latest_summary(&self) -> Option<&str> { + self.latest_summary.as_deref() + } + pub fn history(&self) -> &VecDeque<(UserMessage, AssistantMessage)> { &self.history } diff --git a/crates/chat-cli/src/cli/chat/mod.rs b/crates/chat-cli/src/cli/chat/mod.rs index a7937de749..aab5a134e8 100644 --- a/crates/chat-cli/src/cli/chat/mod.rs +++ b/crates/chat-cli/src/cli/chat/mod.rs @@ -1584,6 +1584,9 @@ impl ChatContext { if let Some(context_manager) = &mut self.conversation_state.context_manager { match subcommand { command::ContextSubcommand::Show { expand } => { + fn map_chat_error(e: ErrReport) -> ChatError { + ChatError::Custom(e.to_string().into()) + } // Display global context execute!( self.output, @@ -1621,6 +1624,28 @@ impl ChatContext { } } + if expand { + queue!( + self.output, + style::SetAttribute(Attribute::Bold), + style::SetForegroundColor(Color::DarkYellow), + style::Print("\n 🔧 Hooks:\n") + )?; + print_hook_section( + &mut self.output, + &context_manager.global_config.hooks, + HookTrigger::ConversationStart, + ) + .map_err(map_chat_error)?; + + print_hook_section( + &mut self.output, + &context_manager.global_config.hooks, + HookTrigger::PerPrompt, + ) + .map_err(map_chat_error)?; + } + // Display profile context execute!( self.output, @@ -1658,6 +1683,28 @@ impl ChatContext { execute!(self.output, style::Print("\n"))?; } + if expand { + queue!( + self.output, + style::SetAttribute(Attribute::Bold), + style::SetForegroundColor(Color::DarkYellow), + style::Print(" 🔧 Hooks:\n") + )?; + print_hook_section( + &mut self.output, + &context_manager.profile_config.hooks, + HookTrigger::ConversationStart, + ) + .map_err(map_chat_error)?; + print_hook_section( + &mut self.output, + &context_manager.profile_config.hooks, + HookTrigger::PerPrompt, + ) + .map_err(map_chat_error)?; + execute!(self.output, style::Print("\n"))?; + } + if global_context_files.is_empty() && profile_context_files.is_empty() { execute!( self.output, @@ -1781,6 +1828,28 @@ impl ChatContext { execute!(self.output, style::Print("\n"))?; } + + // Show last cached conversation summary if available, otherwise regenerate it + if expand { + if let Some(summary) = self.conversation_state.latest_summary() { + let border = "═".repeat(self.terminal_width().min(80)); + execute!( + self.output, + style::Print("\n"), + style::SetForegroundColor(Color::Cyan), + style::Print(&border), + style::Print("\n"), + style::SetAttribute(Attribute::Bold), + style::Print(" CONVERSATION SUMMARY"), + style::Print("\n"), + style::Print(&border), + style::SetAttribute(Attribute::Reset), + style::Print("\n\n"), + style::Print(&summary), + style::Print("\n\n\n") + )?; + } + } }, command::ContextSubcommand::Add { global, force, paths } => { match context_manager.add_paths(paths.clone(), global, force).await { @@ -2030,48 +2099,6 @@ impl ChatContext { }, } } else { - fn print_hook_section( - output: &mut impl Write, - hooks: &HashMap, - trigger: HookTrigger, - ) -> Result<()> { - let section = match trigger { - HookTrigger::ConversationStart => "Conversation Start", - HookTrigger::PerPrompt => "Per Prompt", - }; - let hooks: Vec<(&String, &Hook)> = - hooks.iter().filter(|(_, h)| h.trigger == trigger).collect(); - - queue!( - output, - style::SetForegroundColor(Color::Cyan), - style::Print(format!(" {section}:\n")), - style::SetForegroundColor(Color::Reset), - )?; - - if hooks.is_empty() { - queue!( - output, - style::SetForegroundColor(Color::DarkGrey), - style::Print(" \n"), - style::SetForegroundColor(Color::Reset) - )?; - } else { - for (name, hook) in hooks { - if hook.disabled { - queue!( - output, - style::SetForegroundColor(Color::DarkGrey), - style::Print(format!(" {} (disabled)\n", name)), - style::SetForegroundColor(Color::Reset) - )?; - } else { - queue!(output, style::Print(format!(" {}\n", name)),)?; - } - } - } - Ok(()) - } queue!( self.output, style::SetAttribute(Attribute::Bold), @@ -3357,6 +3384,45 @@ impl ChatContext { } } +/// Prints hook configuration grouped by trigger: conversation session start or per user message +fn print_hook_section(output: &mut impl Write, hooks: &HashMap, trigger: HookTrigger) -> Result<()> { + let section = match trigger { + HookTrigger::ConversationStart => "On Session Start", + HookTrigger::PerPrompt => "Per User Message", + }; + let hooks: Vec<(&String, &Hook)> = hooks.iter().filter(|(_, h)| h.trigger == trigger).collect(); + + queue!( + output, + style::SetForegroundColor(Color::Cyan), + style::Print(format!(" {section}:\n")), + style::SetForegroundColor(Color::Reset), + )?; + + if hooks.is_empty() { + queue!( + output, + style::SetForegroundColor(Color::DarkGrey), + style::Print(" \n"), + style::SetForegroundColor(Color::Reset) + )?; + } else { + for (name, hook) in hooks { + if hook.disabled { + queue!( + output, + style::SetForegroundColor(Color::DarkGrey), + style::Print(format!(" {} (disabled)\n", name)), + style::SetForegroundColor(Color::Reset) + )?; + } else { + queue!(output, style::Print(format!(" {}\n", name)),)?; + } + } + } + Ok(()) +} + #[derive(Debug)] struct ToolUseEventBuilder { pub conversation_id: String,