Skip to content

Commit b25b172

Browse files
authored
feat: Include /context hooks and conversation summary in /context show --expand (#1477)
1 parent 4e6083a commit b25b172

File tree

3 files changed

+114
-43
lines changed

3 files changed

+114
-43
lines changed

crates/chat-cli/src/cli/chat/command.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,8 @@ impl ContextSubcommand {
180180
<em>help</em> <black!>Show an explanation for the context command</black!>
181181
182182
<em>show [--expand]</em> <black!>Display the context rule configuration and matched files</black!>
183-
<black!>--expand: Print out each matched file's content</black!>
183+
<black!>--expand: Print out each matched file's content, hook</black!>
184+
<black!> configurations and last conversation summary </black!>
184185
185186
<em>add [--global] [--force] <<paths...>></em>
186187
<black!>Add context rules (filenames or glob patterns)</black!>

crates/chat-cli/src/cli/chat/conversation_state.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,10 @@ impl ConversationState {
143143
}
144144
}
145145

146+
pub fn latest_summary(&self) -> Option<&str> {
147+
self.latest_summary.as_deref()
148+
}
149+
146150
pub fn history(&self) -> &VecDeque<(UserMessage, AssistantMessage)> {
147151
&self.history
148152
}

crates/chat-cli/src/cli/chat/mod.rs

Lines changed: 108 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1584,6 +1584,9 @@ impl ChatContext {
15841584
if let Some(context_manager) = &mut self.conversation_state.context_manager {
15851585
match subcommand {
15861586
command::ContextSubcommand::Show { expand } => {
1587+
fn map_chat_error(e: ErrReport) -> ChatError {
1588+
ChatError::Custom(e.to_string().into())
1589+
}
15871590
// Display global context
15881591
execute!(
15891592
self.output,
@@ -1621,6 +1624,28 @@ impl ChatContext {
16211624
}
16221625
}
16231626

1627+
if expand {
1628+
queue!(
1629+
self.output,
1630+
style::SetAttribute(Attribute::Bold),
1631+
style::SetForegroundColor(Color::DarkYellow),
1632+
style::Print("\n 🔧 Hooks:\n")
1633+
)?;
1634+
print_hook_section(
1635+
&mut self.output,
1636+
&context_manager.global_config.hooks,
1637+
HookTrigger::ConversationStart,
1638+
)
1639+
.map_err(map_chat_error)?;
1640+
1641+
print_hook_section(
1642+
&mut self.output,
1643+
&context_manager.global_config.hooks,
1644+
HookTrigger::PerPrompt,
1645+
)
1646+
.map_err(map_chat_error)?;
1647+
}
1648+
16241649
// Display profile context
16251650
execute!(
16261651
self.output,
@@ -1658,6 +1683,28 @@ impl ChatContext {
16581683
execute!(self.output, style::Print("\n"))?;
16591684
}
16601685

1686+
if expand {
1687+
queue!(
1688+
self.output,
1689+
style::SetAttribute(Attribute::Bold),
1690+
style::SetForegroundColor(Color::DarkYellow),
1691+
style::Print(" 🔧 Hooks:\n")
1692+
)?;
1693+
print_hook_section(
1694+
&mut self.output,
1695+
&context_manager.profile_config.hooks,
1696+
HookTrigger::ConversationStart,
1697+
)
1698+
.map_err(map_chat_error)?;
1699+
print_hook_section(
1700+
&mut self.output,
1701+
&context_manager.profile_config.hooks,
1702+
HookTrigger::PerPrompt,
1703+
)
1704+
.map_err(map_chat_error)?;
1705+
execute!(self.output, style::Print("\n"))?;
1706+
}
1707+
16611708
if global_context_files.is_empty() && profile_context_files.is_empty() {
16621709
execute!(
16631710
self.output,
@@ -1781,6 +1828,28 @@ impl ChatContext {
17811828

17821829
execute!(self.output, style::Print("\n"))?;
17831830
}
1831+
1832+
// Show last cached conversation summary if available, otherwise regenerate it
1833+
if expand {
1834+
if let Some(summary) = self.conversation_state.latest_summary() {
1835+
let border = "═".repeat(self.terminal_width().min(80));
1836+
execute!(
1837+
self.output,
1838+
style::Print("\n"),
1839+
style::SetForegroundColor(Color::Cyan),
1840+
style::Print(&border),
1841+
style::Print("\n"),
1842+
style::SetAttribute(Attribute::Bold),
1843+
style::Print(" CONVERSATION SUMMARY"),
1844+
style::Print("\n"),
1845+
style::Print(&border),
1846+
style::SetAttribute(Attribute::Reset),
1847+
style::Print("\n\n"),
1848+
style::Print(&summary),
1849+
style::Print("\n\n\n")
1850+
)?;
1851+
}
1852+
}
17841853
},
17851854
command::ContextSubcommand::Add { global, force, paths } => {
17861855
match context_manager.add_paths(paths.clone(), global, force).await {
@@ -2030,48 +2099,6 @@ impl ChatContext {
20302099
},
20312100
}
20322101
} else {
2033-
fn print_hook_section(
2034-
output: &mut impl Write,
2035-
hooks: &HashMap<String, Hook>,
2036-
trigger: HookTrigger,
2037-
) -> Result<()> {
2038-
let section = match trigger {
2039-
HookTrigger::ConversationStart => "Conversation Start",
2040-
HookTrigger::PerPrompt => "Per Prompt",
2041-
};
2042-
let hooks: Vec<(&String, &Hook)> =
2043-
hooks.iter().filter(|(_, h)| h.trigger == trigger).collect();
2044-
2045-
queue!(
2046-
output,
2047-
style::SetForegroundColor(Color::Cyan),
2048-
style::Print(format!(" {section}:\n")),
2049-
style::SetForegroundColor(Color::Reset),
2050-
)?;
2051-
2052-
if hooks.is_empty() {
2053-
queue!(
2054-
output,
2055-
style::SetForegroundColor(Color::DarkGrey),
2056-
style::Print(" <none>\n"),
2057-
style::SetForegroundColor(Color::Reset)
2058-
)?;
2059-
} else {
2060-
for (name, hook) in hooks {
2061-
if hook.disabled {
2062-
queue!(
2063-
output,
2064-
style::SetForegroundColor(Color::DarkGrey),
2065-
style::Print(format!(" {} (disabled)\n", name)),
2066-
style::SetForegroundColor(Color::Reset)
2067-
)?;
2068-
} else {
2069-
queue!(output, style::Print(format!(" {}\n", name)),)?;
2070-
}
2071-
}
2072-
}
2073-
Ok(())
2074-
}
20752102
queue!(
20762103
self.output,
20772104
style::SetAttribute(Attribute::Bold),
@@ -3363,6 +3390,45 @@ impl ChatContext {
33633390
}
33643391
}
33653392

3393+
/// Prints hook configuration grouped by trigger: conversation session start or per user message
3394+
fn print_hook_section(output: &mut impl Write, hooks: &HashMap<String, Hook>, trigger: HookTrigger) -> Result<()> {
3395+
let section = match trigger {
3396+
HookTrigger::ConversationStart => "On Session Start",
3397+
HookTrigger::PerPrompt => "Per User Message",
3398+
};
3399+
let hooks: Vec<(&String, &Hook)> = hooks.iter().filter(|(_, h)| h.trigger == trigger).collect();
3400+
3401+
queue!(
3402+
output,
3403+
style::SetForegroundColor(Color::Cyan),
3404+
style::Print(format!(" {section}:\n")),
3405+
style::SetForegroundColor(Color::Reset),
3406+
)?;
3407+
3408+
if hooks.is_empty() {
3409+
queue!(
3410+
output,
3411+
style::SetForegroundColor(Color::DarkGrey),
3412+
style::Print(" <none>\n"),
3413+
style::SetForegroundColor(Color::Reset)
3414+
)?;
3415+
} else {
3416+
for (name, hook) in hooks {
3417+
if hook.disabled {
3418+
queue!(
3419+
output,
3420+
style::SetForegroundColor(Color::DarkGrey),
3421+
style::Print(format!(" {} (disabled)\n", name)),
3422+
style::SetForegroundColor(Color::Reset)
3423+
)?;
3424+
} else {
3425+
queue!(output, style::Print(format!(" {}\n", name)),)?;
3426+
}
3427+
}
3428+
}
3429+
Ok(())
3430+
}
3431+
33663432
#[derive(Debug)]
33673433
struct ToolUseEventBuilder {
33683434
pub conversation_id: String,

0 commit comments

Comments
 (0)