Skip to content

Commit bff7823

Browse files
committed
Merge remote-tracking branch 'origin/main' into bskiser/add-import-export-commands
2 parents 0222bbd + b25b172 commit bff7823

File tree

3 files changed

+134
-45
lines changed

3 files changed

+134
-45
lines changed

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

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,8 @@ impl ContextSubcommand {
187187
<em>help</em> <black!>Show an explanation for the context command</black!>
188188
189189
<em>show [--expand]</em> <black!>Display the context rule configuration and matched files</black!>
190-
<black!>--expand: Print out each matched file's content</black!>
190+
<black!>--expand: Print out each matched file's content, hook</black!>
191+
<black!> configurations and last conversation summary </black!>
191192
192193
<em>add [--global] [--force] <<paths...>></em>
193194
<black!>Add context rules (filenames or glob patterns)</black!>
@@ -836,8 +837,26 @@ impl Command {
836837
}
837838
Self::Export { path, force }
838839
},
839-
_unknown_command => Self::Ask {
840-
prompt: input.to_string(),
840+
unknown_command => {
841+
let looks_like_path = {
842+
let after_slash_command_str = parts[1..].join(" ");
843+
unknown_command.contains('/')
844+
|| unknown_command.contains('.')
845+
|| unknown_command.contains('\\')
846+
|| after_slash_command_str.contains('/')
847+
|| after_slash_command_str.contains('.')
848+
|| after_slash_command_str.contains('\\')
849+
};
850+
if looks_like_path {
851+
return Ok(Self::Ask {
852+
prompt: command.to_string(),
853+
});
854+
}
855+
856+
return Err(format!(
857+
"Unknown command: '/{}'. Type '/help' to see available commands.\nTo use a literal slash at the beginning of your message, escape it with a backslash (e.g., '\\//hey' for '/hey').",
858+
unknown_command
859+
));
841860
},
842861
});
843862
}

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,10 @@ impl ConversationState {
148148
}
149149
}
150150

151+
pub fn latest_summary(&self) -> Option<&str> {
152+
self.latest_summary.as_deref()
153+
}
154+
151155
pub fn history(&self) -> &VecDeque<(UserMessage, AssistantMessage)> {
152156
&self.history
153157
}

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

Lines changed: 108 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1586,6 +1586,9 @@ impl ChatContext {
15861586
if let Some(context_manager) = &mut self.conversation_state.context_manager {
15871587
match subcommand {
15881588
command::ContextSubcommand::Show { expand } => {
1589+
fn map_chat_error(e: ErrReport) -> ChatError {
1590+
ChatError::Custom(e.to_string().into())
1591+
}
15891592
// Display global context
15901593
execute!(
15911594
self.output,
@@ -1623,6 +1626,28 @@ impl ChatContext {
16231626
}
16241627
}
16251628

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

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

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

3489+
/// Prints hook configuration grouped by trigger: conversation session start or per user message
3490+
fn print_hook_section(output: &mut impl Write, hooks: &HashMap<String, Hook>, trigger: HookTrigger) -> Result<()> {
3491+
let section = match trigger {
3492+
HookTrigger::ConversationStart => "On Session Start",
3493+
HookTrigger::PerPrompt => "Per User Message",
3494+
};
3495+
let hooks: Vec<(&String, &Hook)> = hooks.iter().filter(|(_, h)| h.trigger == trigger).collect();
3496+
3497+
queue!(
3498+
output,
3499+
style::SetForegroundColor(Color::Cyan),
3500+
style::Print(format!(" {section}:\n")),
3501+
style::SetForegroundColor(Color::Reset),
3502+
)?;
3503+
3504+
if hooks.is_empty() {
3505+
queue!(
3506+
output,
3507+
style::SetForegroundColor(Color::DarkGrey),
3508+
style::Print(" <none>\n"),
3509+
style::SetForegroundColor(Color::Reset)
3510+
)?;
3511+
} else {
3512+
for (name, hook) in hooks {
3513+
if hook.disabled {
3514+
queue!(
3515+
output,
3516+
style::SetForegroundColor(Color::DarkGrey),
3517+
style::Print(format!(" {} (disabled)\n", name)),
3518+
style::SetForegroundColor(Color::Reset)
3519+
)?;
3520+
} else {
3521+
queue!(output, style::Print(format!(" {}\n", name)),)?;
3522+
}
3523+
}
3524+
}
3525+
Ok(())
3526+
}
3527+
34623528
#[derive(Debug)]
34633529
struct ToolUseEventBuilder {
34643530
pub conversation_id: String,

0 commit comments

Comments
 (0)