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),
AddBuiltin(String),
ToggleTheme,
SelectTheme(String),
Retry,
ListPrompts(Option<String>),
PromptCommand(PromptCommandOptions),
@@ -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
@@ -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

View File

@@ -499,6 +499,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);

View File

@@ -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 {

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.
### 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

View File

@@ -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,
@@ -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) {