diff --git a/docs/commands.md b/docs/commands.md index 402335ad..596a2530 100644 --- a/docs/commands.md +++ b/docs/commands.md @@ -9,15 +9,15 @@ This document is the reference for the visible slash commands available in Coven 1. [Command System Overview](#command-system-overview) 2. [Session & Navigation](#session--navigation) 3. [Model & Provider](#model--provider) — `/model`, `/providers`, `/connect`, `/thinking`, `/effort`, `/advisor`, `/fast` -4. [Configuration & Settings](#configuration--settings) — `/config`, `/keybindings`, `/permissions`, `/hooks`, `/mcp`, `/output-style`, `/theme`, `/statusline`, `/vim`, `/voice`, `/terminal-setup` -5. [Code & Git](#code--git) — `/commit`, `/diff`, `/undo`, `/revert`, `/review`, `/init`, `/search` -6. [Search & Files](#search--files) — `/context` -7. [Memory & Context](#memory--context) — `/memory`, `/usage`, `/cost`, `/status` +4. [Configuration & Settings](#configuration--settings) — `/config`, `/keybindings`, `/permissions`, `/hooks`, `/mcp`, `/output-style`, `/theme` +5. [Code & Git](#code--git) — `/commit`, `/diff`, `/review`, `/init`, `/search` +6. [Search & Files](#search--files) +7. [Memory & Context](#memory--context) — `/memory`, `/usage`, `/stats`, `/status` 8. [Agents & Tasks](#agents--tasks) — `/agents`, `/tasks`, `/goal`, `/managed-agents`, `/agent` 9. [Planning & Review](#planning--review) — `/plan`, `ultraplan` (CLI) 10. [MCP & Integrations](#mcp--integrations) — `/mcp`, `/skills`, `/plugin`, `/chrome` 11. [Authentication](#authentication) — `/login`, `/logout`, `/switch`, `/refresh` -12. [Display & Terminal](#display--terminal) — `/theme`, `/output-style`, `/statusline`, `/vim`, `/terminal-setup`, `/incant`, `/color` +12. [Display & Terminal](#display--terminal) — `/theme`, `/output-style`, `/incant` 13. [Diagnostics & Info](#diagnostics--info) — `/doctor`, `/version`, `/update` 14. [Export & Sharing](#export--sharing) — `/export`, `/copy`, `/share` 15. [Advanced & Internal](#advanced--internal) — `/thinking`, `/connect`, `/fork`, `/effort`, `/whisper`, `/sandbox`, `/think-back` @@ -125,14 +125,16 @@ Fork the current session into a new independent session that begins from the cur ### /rewind -Rewind the conversation to a previous message. Displays a numbered list of messages; enter a number to truncate history to that point and resume from there. - -``` -/rewind -/rewind -``` - ---- +Rewind the conversation to a previous message. Displays a numbered list of messages; enter a number to truncate history to that point and resume from there. + +``` +/rewind +/rewind +``` + +`/undo` and `/revert` remain available as hidden compatibility commands for one release, but new docs and command discovery route history work through `/rewind`. + +--- ### /compact @@ -358,54 +360,51 @@ Open the interactive theme picker. Preview and select a color theme for the Cove --- -### /statusline - -Configure the status line displayed at the bottom of the TUI. Toggle individual elements such as model name, token count, session name, and git branch. - -``` -/statusline -/statusline toggle model -/statusline toggle tokens -``` - ---- - -### /vim -**Aliases:** `vi` - -Toggle vim keybinding mode on or off. In vim mode the input field behaves like a vim editor (normal/insert/visual modes). Persisted to config. - -``` -/vim -/vim on -/vim off -``` - ---- - -### /voice - -Configure voice input/output. Requires a supported audio backend. Subcommands control microphone selection, TTS voice, and push-to-talk behavior. - -``` -/voice -/voice on -/voice off -/voice mic -/voice tts -``` - ---- - -### /terminal-setup - -Run the terminal capability detection and setup wizard. Checks for true-color support, font ligatures, Unicode rendering, and configures Coven Code accordingly. - -``` -/terminal-setup -``` - ---- +### /config statusline + +Configure the status line displayed at the bottom of the TUI. Toggle individual elements such as model name, token count, session name, and git branch. + +``` +/config statusline +/config statusline show model +/config statusline hide tokens +``` + +--- + +### /config vim + +Toggle vim keybinding mode on or off. In vim mode the input field behaves like a vim editor (normal/insert/visual modes). Persisted to config. + +``` +/config vim +/config vim on +/config vim off +``` + +--- + +### /config voice + +Configure voice input/output. Requires a supported audio backend. Subcommands control microphone selection, TTS voice, and push-to-talk behavior. + +``` +/config voice status +/config voice on +/config voice off +``` + +--- + +### /config terminal-setup + +Run the terminal capability detection and setup wizard. Checks for true-color support, font ligatures, Unicode rendering, and configures Coven Code accordingly. + +``` +/config terminal-setup +``` + +--- ## Code & Git @@ -431,32 +430,7 @@ Show file diffs for changes made during the current session. Displays a unified --- -### /undo - -Undo file changes made during the current session. Restores files to their state before Coven Code's last write operation. Can be called multiple times to step further back. - -``` -/undo -/undo -``` - ---- - -### /revert - -Revert file changes from an assistant turn back to their pre-turn state, using the shadow-git snapshot. `/undo` reverts the most recent edit; `/revert` reverts a chosen turn and removes that turn (and any later turns) from the session transcript. - -``` -/revert — revert the most recent assistant turn -/revert 2 — revert the second-to-last turn -/revert abc123 — revert the turn whose message id starts with 'abc123' -/revert list — list turns that have recorded file changes -/revert diff [n] — preview the shadow-git diff for a turn without reverting -``` - ---- - -### /review +### /review Review code changes via the model and optionally post the review to the associated GitHub PR. Runs `git diff ...HEAD` (or `git diff --cached` when no base is given) and sends the diff for a structured review. @@ -505,13 +479,13 @@ Search the codebase using natural language or regex patterns. Wraps the GrepTool ## Search & Files -### /context - -Analyze context window usage. Shows a breakdown of tokens consumed by system prompt, conversation history, file contents, and tool results. Helps identify what to compact or drop. - -``` -/context -``` +### /usage context + +Analyze context window usage. Shows a breakdown of tokens consumed by system prompt, conversation history, file contents, and tool results. Helps identify what to compact or drop. + +``` +/usage context +``` --- @@ -533,21 +507,23 @@ Manage session memory. Memory entries are short notes persisted across sessions. ### /usage -Display a detailed token usage breakdown for the current session. Shows input tokens, output tokens, cache reads, cache writes, and estimated cost per API call. - -``` -/usage -``` - ---- - -### /cost - -Show the total token usage and estimated cost for the current session. Provides a quick summary without the per-call breakdown of `/usage`. In the TUI, `/cost` opens the interactive stats dialog. - -``` -/cost -``` +Display a detailed token usage breakdown for the current session. Shows input tokens, output tokens, cache reads, cache writes, and estimated cost per API call. + +``` +/usage +/usage cost +/usage context +``` + +--- + +### /usage cost + +Show the total token usage and estimated cost for the current session. Provides a quick summary without the full account/quota context of `/usage`. In the TUI, `/stats` opens the interactive stats dialog. + +``` +/usage cost +``` For aggregate token / cost / tool statistics across saved sessions, use the `stats` CLI command: `coven-code stats [summary|sessions|tools|daily|session ]`. @@ -837,21 +813,21 @@ Documented above under [Configuration & Settings](#configuration--settings). --- -### /statusline - -Documented above under [Configuration & Settings](#configuration--settings). - ---- - -### /vim - -Documented above under [Configuration & Settings](#configuration--settings). - ---- - -### /terminal-setup - -Documented above under [Configuration & Settings](#configuration--settings). +### /config statusline + +Documented above under [Configuration & Settings](#configuration--settings). + +--- + +### /config vim + +Documented above under [Configuration & Settings](#configuration--settings). + +--- + +### /config terminal-setup + +Documented above under [Configuration & Settings](#configuration--settings). --- @@ -887,16 +863,16 @@ Intensity: --- -### /color - -Set the prompt bar color for the current session. Accepts standard color names or hex values. The color resets when the session ends unless saved via `/config`. - -``` -/color — open the interactive color picker -/color — set to a named color (e.g., blue, red, green) -/color #ff6b6b — set to a hex color value -/color default — reset to the theme default -``` +### /config color + +Set the prompt bar color for the current session. Accepts standard color names or hex values. The color resets when the session ends unless saved via `/config`. + +``` +/config color — show the current prompt color +/config color — set to a named color (e.g., blue, red, green) +/config color #ff6b6b — set to a hex color value +/config color default — reset to the theme default +``` --- @@ -1001,9 +977,9 @@ Documented above under [Model & Provider](#model--provider). --- -### /context - -Documented above under [Search & Files](#search--files). +### /usage context + +Documented above under [Search & Files](#search--files). --- @@ -1226,7 +1202,7 @@ adapters (`/agents`, `/add-dir`, `/branch`, `/tag`, `/ide`, | `ide` | Manage IDE integrations. | | `pr-comments` | Get comments from a GitHub PR. | | `ultraplan` | Launch the Ultraplan agentic code planner with extended thinking. | -| `stats` | Aggregate token / cost / tool stats across saved sessions (in the TUI, `/cost` opens the stats dialog). | +| `stats` | Aggregate token / cost / tool stats across saved sessions (in the TUI, `/stats` opens the stats dialog). | --- @@ -1238,13 +1214,13 @@ Not all commands are available in all contexts. When running with `--remote`, only a restricted set of commands is available: -`session`, `exit`, `clear`, `help`, `theme`, `vim`, `cost`, `usage`, `plan`, `keybindings`, `statusline` +`session`, `exit`, `clear`, `help`, `theme`, `config`, `usage`, `plan`, `keybindings` ### Bridge Mode Over the Remote Control bridge (used by IDE integrations), only `local`-type commands are forwarded: -`compact`, `clear`, `cost` +`compact`, `clear`, `usage` ### Availability-Restricted Commands @@ -1254,5 +1230,5 @@ Some commands are available only under certain account or platform conditions: |---------|-------------| | `/fast` | Available when a fast-mode model is configured for the active provider | | `/sandbox` | Functional on macOS, Linux, WSL2 only; no-op on native Windows | -| `/voice` | Requires an audio backend plus `OPENAI_API_KEY` or `WHISPER_ENDPOINT_URL` for transcription | +| `/config voice` | Requires an audio backend plus `OPENAI_API_KEY` or `WHISPER_ENDPOINT_URL` for transcription | | `/chrome` | Requires a running Chrome/Chromium instance launched with remote debugging enabled | diff --git a/docs/src/demos.js b/docs/src/demos.js index 47d8f325..086c1023 100644 --- a/docs/src/demos.js +++ b/docs/src/demos.js @@ -244,28 +244,29 @@ export function registerDemos(Alpine) { { id: '/advisor', category: 'Model', desc: 'Set a secondary advisor model' }, { id: '/fast', category: 'Model', desc: 'Toggle fast mode (smaller, faster model)' }, // Config - { id: '/config', category: 'Config', desc: 'Open the settings editor' }, + { id: '/config', category: 'Config', desc: 'Open settings or adjust UI config' }, + { id: '/config color', category: 'Config', desc: 'Set the prompt bar color' }, + { id: '/config statusline', category: 'Config', desc: 'Configure status line' }, + { id: '/config vim', category: 'Config', desc: 'Toggle vim mode' }, + { id: '/config voice', category: 'Config', desc: 'Voice input mode' }, + { id: '/config terminal-setup', category: 'Config', desc: 'Run terminal capability checks' }, { id: '/keybindings', category: 'Config', desc: 'Open the interactive keybinding editor' }, { id: '/permissions', category: 'Config', desc: 'Manage tool permission rules' }, { id: '/hooks', category: 'Config', desc: 'Inspect active hooks' }, { id: '/mcp', category: 'Config', desc: 'Manage MCP servers' }, { id: '/output-style', category: 'Config', desc: 'Switch output style' }, { id: '/theme', category: 'Config', desc: 'Switch visual theme' }, - { id: '/statusline', category: 'Config', desc: 'Configure status line' }, - { id: '/vim', category: 'Config', desc: 'Toggle vim mode' }, - { id: '/voice', category: 'Config', desc: 'Voice input mode' }, // Code & Git { id: '/commit', category: 'Code & Git', desc: 'Stage and commit current changes', keywords: 'git' }, { id: '/diff', category: 'Code & Git', desc: 'Show working-tree diff', keywords: 'git' }, - { id: '/undo', category: 'Code & Git', desc: 'Undo the last file edit (uses snapshot)' }, { id: '/review', category: 'Code & Git', desc: 'Review a PR or current changes' }, { id: '/security-review', category: 'Code & Git', desc: 'Security audit of pending changes' }, { id: '/init', category: 'Code & Git', desc: 'Initialise a new AGENTS.md for the project' }, { id: '/search', category: 'Code & Git', desc: 'Codebase search', keywords: 'grep find' }, // Memory & Cost { id: '/memory', category: 'Memory & Cost', desc: 'Browse persistent memory entries' }, - { id: '/context', category: 'Memory & Cost', desc: 'Show context window usage' }, - { id: '/cost', category: 'Memory & Cost', desc: 'Token usage and dollar cost for the session', keywords: 'tokens money' }, + { id: '/usage context', category: 'Memory & Cost', desc: 'Show context window usage' }, + { id: '/usage cost', category: 'Memory & Cost', desc: 'Token usage and dollar cost for the session', keywords: 'tokens money' }, { id: '/usage', category: 'Memory & Cost', desc: 'Session usage statistics' }, { id: '/stats', category: 'Memory & Cost', desc: 'Session statistics' }, { id: '/insights', category: 'Memory & Cost', desc: 'Session statistics and tool usage report' }, @@ -290,7 +291,6 @@ export function registerDemos(Alpine) { { id: '/rocky', category: 'Display', desc: 'Rocky (Project Hail Mary) speech mode' }, { id: '/normal', category: 'Display', desc: 'Deactivate speech modes' }, { id: '/mobile', category: 'Display', desc: 'Compact mobile-friendly rendering' }, - { id: '/color', category: 'Display', desc: 'Adjust colour palette at runtime' }, { id: '/stickers', category: 'Display', desc: 'Toggle sticker rendering' }, // Coven { id: '/coven', category: 'Coven', desc: 'Substrate surface: kill, log, send, familiars, etc.' }, diff --git a/docs/src/palette-data.js b/docs/src/palette-data.js index 7ddc0c78..ac45bf46 100644 --- a/docs/src/palette-data.js +++ b/docs/src/palette-data.js @@ -34,25 +34,28 @@ export const STATIC_PALETTE_ITEMS = [ ['/effort', 'Model', 'Set extended-thinking effort level'], ['/advisor', 'Model', 'Set a secondary advisor model'], ['/fast', 'Model', 'Toggle fast mode (smaller, faster model)'], - ['/config', 'Config', 'Open the settings editor'], + ['/config', 'Config', 'Open settings or adjust UI config'], + ['/config color', 'Config', 'Set the prompt bar color'], + ['/config statusline','Config', 'Configure the TUI status line'], + ['/config vim', 'Config', 'Toggle vim mode'], + ['/config voice', 'Config', 'Voice input mode'], + ['/config terminal-setup','Config', 'Run terminal capability checks'], ['/keybindings', 'Config', 'Open the interactive keybinding editor'], ['/permissions', 'Config', 'Manage tool permission rules'], ['/hooks', 'Config', 'Inspect active hooks'], ['/mcp', 'Config', 'Manage MCP servers'], ['/output-style', 'Config', 'Switch output style'], ['/theme', 'Config', 'Switch visual theme'], - ['/vim', 'Config', 'Toggle vim mode'], - ['/voice', 'Config', 'Voice input mode'], ['/commit', 'Code & Git', 'Stage and commit current changes'], ['/diff', 'Code & Git', 'Show working-tree diff'], - ['/undo', 'Code & Git', 'Undo the last file edit'], ['/review', 'Code & Git', 'Review a PR or current changes'], ['/security-review', 'Code & Git', 'Security audit of pending changes'], ['/init', 'Code & Git', 'Initialise a new AGENTS.md for the project'], ['/search', 'Code & Git', 'Codebase search'], ['/memory', 'Memory & Cost', 'Browse persistent memory entries'], - ['/context', 'Memory & Cost', 'Show context window usage'], - ['/cost', 'Memory & Cost', 'Token usage and dollar cost for the session'], + ['/usage context', 'Memory & Cost', 'Show context window usage'], + ['/usage cost', 'Memory & Cost', 'Token usage and dollar cost for the session'], + ['/stats', 'Memory & Cost', 'Open the interactive session statistics dialog'], ['/insights', 'Memory & Cost', 'Session statistics and tool usage report'], ['/agents', 'Agents & Tasks', 'List built-in, custom, and familiar agents'], ['/agent', 'Agents & Tasks', 'Switch active agent for this session'], diff --git a/src-rust/crates/commands/src/lib.rs b/src-rust/crates/commands/src/lib.rs index fe969a3a..87e3f821 100644 --- a/src-rust/crates/commands/src/lib.rs +++ b/src-rust/crates/commands/src/lib.rs @@ -657,6 +657,9 @@ impl SlashCommand for CostCommand { fn name(&self) -> &str { "cost" } + fn hidden(&self) -> bool { + true + } fn description(&self) -> &str { "Show token usage and cost for this session" } @@ -820,17 +823,60 @@ impl SlashCommand for ConfigCommand { fn description(&self) -> &str { "Show or modify configuration settings" } + fn help(&self) -> &str { + "Usage: /config [show|get|set|unset|color|vim|voice|statusline|terminal-setup] ...\n\n\ + Shows or modifies configuration settings.\n\n\ + Core settings:\n\ + /config\n\ + /config set theme \n\ + /config set output-style \n\ + /config set model \n\ + /config set permission-mode \n\ + /config unset \n\n\ + UI settings:\n\ + /config color []\n\ + /config vim [on|off]\n\ + /config voice [on|off|status]\n\ + /config statusline [show|hide] [cost|tokens|model|time|all]\n\ + /config terminal-setup" + } async fn execute(&self, args: &str, ctx: &mut CommandContext) -> CommandResult { let args = args.trim(); if args.is_empty() || matches!(args, "show" | "get") { let json = serde_json::to_string_pretty(&ctx.config).unwrap_or_default(); return CommandResult::Message(format!( - "Current configuration:\n{}\n\nUsage:\n /config\n /config set theme \n /config set output-style \n /config set model \n /config set permission-mode \n /config unset ", - json + "Current configuration:\n{}\n\n{}", + json, + self.help() )); } + let mut subcommand_parts = args.splitn(2, char::is_whitespace); + let subcommand = subcommand_parts.next().unwrap_or_default(); + let subcommand_args = subcommand_parts.next().unwrap_or_default().trim(); + match subcommand { + "color" | "prompt-color" | "prompt_color" => { + return ColorCommand.execute(subcommand_args, ctx).await; + } + "vim" | "vi" | "editor" | "editor-mode" | "editor_mode" => { + return VimCommand.execute(subcommand_args, ctx).await; + } + "voice" => { + return VoiceCommand.execute(subcommand_args, ctx).await; + } + "statusline" | "status-line" | "status_line" => { + return StatuslineCommand.execute(subcommand_args, ctx).await; + } + "terminal-setup" | "terminal_setup" | "terminal" => { + if !subcommand_args.is_empty() { + return CommandResult::Error("Usage: /config terminal-setup".to_string()); + } + return TerminalSetupCommand.execute("", ctx).await; + } + _ => {} + } + if let Some(key) = args.strip_prefix("get ").map(str::trim) { return match key { "theme" => CommandResult::Message(format!("theme = {:?}", ctx.config.theme)), @@ -1003,6 +1049,9 @@ impl SlashCommand for ColorCommand { fn name(&self) -> &str { "color" } + fn hidden(&self) -> bool { + true + } fn description(&self) -> &str { "Set or show the prompt bar color for this session" } @@ -1935,12 +1984,28 @@ impl SlashCommand for UsageCommand { "Show API usage, quotas, and rate limit status" } fn help(&self) -> &str { - "Usage: /usage\n\n\ + "Usage: /usage [cost|context]\n\n\ Shows current session API usage and account quota information.\n\ - For cost details, use /cost." + Use /usage cost for the session cost breakdown or /usage context for context-window details.\n\ + The legacy /cost and /context commands remain hidden compatibility aliases." } - async fn execute(&self, _args: &str, ctx: &mut CommandContext) -> CommandResult { + async fn execute(&self, args: &str, ctx: &mut CommandContext) -> CommandResult { + let mut parts = args.trim().splitn(2, char::is_whitespace); + let subcommand = parts.next().unwrap_or_default(); + let rest = parts.next().unwrap_or_default().trim(); + match subcommand { + "" | "summary" | "quota" | "status" => {} + "cost" | "costs" => return CostCommand.execute(rest, ctx).await, + "context" | "window" => return ContextCommand.execute(rest, ctx).await, + other => { + return CommandResult::Error(format!( + "Unknown usage view '{}'. Use: /usage [cost|context]", + other + )) + } + } + let input = ctx.cost_tracker.input_tokens(); let output = ctx.cost_tracker.output_tokens(); let cache_creation = ctx.cost_tracker.cache_creation_tokens(); @@ -5118,7 +5183,9 @@ impl SlashCommand for RewindCommand { fn help(&self) -> &str { "Usage: /rewind\n\ Opens an interactive overlay to select the message to rewind to.\n\ - Use ↑↓ to navigate, Enter to select, y/n to confirm." + Use ↑↓ to navigate, Enter to select, y/n to confirm.\n\n\ + The legacy /undo and /revert file-rollback commands remain available \ + as hidden compatibility commands for this release." } async fn execute(&self, _args: &str, ctx: &mut CommandContext) -> CommandResult { @@ -5491,6 +5558,9 @@ impl SlashCommand for ContextCommand { fn name(&self) -> &str { "context" } + fn hidden(&self) -> bool { + true + } fn description(&self) -> &str { "Show context window usage (tokens used / available)" } @@ -6134,6 +6204,9 @@ impl SlashCommand for VimCommand { fn name(&self) -> &str { "vim" } + fn hidden(&self) -> bool { + true + } fn aliases(&self) -> Vec<&str> { vec!["vi"] } @@ -6194,6 +6267,9 @@ impl SlashCommand for VoiceCommand { fn name(&self) -> &str { "voice" } + fn hidden(&self) -> bool { + true + } fn description(&self) -> &str { "Toggle voice input mode on/off" } @@ -6383,6 +6459,9 @@ impl SlashCommand for StatuslineCommand { fn name(&self) -> &str { "statusline" } + fn hidden(&self) -> bool { + true + } fn description(&self) -> &str { "Configure what is shown in the status line" } @@ -6537,6 +6616,9 @@ impl SlashCommand for TerminalSetupCommand { fn name(&self) -> &str { "terminal-setup" } + fn hidden(&self) -> bool { + true + } fn description(&self) -> &str { "Help configure your terminal for optimal Coven Code use" } @@ -7361,6 +7443,9 @@ impl SlashCommand for UndoCommand { fn name(&self) -> &str { "undo" } + fn hidden(&self) -> bool { + true + } fn aliases(&self) -> Vec<&str> { vec![] } @@ -7384,6 +7469,9 @@ impl SlashCommand for RevertCommand { fn name(&self) -> &str { "revert" } + fn hidden(&self) -> bool { + true + } fn description(&self) -> &str { "Revert file changes from an assistant turn back to pre-turn state" } @@ -9564,6 +9652,103 @@ mod tests { assert!(find_command("/clear").is_some()); } + #[test] + fn phase_two_legacy_commands_are_hidden_but_callable() { + let hidden_legacy = [ + "color", + "context", + "cost", + "revert", + "statusline", + "terminal-setup", + "undo", + "vim", + "voice", + ]; + + for name in hidden_legacy { + let command = find_command(name).unwrap_or_else(|| panic!("{name} should resolve")); + assert!( + command.hidden(), + "{name} should stay callable as a hidden one-release compatibility alias" + ); + } + + let visible_names: std::collections::HashSet<&str> = all_commands() + .iter() + .filter(|command| !command.hidden()) + .map(|command| command.name()) + .collect(); + for name in hidden_legacy { + assert!( + !visible_names.contains(name), + "{name} should not be a visible primary command" + ); + } + } + + #[tokio::test] + async fn config_command_owns_folded_ui_settings() { + let _guard = CommandEnvGuard::with_coven_home(None); + let mut ctx = make_ctx(); + let command = find_command("config").unwrap(); + + let result = command.execute("color", &mut ctx).await; + match result { + CommandResult::Message(message) => assert!(message.contains("Current prompt color")), + other => panic!("expected color status message, got {:?}", other), + } + + let result = command.execute("statusline", &mut ctx).await; + match result { + CommandResult::Message(message) => { + assert!(message.contains("Status line configuration")) + } + other => panic!("expected statusline message, got {:?}", other), + } + + let result = command.execute("voice status", &mut ctx).await; + match result { + CommandResult::Message(message) => assert!(message.contains("Voice mode")), + other => panic!("expected voice status message, got {:?}", other), + } + + let result = command.execute("vim on", &mut ctx).await; + match result { + CommandResult::Message(message) => assert!(message.contains("Editor mode set to vim")), + other => panic!("expected vim setting message, got {:?}", other), + } + } + + #[tokio::test] + async fn usage_command_owns_cost_and_context_views() { + let mut ctx = make_ctx(); + let command = find_command("usage").unwrap(); + + let result = command.execute("cost", &mut ctx).await; + match result { + CommandResult::Message(message) => assert!(message.contains("Session Cost")), + other => panic!("expected cost message, got {:?}", other), + } + + let result = command.execute("context", &mut ctx).await; + match result { + CommandResult::Message(message) => assert!(message.contains("Context Window Usage")), + other => panic!("expected context message, got {:?}", other), + } + } + + #[tokio::test] + async fn ide_slash_adapter_uses_named_command() { + let mut ctx = make_ctx(); + let command = find_command("ide").unwrap(); + let result = command.execute("status", &mut ctx).await; + match result { + CommandResult::Message(message) => assert!(message.contains("IDE")), + other => panic!("expected IDE status message, got {:?}", other), + } + } + #[test] fn test_find_command_by_alias() { // /help has aliases "h" and "?" @@ -10030,7 +10215,10 @@ mod tests { // `App::intercept_slash_command_with_args` (sends the current // session context to a Coven familiar). It is documented in // docs/familiars.md and lives in tui/src/handoff.rs. - const ALLOWED_ALIAS_NAMES: &[&str] = &["quit", "settings", "survey", "handoff"]; + // - stats: intercepted directly by the TUI to open the live stats + // dialog; the named CLI `stats` command handles aggregate saved + // session reports outside the TUI. + const ALLOWED_ALIAS_NAMES: &[&str] = &["quit", "settings", "survey", "handoff", "stats"]; let prompt_names: HashSet<&str> = claurst_tui::app::PROMPT_SLASH_COMMANDS .iter() diff --git a/src-rust/crates/tui/src/app.rs b/src-rust/crates/tui/src/app.rs index 9944a153..5365c7b1 100644 --- a/src-rust/crates/tui/src/app.rs +++ b/src-rust/crates/tui/src/app.rs @@ -62,7 +62,6 @@ pub const PROMPT_SLASH_COMMANDS: &[(&str, &str)] = &[ ("branch", "Create or switch session branches"), ("chrome", "Browser automation via Chrome DevTools Protocol"), ("clear", "Clear the conversation transcript"), - ("color", "Set the prompt bar color for the current session"), ( "commit", "Stage and commit changes (model drafts the message)", @@ -70,9 +69,7 @@ pub const PROMPT_SLASH_COMMANDS: &[(&str, &str)] = &[ ("compact", "Compact the conversation context"), ("config", "Open settings"), ("connect", "Connect an AI provider"), - ("context", "Show context window and rate limit usage"), ("copy", "Copy the last assistant response to clipboard"), - ("cost", "Show cost breakdown"), ( "coven", "Drive the local Coven daemon (sessions, harness runs, rituals)", @@ -132,7 +129,6 @@ pub const PROMPT_SLASH_COMMANDS: &[(&str, &str)] = &[ "Reload the active session plugin registry", ), ("resume", "Resume a previous session"), - ("revert", "Revert a file to its pre-session state"), ("review", "Review changes (git diff)"), ("rewind", "Rewind to an earlier turn"), ("sandbox", "Toggle sandboxed shell execution"), @@ -145,22 +141,17 @@ pub const PROMPT_SLASH_COMMANDS: &[(&str, &str)] = &[ ), ("skills", "List and manage skills"), ("status", "Show the current session status"), - ("statusline", "Configure the TUI status line"), + ("stats", "Open the interactive session statistics dialog"), ("survey", "Open session feedback survey"), ("switch", "Switch the active account for a provider"), ("tag", "Tag the current session with a label"), ("tasks", "Manage tracked background tasks"), - ( - "terminal-setup", - "Run the terminal capability detection wizard", - ), ("theme", "Open the theme picker"), ( "think-back", "Show extended-thinking traces from previous responses", ), ("thinking", "Configure extended thinking for the session"), - ("undo", "Undo a file change made during this session"), ( "update", "Check for updates and upgrade to the latest version", @@ -171,8 +162,6 @@ pub const PROMPT_SLASH_COMMANDS: &[(&str, &str)] = &[ ), ("usage", "Detailed per-call token usage breakdown"), ("version", "Display the current Coven Code version"), - ("vim", "Toggle vim keybindings"), - ("voice", "Toggle voice input mode"), ( "whisper", "Whisper a side question to your familiar (not kept in history)", @@ -181,13 +170,9 @@ pub const PROMPT_SLASH_COMMANDS: &[(&str, &str)] = &[ fn help_command_category(name: &str) -> &'static str { match name { - "connect" | "model" | "providers" | "refresh" | "fast" | "effort" | "voice" => { - "Model & Provider" - } - "diff" | "review" | "rewind" | "revert" | "undo" | "export" | "copy" | "share" => { - "Review & History" - } - "cost" | "context" | "usage" | "doctor" | "status" => "Diagnostics", + "connect" | "model" | "providers" | "refresh" | "fast" | "effort" => "Model & Provider", + "diff" | "review" | "rewind" | "export" | "copy" | "share" => "Review & History", + "usage" | "doctor" | "status" | "stats" => "Diagnostics", "config" | "settings" | "theme" | "keybindings" | "hooks" | "mcp" | "import-config" => { "Workspace" } @@ -2520,6 +2505,9 @@ impl App { /// Handle slash commands that should open UI screens rather than execute /// as normal commands. Returns `true` if the command was intercepted. pub fn intercept_slash_command_with_args(&mut self, cmd: &str, args: &str) -> bool { + if !args.trim().is_empty() && matches!(cmd, "config" | "settings" | "usage") { + return false; + } if cmd == "mcp" && !args.trim().is_empty() { return false; } @@ -7881,6 +7869,14 @@ role = "Research" assert!(!app.prompt_input.vim_enabled); } + #[test] + fn config_with_args_reaches_command_layer() { + let mut app = make_app(); + assert!(!app.settings_screen.visible); + assert!(!app.intercept_slash_command_with_args("config", "vim on")); + assert!(!app.settings_screen.visible); + } + #[test] fn test_model_slash_command_opens_picker() { let mut app = make_app();