feat(goose-cli): theme persistence & selection (#1693)

Co-authored-by: Bradley Axen <baxen@squareup.com>
This commit is contained in:
Shodipo Ayomide
2025-07-04 01:23:34 +01:00
committed by GitHub
parent f59077587f
commit 5e8e5fb7c2
5 changed files with 70 additions and 7 deletions

View File

@@ -11,6 +11,7 @@ pub enum InputResult {
AddExtension(String), AddExtension(String),
AddBuiltin(String), AddBuiltin(String),
ToggleTheme, ToggleTheme,
SelectTheme(String),
Retry, Retry,
ListPrompts(Option<String>), ListPrompts(Option<String>),
PromptCommand(PromptCommandOptions), PromptCommand(PromptCommandOptions),
@@ -103,6 +104,22 @@ fn handle_slash_command(input: &str) -> Option<InputResult> {
Some(InputResult::Retry) Some(InputResult::Retry)
} }
"/t" => Some(InputResult::ToggleTheme), "/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)), "/prompts" => Some(InputResult::ListPrompts(None)),
s if s.starts_with(CMD_PROMPTS) => { s if s.starts_with(CMD_PROMPTS) => {
// Parse arguments for /prompts command // Parse arguments for /prompts command
@@ -234,6 +251,7 @@ fn print_help() {
"Available commands: "Available commands:
/exit or /quit - Exit the session /exit or /quit - Exit the session
/t - Toggle Light/Dark/Ansi theme /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...) /extension <command> - Add a stdio extension (format: ENV1=val1 command args...)
/builtin <names> - Add builtin extensions by name (comma-separated) /builtin <names> - Add builtin extensions by name (comma-separated)
/prompts [--extension <name>] - List all available prompts, optionally filtered by extension /prompts [--extension <name>] - List all available prompts, optionally filtered by extension

View File

@@ -499,6 +499,28 @@ impl Session {
output::set_theme(new_theme); output::set_theme(new_theme);
continue; 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::Retry => continue,
input::InputResult::ListPrompts(extension) => { input::InputResult::ListPrompts(extension) => {
save_history(&mut editor); save_history(&mut editor);

View File

@@ -67,6 +67,17 @@ pub fn set_theme(theme: Theme) {
.set_param("GOOSE_CLI_THEME", Value::String(theme.as_config_string())) .set_param("GOOSE_CLI_THEME", Value::String(theme.as_config_string()))
.expect("Failed to set theme"); .expect("Failed to set theme");
CURRENT_THEME.with(|t| *t.borrow_mut() = 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 { pub fn get_theme() -> Theme {

View File

@@ -556,6 +556,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. Goose CLI supports several shortcuts and built-in commands for easier navigation.
### Keyboard Navigation
- **`Ctrl+C`** - Interrupt the current request - **`Ctrl+C`** - Interrupt the current request
- **`Ctrl+J`** - Add a newline - **`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

View File

@@ -319,7 +319,8 @@ export function useMessageStream({
} }
// Fetch updated session metadata with token counts // 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) { if (sessionId) {
try { try {
const sessionResponse = await getSessionHistory({ const sessionResponse = await getSessionHistory({
@@ -335,9 +336,12 @@ export function useMessageStream({
totalTokens: sessionResponse.data.metadata.total_tokens || null, totalTokens: sessionResponse.data.metadata.total_tokens || null,
inputTokens: sessionResponse.data.metadata.input_tokens || null, inputTokens: sessionResponse.data.metadata.input_tokens || null,
outputTokens: sessionResponse.data.metadata.output_tokens || null, outputTokens: sessionResponse.data.metadata.output_tokens || null,
accumulatedTotalTokens: sessionResponse.data.metadata.accumulated_total_tokens || null, accumulatedTotalTokens:
accumulatedInputTokens: sessionResponse.data.metadata.accumulated_input_tokens || null, sessionResponse.data.metadata.accumulated_total_tokens || null,
accumulatedOutputTokens: sessionResponse.data.metadata.accumulated_output_tokens || null, accumulatedInputTokens:
sessionResponse.data.metadata.accumulated_input_tokens || null,
accumulatedOutputTokens:
sessionResponse.data.metadata.accumulated_output_tokens || null,
}); });
} }
} catch (error) { } catch (error) {