Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions crates/goose-cli/src/session/input.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ pub enum InputResult {
AddExtension(String),
AddBuiltin(String),
ToggleTheme,
SelectTheme(String),
Retry,
ListPrompts(Option<String>),
PromptCommand(PromptCommandOptions),
Expand Down Expand Up @@ -103,6 +104,22 @@ fn handle_slash_command(input: &str) -> Option<InputResult> {
Some(InputResult::Retry)
}
"/t" => Some(InputResult::ToggleTheme),
s if s.starts_with("/t ") => {
let t = s
.strip_prefix("/t ")
.unwrap_or_default()
.trim()
.to_lowercase();
if ["light", "dark", "ansi"].contains(&t.as_str()) {
Some(InputResult::SelectTheme(t))
} else {
println!(
"Theme Unavailable: {} Available themes are: light, dark, ansi",
t
);
Some(InputResult::Retry)
}
}
"/prompts" => Some(InputResult::ListPrompts(None)),
s if s.starts_with(CMD_PROMPTS) => {
// Parse arguments for /prompts command
Expand Down Expand Up @@ -234,6 +251,7 @@ fn print_help() {
"Available commands:
/exit or /quit - Exit the session
/t - Toggle Light/Dark/Ansi theme
/t <name> - Set theme directly (light, dark, ansi)
/extension <command> - Add a stdio extension (format: ENV1=val1 command args...)
/builtin <names> - Add builtin extensions by name (comma-separated)
/prompts [--extension <name>] - List all available prompts, optionally filtered by extension
Expand Down
22 changes: 22 additions & 0 deletions crates/goose-cli/src/session/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -496,6 +496,28 @@ impl Session {
output::set_theme(new_theme);
continue;
}

input::InputResult::SelectTheme(theme_name) => {
save_history(&mut editor);

let new_theme = match theme_name.as_str() {
"light" => {
println!("Switching to Light theme");
output::Theme::Light
}
"dark" => {
println!("Switching to Dark theme");
output::Theme::Dark
}
"ansi" => {
println!("Switching to Ansi theme");
output::Theme::Ansi
}
_ => output::Theme::Dark,
};
output::set_theme(new_theme);
continue;
}
input::InputResult::Retry => continue,
input::InputResult::ListPrompts(extension) => {
save_history(&mut editor);
Expand Down
11 changes: 11 additions & 0 deletions crates/goose-cli/src/session/output.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,17 @@ pub fn set_theme(theme: Theme) {
.set_param("GOOSE_CLI_THEME", Value::String(theme.as_config_string()))
.expect("Failed to set theme");
CURRENT_THEME.with(|t| *t.borrow_mut() = theme);

let config = Config::global();
let theme_str = match theme {
Theme::Light => "light",
Theme::Dark => "dark",
Theme::Ansi => "ansi",
};

if let Err(e) = config.set_param("GOOSE_CLI_THEME", Value::String(theme_str.to_string())) {
eprintln!("Failed to save theme setting to config: {}", e);
}
}

pub fn get_theme() -> Theme {
Expand Down
10 changes: 9 additions & 1 deletion documentation/docs/guides/goose-cli-commands.md
Original file line number Diff line number Diff line change
Expand Up @@ -540,6 +540,14 @@ All commands support tab completion. Press `<Tab>` after a slash (/) to cycle th

Goose CLI supports several shortcuts and built-in commands for easier navigation.

### Keyboard Navigation

- **`Ctrl+C`** - Interrupt the current request
- **`Ctrl+J`** - Add a newline
- **`Cmd+Up/Down arrows`** - Navigate through command history
- **`Cmd+Up/Down arrows`** - Navigate through command history

### Slash Commands
- **`/exit` or `/quit`** - Exit the session
- **`/t`** - Toggle between Light/Dark/Ansi themes
- **`/t <theme>`** - Set theme directly (`/t light`, `/t dark`, or `/t ansi`)
- **`/?` or `/help`** - Display the help menu
16 changes: 10 additions & 6 deletions ui/desktop/src/hooks/useMessageStream.ts
Original file line number Diff line number Diff line change
Expand Up @@ -317,15 +317,16 @@ export function useMessageStream({
const lastMessage = currentMessages[currentMessages.length - 1];
onFinish(lastMessage, parsedEvent.reason);
}

// Fetch updated session metadata with token counts
const sessionId = (extraMetadataRef.current.body as Record<string, unknown>)?.session_id as string;
const sessionId = (extraMetadataRef.current.body as Record<string, unknown>)
?.session_id as string;
if (sessionId) {
try {
const sessionResponse = await getSessionHistory({
path: { session_id: sessionId },
});

if (sessionResponse.data?.metadata) {
setSessionMetadata({
workingDir: sessionResponse.data.metadata.working_dir,
Expand All @@ -335,9 +336,12 @@ export function useMessageStream({
totalTokens: sessionResponse.data.metadata.total_tokens || null,
inputTokens: sessionResponse.data.metadata.input_tokens || null,
outputTokens: sessionResponse.data.metadata.output_tokens || null,
accumulatedTotalTokens: sessionResponse.data.metadata.accumulated_total_tokens || null,
accumulatedInputTokens: sessionResponse.data.metadata.accumulated_input_tokens || null,
accumulatedOutputTokens: sessionResponse.data.metadata.accumulated_output_tokens || null,
accumulatedTotalTokens:
sessionResponse.data.metadata.accumulated_total_tokens || null,
accumulatedInputTokens:
sessionResponse.data.metadata.accumulated_input_tokens || null,
accumulatedOutputTokens:
sessionResponse.data.metadata.accumulated_output_tokens || null,
});
}
} catch (error) {
Expand Down
Loading