Skip to main content

opendev_tui/controllers/
slash_commands.rs

1//! Slash command registry and autocomplete.
2//!
3//! Mirrors Python `CommandRegistry` and `BUILTIN_COMMANDS` — provides the
4//! full set of slash commands available in the TUI with autocomplete support.
5
6/// A registered slash command.
7#[derive(Debug, Clone)]
8pub struct SlashCommand {
9    /// Command name (without the leading `/`).
10    pub name: &'static str,
11    /// Human-readable description.
12    pub description: &'static str,
13}
14
15/// All built-in slash commands.
16///
17/// Mirrors the Python `BUILTIN_COMMANDS` registry exactly.
18pub const BUILTIN_COMMANDS: &[SlashCommand] = &[
19    // Session management
20    SlashCommand {
21        name: "help",
22        description: "show available commands and help",
23    },
24    SlashCommand {
25        name: "exit",
26        description: "exit OpenDev",
27    },
28    SlashCommand {
29        name: "quit",
30        description: "exit OpenDev (alias for /exit)",
31    },
32    SlashCommand {
33        name: "clear",
34        description: "clear current session and start fresh",
35    },
36    SlashCommand {
37        name: "models",
38        description: "interactive model/provider selector (global)",
39    },
40    SlashCommand {
41        name: "session-models",
42        description: "set model for this session only",
43    },
44    // Execution commands
45    SlashCommand {
46        name: "mode",
47        description: "switch between NORMAL and PLAN mode",
48    },
49    // Advanced commands
50    SlashCommand {
51        name: "init",
52        description: "analyze codebase and generate AGENTS.md",
53    },
54    SlashCommand {
55        name: "mcp",
56        description: "manage MCP servers and tools",
57    },
58    // Background task management
59    SlashCommand {
60        name: "tasks",
61        description: "list background tasks",
62    },
63    SlashCommand {
64        name: "task",
65        description: "show output from a background task (usage: /task <id>)",
66    },
67    SlashCommand {
68        name: "kill",
69        description: "kill a background task (usage: /kill <id>)",
70    },
71    // Agent and skill management
72    SlashCommand {
73        name: "agents",
74        description: "create and manage custom agents",
75    },
76    SlashCommand {
77        name: "skills",
78        description: "create and manage custom skills with AI assistance",
79    },
80    SlashCommand {
81        name: "plugins",
82        description: "manage plugins and marketplaces",
83    },
84    // Autonomy
85    SlashCommand {
86        name: "autonomy",
87        description: "set autonomy level (manual/semi-auto/auto)",
88    },
89    // Utility commands
90    SlashCommand {
91        name: "sound",
92        description: "play a test notification sound",
93    },
94    SlashCommand {
95        name: "compact",
96        description: "manually compact conversation context",
97    },
98    // Undo/Redo/Share
99    SlashCommand {
100        name: "undo",
101        description: "undo last file changes",
102    },
103    SlashCommand {
104        name: "redo",
105        description: "redo undone changes",
106    },
107    SlashCommand {
108        name: "share",
109        description: "share session as HTML",
110    },
111    // Session management
112    SlashCommand {
113        name: "sessions",
114        description: "list saved sessions",
115    },
116    // Background agents
117    SlashCommand {
118        name: "bg",
119        description: "manage background agents",
120    },
121];
122
123/// Find commands matching a query prefix.
124///
125/// The query should be the text after `/` (e.g., for `/he`, pass `"he"`).
126pub fn find_matching_commands(query: &str) -> Vec<&'static SlashCommand> {
127    let query_lower = query.to_lowercase();
128    BUILTIN_COMMANDS
129        .iter()
130        .filter(|cmd| cmd.name.starts_with(&query_lower))
131        .collect()
132}
133
134/// Check if a command exists by exact name.
135pub fn is_command(name: &str) -> bool {
136    BUILTIN_COMMANDS.iter().any(|cmd| cmd.name == name)
137}
138
139#[cfg(test)]
140#[path = "slash_commands_tests.rs"]
141mod tests;