Skip to content

Commit aab92d3

Browse files
echobtfactorydroid
andauthored
feat(tui): register missing slash commands for autocompletion (#427)
Add 16 missing slash commands to the TUI command registry and executor: Registry (autocompletion): - /plugins (/plugin) - List installed plugins - /cost - Show token usage and cost - /bug - Report a bug - /delegates - Manage custom delegates (subagents) - /spec - Toggle specification mode - /bg-process - Manage background processes - /ide - Manage IDE integration (VS Code, Cursor) - /install-github-app - Install the Cortex GitHub App - /review - Review code changes - /experimental (/exp, /features) - Manage experimental features - /ratelimits (/limits, /quota) - Show API rate limits and usage - /ghost - Manage ghost commits for undo - /multiedit (/sed, /replace) - Search and replace across multiple files - /diagnostics (/diag, /lint) - Show LSP diagnostics for a file - /hooks - Manage file hooks (formatters, linters) - /custom-commands (/cc) - Manage custom commands These commands were defined in cortex-engine/src/commands.rs but were not registered in the TUI, so they had no autocompletion support. Follows AGENTS.md guidelines for registering commands in BOTH places: - registry.rs (for autocompletion) - executor.rs (for execution) Co-authored-by: Droid Agent <droid@factory.ai>
1 parent ad1d48f commit aab92d3

2 files changed

Lines changed: 326 additions & 0 deletions

File tree

cortex-tui/src/commands/executor.rs

Lines changed: 178 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,24 @@ impl CommandExecutor {
179179
"crash" => CommandResult::Error("Crash test triggered".to_string()),
180180
"eval" => self.cmd_eval(cmd),
181181

182+
// ============ DEVELOPMENT & TOOLS ============
183+
"plugins" | "plugin" => CommandResult::Async("plugins:list".to_string()),
184+
"cost" => CommandResult::Async("cost".to_string()),
185+
"bug" => self.cmd_bug(cmd),
186+
"delegates" => self.cmd_delegates(cmd),
187+
"spec" => self.cmd_spec(cmd),
188+
"bg-process" => self.cmd_bg_process(cmd),
189+
"ide" => CommandResult::Async("ide:status".to_string()),
190+
"install-github-app" => CommandResult::Async("github:install-app".to_string()),
191+
"review" => self.cmd_review(cmd),
192+
"experimental" | "exp" | "features" => self.cmd_experimental(cmd),
193+
"ratelimits" | "limits" | "quota" => CommandResult::Async("ratelimits".to_string()),
194+
"ghost" => self.cmd_ghost(cmd),
195+
"multiedit" | "sed" | "replace" => self.cmd_multiedit(cmd),
196+
"diagnostics" | "diag" | "lint" => self.cmd_diagnostics(cmd),
197+
"hooks" => self.cmd_hooks(cmd),
198+
"custom-commands" | "cc" => self.cmd_custom_commands(cmd),
199+
182200
// Unknown (shouldn't reach here if registry check passed)
183201
_ => CommandResult::NotFound(format!("No handler for: /{}", cmd.name)),
184202
}
@@ -676,6 +694,166 @@ impl CommandExecutor {
676694
CommandResult::Async(format!("eval:{}", cmd.args_string()))
677695
}
678696
}
697+
698+
// ========== DEVELOPMENT & TOOLS ==========
699+
700+
fn cmd_bug(&self, cmd: &ParsedCommand) -> CommandResult {
701+
if cmd.args.is_empty() {
702+
CommandResult::OpenModal(ModalType::Form("bug".to_string()))
703+
} else {
704+
CommandResult::Async(format!("bug:report:{}", cmd.args_string()))
705+
}
706+
}
707+
708+
fn cmd_delegates(&self, cmd: &ParsedCommand) -> CommandResult {
709+
match cmd.first_arg() {
710+
Some("create") => CommandResult::Async("delegates:create".to_string()),
711+
Some("list") => CommandResult::Async("delegates:list".to_string()),
712+
Some("reload") => CommandResult::Async("delegates:reload".to_string()),
713+
None => CommandResult::Async("delegates:list".to_string()),
714+
Some(other) => CommandResult::Error(format!(
715+
"Unknown delegates action: {}. Use: create, list, reload",
716+
other
717+
)),
718+
}
719+
}
720+
721+
fn cmd_spec(&self, cmd: &ParsedCommand) -> CommandResult {
722+
match cmd.first_arg() {
723+
Some("off") | Some("false") => {
724+
CommandResult::SetValue("spec_mode".to_string(), "false".to_string())
725+
}
726+
Some("on") | Some("true") | None => {
727+
CommandResult::SetValue("spec_mode".to_string(), "true".to_string())
728+
}
729+
Some(other) => {
730+
CommandResult::Error(format!("Invalid spec mode value: {}. Use on|off", other))
731+
}
732+
}
733+
}
734+
735+
fn cmd_bg_process(&self, cmd: &ParsedCommand) -> CommandResult {
736+
let action = cmd.first_arg().unwrap_or("list");
737+
match action {
738+
"list" => CommandResult::Async("bg:list".to_string()),
739+
"start" => {
740+
if let Some(target) = cmd.args.get(1) {
741+
CommandResult::Async(format!("bg:start:{}", target))
742+
} else {
743+
CommandResult::Error("Usage: /bg-process start <command>".to_string())
744+
}
745+
}
746+
"stop" | "kill" => {
747+
if let Some(target) = cmd.args.get(1) {
748+
CommandResult::Async(format!("bg:stop:{}", target))
749+
} else {
750+
CommandResult::Error("Usage: /bg-process stop <pid>".to_string())
751+
}
752+
}
753+
_ => CommandResult::Error(format!(
754+
"Unknown action: {}. Use: list, start, stop, kill",
755+
action
756+
)),
757+
}
758+
}
759+
760+
fn cmd_review(&self, cmd: &ParsedCommand) -> CommandResult {
761+
let target = cmd.first_arg().unwrap_or("uncommitted");
762+
// Check for --base flag
763+
let base_branch = cmd
764+
.args
765+
.iter()
766+
.find(|a| a.starts_with("--base="))
767+
.map(|a| a.trim_start_matches("--base="));
768+
769+
match base_branch {
770+
Some(base) => CommandResult::Async(format!("review:{}:base={}", target, base)),
771+
None => CommandResult::Async(format!("review:{}", target)),
772+
}
773+
}
774+
775+
fn cmd_experimental(&self, cmd: &ParsedCommand) -> CommandResult {
776+
let feature = cmd.first_arg();
777+
let enable = cmd.args.iter().any(|a| a == "--enable");
778+
let disable = cmd.args.iter().any(|a| a == "--disable");
779+
780+
match (feature, enable, disable) {
781+
(Some(f), true, false) => CommandResult::Async(format!("experimental:enable:{}", f)),
782+
(Some(f), false, true) => CommandResult::Async(format!("experimental:disable:{}", f)),
783+
(Some(f), false, false) => CommandResult::Async(format!("experimental:status:{}", f)),
784+
(None, _, _) => CommandResult::Async("experimental:list".to_string()),
785+
_ => CommandResult::Error("Cannot use both --enable and --disable".to_string()),
786+
}
787+
}
788+
789+
fn cmd_ghost(&self, cmd: &ParsedCommand) -> CommandResult {
790+
match cmd.first_arg() {
791+
Some("list") => CommandResult::Async("ghost:list".to_string()),
792+
Some("cleanup") => CommandResult::Async("ghost:cleanup".to_string()),
793+
Some("status") | None => CommandResult::Async("ghost:status".to_string()),
794+
Some(other) => CommandResult::Error(format!(
795+
"Unknown ghost action: {}. Use: status, list, cleanup",
796+
other
797+
)),
798+
}
799+
}
800+
801+
fn cmd_multiedit(&self, cmd: &ParsedCommand) -> CommandResult {
802+
if cmd.args.len() < 2 {
803+
return CommandResult::Error(
804+
"Usage: /multiedit <pattern> <replacement> [--glob=pattern]".to_string(),
805+
);
806+
}
807+
808+
let pattern = &cmd.args[0];
809+
let replacement = &cmd.args[1];
810+
811+
// Check for --glob flag
812+
let glob = cmd
813+
.args
814+
.iter()
815+
.find(|a| a.starts_with("--glob="))
816+
.map(|a| a.trim_start_matches("--glob="));
817+
818+
match glob {
819+
Some(g) => {
820+
CommandResult::Async(format!("multiedit:{}:{}:glob={}", pattern, replacement, g))
821+
}
822+
None => CommandResult::Async(format!("multiedit:{}:{}", pattern, replacement)),
823+
}
824+
}
825+
826+
fn cmd_diagnostics(&self, cmd: &ParsedCommand) -> CommandResult {
827+
match cmd.first_arg() {
828+
Some(file) => CommandResult::Async(format!("diagnostics:{}", file)),
829+
None => CommandResult::Async("diagnostics:all".to_string()),
830+
}
831+
}
832+
833+
fn cmd_hooks(&self, cmd: &ParsedCommand) -> CommandResult {
834+
match cmd.first_arg() {
835+
Some("list") | None => CommandResult::Async("hooks:list".to_string()),
836+
Some("run") => CommandResult::Async("hooks:run".to_string()),
837+
Some("enable") => CommandResult::Async("hooks:enable".to_string()),
838+
Some("disable") => CommandResult::Async("hooks:disable".to_string()),
839+
Some(other) => CommandResult::Error(format!(
840+
"Unknown hooks action: {}. Use: list, run, enable, disable",
841+
other
842+
)),
843+
}
844+
}
845+
846+
fn cmd_custom_commands(&self, cmd: &ParsedCommand) -> CommandResult {
847+
match cmd.first_arg() {
848+
Some("create") => CommandResult::Async("custom-commands:create".to_string()),
849+
Some("list") | None => CommandResult::Async("custom-commands:list".to_string()),
850+
Some("reload") => CommandResult::Async("custom-commands:reload".to_string()),
851+
Some(other) => CommandResult::Error(format!(
852+
"Unknown action: {}. Use: create, list, reload",
853+
other
854+
)),
855+
}
856+
}
679857
}
680858

681859
impl Default for CommandExecutor {

cortex-tui/src/commands/registry.rs

Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -864,6 +864,154 @@ pub fn register_builtin_commands(registry: &mut CommandRegistry) {
864864
CommandCategory::Debug,
865865
true,
866866
));
867+
868+
// ========================================
869+
// DEVELOPMENT & TOOLS COMMANDS
870+
// ========================================
871+
872+
registry.register(CommandDef::new(
873+
"plugins",
874+
&["plugin"],
875+
"List installed plugins",
876+
"/plugins",
877+
CommandCategory::General,
878+
false,
879+
));
880+
881+
registry.register(CommandDef::new(
882+
"cost",
883+
&[],
884+
"Show token usage and cost",
885+
"/cost",
886+
CommandCategory::General,
887+
false,
888+
));
889+
890+
registry.register(CommandDef::new(
891+
"bug",
892+
&[],
893+
"Report a bug",
894+
"/bug [description]",
895+
CommandCategory::General,
896+
true,
897+
));
898+
899+
registry.register(CommandDef::new(
900+
"delegates",
901+
&[],
902+
"Manage custom delegates (subagents)",
903+
"/delegates [action]",
904+
CommandCategory::General,
905+
true,
906+
));
907+
908+
registry.register(CommandDef::new(
909+
"spec",
910+
&[],
911+
"Toggle specification mode",
912+
"/spec [off]",
913+
CommandCategory::General,
914+
true,
915+
));
916+
917+
registry.register(CommandDef::new(
918+
"bg-process",
919+
&[],
920+
"Manage background processes",
921+
"/bg-process [action] [target]",
922+
CommandCategory::General,
923+
true,
924+
));
925+
926+
registry.register(CommandDef::new(
927+
"ide",
928+
&[],
929+
"Manage IDE integration (VS Code, Cursor)",
930+
"/ide",
931+
CommandCategory::General,
932+
false,
933+
));
934+
935+
registry.register(CommandDef::new(
936+
"install-github-app",
937+
&[],
938+
"Install the Cortex GitHub App",
939+
"/install-github-app",
940+
CommandCategory::General,
941+
false,
942+
));
943+
944+
registry.register(CommandDef::new(
945+
"review",
946+
&[],
947+
"Review code changes",
948+
"/review [target] [--base=branch]",
949+
CommandCategory::General,
950+
true,
951+
));
952+
953+
registry.register(CommandDef::new(
954+
"experimental",
955+
&["exp", "features"],
956+
"Manage experimental features",
957+
"/experimental [feature] [--enable|--disable]",
958+
CommandCategory::General,
959+
true,
960+
));
961+
962+
registry.register(CommandDef::new(
963+
"ratelimits",
964+
&["limits", "quota"],
965+
"Show API rate limits and usage",
966+
"/ratelimits",
967+
CommandCategory::General,
968+
false,
969+
));
970+
971+
registry.register(CommandDef::new(
972+
"ghost",
973+
&[],
974+
"Manage ghost commits for undo",
975+
"/ghost [action]",
976+
CommandCategory::General,
977+
true,
978+
));
979+
980+
registry.register(CommandDef::new(
981+
"multiedit",
982+
&["sed", "replace"],
983+
"Search and replace across multiple files",
984+
"/multiedit <pattern> <replacement> [--glob=pattern]",
985+
CommandCategory::Files,
986+
true,
987+
));
988+
989+
registry.register(CommandDef::new(
990+
"diagnostics",
991+
&["diag", "lint"],
992+
"Show LSP diagnostics for a file",
993+
"/diagnostics [file]",
994+
CommandCategory::Debug,
995+
true,
996+
));
997+
998+
registry.register(CommandDef::new(
999+
"hooks",
1000+
&[],
1001+
"Manage file hooks (formatters, linters)",
1002+
"/hooks [action]",
1003+
CommandCategory::General,
1004+
true,
1005+
));
1006+
1007+
registry.register(CommandDef::new(
1008+
"custom-commands",
1009+
&["cc"],
1010+
"Manage custom commands",
1011+
"/custom-commands [action]",
1012+
CommandCategory::General,
1013+
true,
1014+
));
8671015
}
8681016

8691017
// ============================================================

0 commit comments

Comments
 (0)