mirror of
https://github.com/openai/codex.git
synced 2026-10-29 19:08:43 +00:00
tui: unify slash command registration
Move usage strings, bare-form behavior, and inline-arg parser selection into the per-command slash spec so command registration lives in one authoritative table in both tui implementations. Co-authored-by: Codex <noreply@openai.com>
This commit is contained in:
co-authored by
Codex
parent
9e1f60ce42
commit
708a95ed4a
@@ -66,272 +66,420 @@ pub enum SlashCommand {
|
||||
MemoryUpdate,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub(crate) enum SlashCommandBareBehavior {
|
||||
DispatchesDirectly,
|
||||
OpensUi,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub(crate) enum SlashCommandParseKind {
|
||||
NoArgs,
|
||||
Fast,
|
||||
Rename,
|
||||
Plan,
|
||||
Review,
|
||||
SandboxReadRoot,
|
||||
}
|
||||
|
||||
impl SlashCommand {
|
||||
fn spec(self) -> SlashCommandSpec {
|
||||
pub(crate) fn spec(self) -> SlashCommandSpec {
|
||||
match self {
|
||||
SlashCommand::Model => SlashCommandSpec {
|
||||
description: "choose what model and reasoning effort to use",
|
||||
available_during_task: false,
|
||||
is_disabled: false,
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/model"],
|
||||
bare_behavior: SlashCommandBareBehavior::OpensUi,
|
||||
parse_kind: SlashCommandParseKind::NoArgs,
|
||||
},
|
||||
SlashCommand::Fast => SlashCommandSpec {
|
||||
description: "toggle Fast mode to enable fastest inference at 2X plan usage",
|
||||
available_during_task: false,
|
||||
is_disabled: false,
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/fast", "/fast [on|off|status]"],
|
||||
bare_behavior: SlashCommandBareBehavior::DispatchesDirectly,
|
||||
parse_kind: SlashCommandParseKind::Fast,
|
||||
},
|
||||
SlashCommand::Approvals => SlashCommandSpec {
|
||||
description: "choose what Codex is allowed to do",
|
||||
available_during_task: false,
|
||||
is_disabled: false,
|
||||
hide_in_command_popup: true,
|
||||
usage_lines: &["/approvals"],
|
||||
bare_behavior: SlashCommandBareBehavior::OpensUi,
|
||||
parse_kind: SlashCommandParseKind::NoArgs,
|
||||
},
|
||||
SlashCommand::Permissions => SlashCommandSpec {
|
||||
description: "choose what Codex is allowed to do",
|
||||
available_during_task: false,
|
||||
is_disabled: false,
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/permissions"],
|
||||
bare_behavior: SlashCommandBareBehavior::OpensUi,
|
||||
parse_kind: SlashCommandParseKind::NoArgs,
|
||||
},
|
||||
SlashCommand::ElevateSandbox => SlashCommandSpec {
|
||||
description: "set up elevated agent sandbox",
|
||||
available_during_task: false,
|
||||
is_disabled: false,
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/setup-default-sandbox"],
|
||||
bare_behavior: SlashCommandBareBehavior::DispatchesDirectly,
|
||||
parse_kind: SlashCommandParseKind::NoArgs,
|
||||
},
|
||||
SlashCommand::SandboxReadRoot => SlashCommandSpec {
|
||||
description: "let sandbox read a directory: /sandbox-add-read-dir <absolute_path>",
|
||||
available_during_task: false,
|
||||
is_disabled: !cfg!(target_os = "windows"),
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/sandbox-add-read-dir <absolute-path>"],
|
||||
bare_behavior: SlashCommandBareBehavior::DispatchesDirectly,
|
||||
parse_kind: SlashCommandParseKind::SandboxReadRoot,
|
||||
},
|
||||
SlashCommand::Experimental => SlashCommandSpec {
|
||||
description: "toggle experimental features",
|
||||
available_during_task: false,
|
||||
is_disabled: false,
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/experimental"],
|
||||
bare_behavior: SlashCommandBareBehavior::OpensUi,
|
||||
parse_kind: SlashCommandParseKind::NoArgs,
|
||||
},
|
||||
SlashCommand::Skills => SlashCommandSpec {
|
||||
description: "use skills to improve how Codex performs specific tasks",
|
||||
available_during_task: true,
|
||||
is_disabled: false,
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/skills"],
|
||||
bare_behavior: SlashCommandBareBehavior::OpensUi,
|
||||
parse_kind: SlashCommandParseKind::NoArgs,
|
||||
},
|
||||
SlashCommand::Review => SlashCommandSpec {
|
||||
description: "review my current changes and find issues",
|
||||
available_during_task: false,
|
||||
is_disabled: false,
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/review", "/review <instructions>"],
|
||||
bare_behavior: SlashCommandBareBehavior::OpensUi,
|
||||
parse_kind: SlashCommandParseKind::Review,
|
||||
},
|
||||
SlashCommand::Rename => SlashCommandSpec {
|
||||
description: "rename the current thread",
|
||||
available_during_task: true,
|
||||
is_disabled: false,
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/rename", "/rename <title>"],
|
||||
bare_behavior: SlashCommandBareBehavior::OpensUi,
|
||||
parse_kind: SlashCommandParseKind::Rename,
|
||||
},
|
||||
SlashCommand::New => SlashCommandSpec {
|
||||
description: "start a new chat during a conversation",
|
||||
available_during_task: false,
|
||||
is_disabled: false,
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/new"],
|
||||
bare_behavior: SlashCommandBareBehavior::DispatchesDirectly,
|
||||
parse_kind: SlashCommandParseKind::NoArgs,
|
||||
},
|
||||
SlashCommand::Resume => SlashCommandSpec {
|
||||
description: "resume a saved chat",
|
||||
available_during_task: false,
|
||||
is_disabled: false,
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/resume"],
|
||||
bare_behavior: SlashCommandBareBehavior::OpensUi,
|
||||
parse_kind: SlashCommandParseKind::NoArgs,
|
||||
},
|
||||
SlashCommand::Fork => SlashCommandSpec {
|
||||
description: "fork the current chat",
|
||||
available_during_task: false,
|
||||
is_disabled: false,
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/fork"],
|
||||
bare_behavior: SlashCommandBareBehavior::DispatchesDirectly,
|
||||
parse_kind: SlashCommandParseKind::NoArgs,
|
||||
},
|
||||
SlashCommand::Init => SlashCommandSpec {
|
||||
description: "create an AGENTS.md file with instructions for Codex",
|
||||
available_during_task: false,
|
||||
is_disabled: false,
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/init"],
|
||||
bare_behavior: SlashCommandBareBehavior::DispatchesDirectly,
|
||||
parse_kind: SlashCommandParseKind::NoArgs,
|
||||
},
|
||||
SlashCommand::Compact => SlashCommandSpec {
|
||||
description: "summarize conversation to prevent hitting the context limit",
|
||||
available_during_task: false,
|
||||
is_disabled: false,
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/compact"],
|
||||
bare_behavior: SlashCommandBareBehavior::DispatchesDirectly,
|
||||
parse_kind: SlashCommandParseKind::NoArgs,
|
||||
},
|
||||
SlashCommand::Plan => SlashCommandSpec {
|
||||
description: "switch to Plan mode",
|
||||
available_during_task: false,
|
||||
is_disabled: false,
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/plan", "/plan <prompt>"],
|
||||
bare_behavior: SlashCommandBareBehavior::DispatchesDirectly,
|
||||
parse_kind: SlashCommandParseKind::Plan,
|
||||
},
|
||||
SlashCommand::Collab => SlashCommandSpec {
|
||||
description: "change collaboration mode (experimental)",
|
||||
available_during_task: true,
|
||||
is_disabled: false,
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/collab"],
|
||||
bare_behavior: SlashCommandBareBehavior::OpensUi,
|
||||
parse_kind: SlashCommandParseKind::NoArgs,
|
||||
},
|
||||
SlashCommand::Agent => SlashCommandSpec {
|
||||
description: "switch the active agent thread",
|
||||
available_during_task: true,
|
||||
is_disabled: false,
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/agent"],
|
||||
bare_behavior: SlashCommandBareBehavior::OpensUi,
|
||||
parse_kind: SlashCommandParseKind::NoArgs,
|
||||
},
|
||||
SlashCommand::Diff => SlashCommandSpec {
|
||||
description: "show git diff (including untracked files)",
|
||||
available_during_task: true,
|
||||
is_disabled: false,
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/diff"],
|
||||
bare_behavior: SlashCommandBareBehavior::DispatchesDirectly,
|
||||
parse_kind: SlashCommandParseKind::NoArgs,
|
||||
},
|
||||
SlashCommand::Copy => SlashCommandSpec {
|
||||
description: "copy the latest Codex output to your clipboard",
|
||||
available_during_task: true,
|
||||
is_disabled: cfg!(target_os = "android"),
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/copy"],
|
||||
bare_behavior: SlashCommandBareBehavior::DispatchesDirectly,
|
||||
parse_kind: SlashCommandParseKind::NoArgs,
|
||||
},
|
||||
SlashCommand::Mention => SlashCommandSpec {
|
||||
description: "mention a file",
|
||||
available_during_task: true,
|
||||
is_disabled: false,
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/mention"],
|
||||
bare_behavior: SlashCommandBareBehavior::DispatchesDirectly,
|
||||
parse_kind: SlashCommandParseKind::NoArgs,
|
||||
},
|
||||
SlashCommand::Status => SlashCommandSpec {
|
||||
description: "show current session configuration and token usage",
|
||||
available_during_task: true,
|
||||
is_disabled: false,
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/status"],
|
||||
bare_behavior: SlashCommandBareBehavior::DispatchesDirectly,
|
||||
parse_kind: SlashCommandParseKind::NoArgs,
|
||||
},
|
||||
SlashCommand::DebugConfig => SlashCommandSpec {
|
||||
description: "show config layers and requirement sources for debugging",
|
||||
available_during_task: true,
|
||||
is_disabled: false,
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/debug-config"],
|
||||
bare_behavior: SlashCommandBareBehavior::DispatchesDirectly,
|
||||
parse_kind: SlashCommandParseKind::NoArgs,
|
||||
},
|
||||
SlashCommand::Title => SlashCommandSpec {
|
||||
description: "configure which items appear in the terminal title",
|
||||
available_during_task: false,
|
||||
is_disabled: false,
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/title"],
|
||||
bare_behavior: SlashCommandBareBehavior::DispatchesDirectly,
|
||||
parse_kind: SlashCommandParseKind::NoArgs,
|
||||
},
|
||||
SlashCommand::Statusline => SlashCommandSpec {
|
||||
description: "configure which items appear in the status line",
|
||||
available_during_task: false,
|
||||
is_disabled: false,
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/statusline"],
|
||||
bare_behavior: SlashCommandBareBehavior::OpensUi,
|
||||
parse_kind: SlashCommandParseKind::NoArgs,
|
||||
},
|
||||
SlashCommand::Theme => SlashCommandSpec {
|
||||
description: "choose a syntax highlighting theme",
|
||||
available_during_task: false,
|
||||
is_disabled: false,
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/theme"],
|
||||
bare_behavior: SlashCommandBareBehavior::OpensUi,
|
||||
parse_kind: SlashCommandParseKind::NoArgs,
|
||||
},
|
||||
SlashCommand::Mcp => SlashCommandSpec {
|
||||
description: "list configured MCP tools",
|
||||
available_during_task: true,
|
||||
is_disabled: false,
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/mcp"],
|
||||
bare_behavior: SlashCommandBareBehavior::DispatchesDirectly,
|
||||
parse_kind: SlashCommandParseKind::NoArgs,
|
||||
},
|
||||
SlashCommand::Apps => SlashCommandSpec {
|
||||
description: "manage apps",
|
||||
available_during_task: true,
|
||||
is_disabled: false,
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/apps"],
|
||||
bare_behavior: SlashCommandBareBehavior::DispatchesDirectly,
|
||||
parse_kind: SlashCommandParseKind::NoArgs,
|
||||
},
|
||||
SlashCommand::Plugins => SlashCommandSpec {
|
||||
description: "browse plugins",
|
||||
available_during_task: true,
|
||||
is_disabled: false,
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/plugins"],
|
||||
bare_behavior: SlashCommandBareBehavior::DispatchesDirectly,
|
||||
parse_kind: SlashCommandParseKind::NoArgs,
|
||||
},
|
||||
SlashCommand::Logout => SlashCommandSpec {
|
||||
description: "log out of Codex",
|
||||
available_during_task: false,
|
||||
is_disabled: false,
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/logout"],
|
||||
bare_behavior: SlashCommandBareBehavior::DispatchesDirectly,
|
||||
parse_kind: SlashCommandParseKind::NoArgs,
|
||||
},
|
||||
SlashCommand::Quit => SlashCommandSpec {
|
||||
description: "exit Codex",
|
||||
available_during_task: true,
|
||||
is_disabled: false,
|
||||
hide_in_command_popup: true,
|
||||
usage_lines: &["/quit"],
|
||||
bare_behavior: SlashCommandBareBehavior::DispatchesDirectly,
|
||||
parse_kind: SlashCommandParseKind::NoArgs,
|
||||
},
|
||||
SlashCommand::Exit => SlashCommandSpec {
|
||||
description: "exit Codex",
|
||||
available_during_task: true,
|
||||
is_disabled: false,
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/exit"],
|
||||
bare_behavior: SlashCommandBareBehavior::DispatchesDirectly,
|
||||
parse_kind: SlashCommandParseKind::NoArgs,
|
||||
},
|
||||
SlashCommand::Feedback => SlashCommandSpec {
|
||||
description: "send logs to maintainers",
|
||||
available_during_task: true,
|
||||
is_disabled: false,
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/feedback"],
|
||||
bare_behavior: SlashCommandBareBehavior::OpensUi,
|
||||
parse_kind: SlashCommandParseKind::NoArgs,
|
||||
},
|
||||
SlashCommand::Rollout => SlashCommandSpec {
|
||||
description: "print the rollout file path",
|
||||
available_during_task: true,
|
||||
is_disabled: !cfg!(debug_assertions),
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/rollout"],
|
||||
bare_behavior: SlashCommandBareBehavior::DispatchesDirectly,
|
||||
parse_kind: SlashCommandParseKind::NoArgs,
|
||||
},
|
||||
SlashCommand::Ps => SlashCommandSpec {
|
||||
description: "list background terminals",
|
||||
available_during_task: true,
|
||||
is_disabled: false,
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/ps"],
|
||||
bare_behavior: SlashCommandBareBehavior::DispatchesDirectly,
|
||||
parse_kind: SlashCommandParseKind::NoArgs,
|
||||
},
|
||||
SlashCommand::Stop => SlashCommandSpec {
|
||||
description: "stop all background terminals",
|
||||
available_during_task: true,
|
||||
is_disabled: false,
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/stop"],
|
||||
bare_behavior: SlashCommandBareBehavior::DispatchesDirectly,
|
||||
parse_kind: SlashCommandParseKind::NoArgs,
|
||||
},
|
||||
SlashCommand::Clear => SlashCommandSpec {
|
||||
description: "clear the terminal and start a new chat",
|
||||
available_during_task: false,
|
||||
is_disabled: false,
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/clear"],
|
||||
bare_behavior: SlashCommandBareBehavior::DispatchesDirectly,
|
||||
parse_kind: SlashCommandParseKind::NoArgs,
|
||||
},
|
||||
SlashCommand::Personality => SlashCommandSpec {
|
||||
description: "choose a communication style for Codex",
|
||||
available_during_task: false,
|
||||
is_disabled: false,
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/personality"],
|
||||
bare_behavior: SlashCommandBareBehavior::OpensUi,
|
||||
parse_kind: SlashCommandParseKind::NoArgs,
|
||||
},
|
||||
SlashCommand::Realtime => SlashCommandSpec {
|
||||
description: "toggle realtime voice mode (experimental)",
|
||||
available_during_task: true,
|
||||
is_disabled: false,
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/realtime"],
|
||||
bare_behavior: SlashCommandBareBehavior::DispatchesDirectly,
|
||||
parse_kind: SlashCommandParseKind::NoArgs,
|
||||
},
|
||||
SlashCommand::Settings => SlashCommandSpec {
|
||||
description: "configure realtime microphone/speaker",
|
||||
available_during_task: true,
|
||||
is_disabled: false,
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/settings"],
|
||||
bare_behavior: SlashCommandBareBehavior::OpensUi,
|
||||
parse_kind: SlashCommandParseKind::NoArgs,
|
||||
},
|
||||
SlashCommand::TestApproval => SlashCommandSpec {
|
||||
description: "test approval request",
|
||||
available_during_task: true,
|
||||
is_disabled: !cfg!(debug_assertions),
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/test-approval"],
|
||||
bare_behavior: SlashCommandBareBehavior::DispatchesDirectly,
|
||||
parse_kind: SlashCommandParseKind::NoArgs,
|
||||
},
|
||||
SlashCommand::MultiAgents => SlashCommandSpec {
|
||||
description: "switch the active agent thread",
|
||||
available_during_task: true,
|
||||
is_disabled: false,
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/subagents"],
|
||||
bare_behavior: SlashCommandBareBehavior::OpensUi,
|
||||
parse_kind: SlashCommandParseKind::NoArgs,
|
||||
},
|
||||
SlashCommand::MemoryDrop => SlashCommandSpec {
|
||||
description: "DO NOT USE",
|
||||
available_during_task: false,
|
||||
is_disabled: false,
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/debug-m-drop"],
|
||||
bare_behavior: SlashCommandBareBehavior::DispatchesDirectly,
|
||||
parse_kind: SlashCommandParseKind::NoArgs,
|
||||
},
|
||||
SlashCommand::MemoryUpdate => SlashCommandSpec {
|
||||
description: "DO NOT USE",
|
||||
available_during_task: false,
|
||||
is_disabled: false,
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/debug-m-update"],
|
||||
bare_behavior: SlashCommandBareBehavior::DispatchesDirectly,
|
||||
parse_kind: SlashCommandParseKind::NoArgs,
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -349,52 +497,7 @@ impl SlashCommand {
|
||||
|
||||
/// User-visible usage forms for this command.
|
||||
pub(crate) fn usage_lines(self) -> &'static [&'static str] {
|
||||
match self {
|
||||
SlashCommand::Model => &["/model"],
|
||||
SlashCommand::Fast => &["/fast", "/fast [on|off|status]"],
|
||||
SlashCommand::Approvals => &["/approvals"],
|
||||
SlashCommand::Permissions => &["/permissions"],
|
||||
SlashCommand::ElevateSandbox => &["/setup-default-sandbox"],
|
||||
SlashCommand::SandboxReadRoot => &["/sandbox-add-read-dir <absolute-path>"],
|
||||
SlashCommand::Experimental => &["/experimental"],
|
||||
SlashCommand::Skills => &["/skills"],
|
||||
SlashCommand::Review => &["/review", "/review <instructions>"],
|
||||
SlashCommand::Rename => &["/rename", "/rename <title>"],
|
||||
SlashCommand::New => &["/new"],
|
||||
SlashCommand::Resume => &["/resume"],
|
||||
SlashCommand::Fork => &["/fork"],
|
||||
SlashCommand::Init => &["/init"],
|
||||
SlashCommand::Compact => &["/compact"],
|
||||
SlashCommand::Plan => &["/plan", "/plan <prompt>"],
|
||||
SlashCommand::Collab => &["/collab"],
|
||||
SlashCommand::Agent => &["/agent"],
|
||||
SlashCommand::Diff => &["/diff"],
|
||||
SlashCommand::Copy => &["/copy"],
|
||||
SlashCommand::Mention => &["/mention"],
|
||||
SlashCommand::Status => &["/status"],
|
||||
SlashCommand::DebugConfig => &["/debug-config"],
|
||||
SlashCommand::Title => &["/title"],
|
||||
SlashCommand::Statusline => &["/statusline"],
|
||||
SlashCommand::Theme => &["/theme"],
|
||||
SlashCommand::Mcp => &["/mcp"],
|
||||
SlashCommand::Apps => &["/apps"],
|
||||
SlashCommand::Plugins => &["/plugins"],
|
||||
SlashCommand::Logout => &["/logout"],
|
||||
SlashCommand::Quit => &["/quit"],
|
||||
SlashCommand::Exit => &["/exit"],
|
||||
SlashCommand::Feedback => &["/feedback"],
|
||||
SlashCommand::Rollout => &["/rollout"],
|
||||
SlashCommand::Ps => &["/ps"],
|
||||
SlashCommand::Stop => &["/stop"],
|
||||
SlashCommand::Clear => &["/clear"],
|
||||
SlashCommand::Personality => &["/personality"],
|
||||
SlashCommand::Realtime => &["/realtime"],
|
||||
SlashCommand::Settings => &["/settings"],
|
||||
SlashCommand::TestApproval => &["/test-approval"],
|
||||
SlashCommand::MultiAgents => &["/subagents"],
|
||||
SlashCommand::MemoryDrop => &["/debug-m-drop"],
|
||||
SlashCommand::MemoryUpdate => &["/debug-m-update"],
|
||||
}
|
||||
self.spec().usage_lines
|
||||
}
|
||||
|
||||
/// Whether this command can be run while a task is in progress.
|
||||
@@ -423,11 +526,14 @@ pub fn built_in_slash_commands() -> Vec<(&'static str, SlashCommand)> {
|
||||
.collect()
|
||||
}
|
||||
|
||||
struct SlashCommandSpec {
|
||||
description: &'static str,
|
||||
available_during_task: bool,
|
||||
is_disabled: bool,
|
||||
hide_in_command_popup: bool,
|
||||
pub(crate) struct SlashCommandSpec {
|
||||
pub(crate) description: &'static str,
|
||||
pub(crate) available_during_task: bool,
|
||||
pub(crate) is_disabled: bool,
|
||||
pub(crate) hide_in_command_popup: bool,
|
||||
pub(crate) usage_lines: &'static [&'static str],
|
||||
pub(crate) bare_behavior: SlashCommandBareBehavior,
|
||||
pub(crate) parse_kind: SlashCommandParseKind,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
use crate::slash_command::SlashCommand;
|
||||
use crate::slash_command::SlashCommandBareBehavior;
|
||||
use crate::slash_command::SlashCommandParseKind;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub(crate) enum FastSlashCommandArgs {
|
||||
@@ -7,12 +9,6 @@ pub(crate) enum FastSlashCommandArgs {
|
||||
Status,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub(crate) enum SlashCommandBareBehavior {
|
||||
DispatchesDirectly,
|
||||
OpensUi,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub(crate) enum ParsedSlashCommand {
|
||||
Bare(SlashCommandBareBehavior),
|
||||
@@ -49,66 +45,22 @@ impl SlashCommandUsageError {
|
||||
}
|
||||
|
||||
impl SlashCommand {
|
||||
pub(crate) fn bare_behavior(self) -> SlashCommandBareBehavior {
|
||||
match self {
|
||||
SlashCommand::Model
|
||||
| SlashCommand::Approvals
|
||||
| SlashCommand::Permissions
|
||||
| SlashCommand::Experimental
|
||||
| SlashCommand::Skills
|
||||
| SlashCommand::Review
|
||||
| SlashCommand::Rename
|
||||
| SlashCommand::Resume
|
||||
| SlashCommand::Collab
|
||||
| SlashCommand::Agent
|
||||
| SlashCommand::Statusline
|
||||
| SlashCommand::Theme
|
||||
| SlashCommand::Feedback
|
||||
| SlashCommand::Personality
|
||||
| SlashCommand::Settings
|
||||
| SlashCommand::MultiAgents => SlashCommandBareBehavior::OpensUi,
|
||||
SlashCommand::Fast
|
||||
| SlashCommand::ElevateSandbox
|
||||
| SlashCommand::SandboxReadRoot
|
||||
| SlashCommand::New
|
||||
| SlashCommand::Fork
|
||||
| SlashCommand::Init
|
||||
| SlashCommand::Compact
|
||||
| SlashCommand::Plan
|
||||
| SlashCommand::Diff
|
||||
| SlashCommand::Copy
|
||||
| SlashCommand::Mention
|
||||
| SlashCommand::Status
|
||||
| SlashCommand::DebugConfig
|
||||
| SlashCommand::Title
|
||||
| SlashCommand::Mcp
|
||||
| SlashCommand::Apps
|
||||
| SlashCommand::Plugins
|
||||
| SlashCommand::Logout
|
||||
| SlashCommand::Quit
|
||||
| SlashCommand::Exit
|
||||
| SlashCommand::Rollout
|
||||
| SlashCommand::Ps
|
||||
| SlashCommand::Stop
|
||||
| SlashCommand::Clear
|
||||
| SlashCommand::Realtime
|
||||
| SlashCommand::TestApproval
|
||||
| SlashCommand::MemoryDrop
|
||||
| SlashCommand::MemoryUpdate => SlashCommandBareBehavior::DispatchesDirectly,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn parse_invocation(
|
||||
self,
|
||||
args: &str,
|
||||
) -> Result<ParsedSlashCommand, SlashCommandUsageError> {
|
||||
let trimmed = args.trim();
|
||||
let spec = self.spec();
|
||||
if trimmed.is_empty() {
|
||||
return Ok(ParsedSlashCommand::Bare(self.bare_behavior()));
|
||||
return Ok(ParsedSlashCommand::Bare(spec.bare_behavior));
|
||||
}
|
||||
|
||||
match self {
|
||||
SlashCommand::Fast => match trimmed.to_ascii_lowercase().as_str() {
|
||||
match spec.parse_kind {
|
||||
SlashCommandParseKind::NoArgs => Err(SlashCommandUsageError {
|
||||
command: self,
|
||||
kind: SlashCommandUsageErrorKind::UnexpectedInlineArgs,
|
||||
}),
|
||||
SlashCommandParseKind::Fast => match trimmed.to_ascii_lowercase().as_str() {
|
||||
"on" => Ok(ParsedSlashCommand::Fast(FastSlashCommandArgs::On)),
|
||||
"off" => Ok(ParsedSlashCommand::Fast(FastSlashCommandArgs::Off)),
|
||||
"status" => Ok(ParsedSlashCommand::Fast(FastSlashCommandArgs::Status)),
|
||||
@@ -117,52 +69,10 @@ impl SlashCommand {
|
||||
kind: SlashCommandUsageErrorKind::InvalidInlineArgs,
|
||||
}),
|
||||
},
|
||||
SlashCommand::Rename => Ok(ParsedSlashCommand::Rename),
|
||||
SlashCommand::Plan => Ok(ParsedSlashCommand::Plan),
|
||||
SlashCommand::Review => Ok(ParsedSlashCommand::Review),
|
||||
SlashCommand::SandboxReadRoot => Ok(ParsedSlashCommand::SandboxReadRoot),
|
||||
SlashCommand::Model
|
||||
| SlashCommand::Approvals
|
||||
| SlashCommand::Permissions
|
||||
| SlashCommand::ElevateSandbox
|
||||
| SlashCommand::Experimental
|
||||
| SlashCommand::Skills
|
||||
| SlashCommand::New
|
||||
| SlashCommand::Resume
|
||||
| SlashCommand::Fork
|
||||
| SlashCommand::Init
|
||||
| SlashCommand::Compact
|
||||
| SlashCommand::Collab
|
||||
| SlashCommand::Agent
|
||||
| SlashCommand::Diff
|
||||
| SlashCommand::Copy
|
||||
| SlashCommand::Mention
|
||||
| SlashCommand::Status
|
||||
| SlashCommand::DebugConfig
|
||||
| SlashCommand::Title
|
||||
| SlashCommand::Statusline
|
||||
| SlashCommand::Theme
|
||||
| SlashCommand::Mcp
|
||||
| SlashCommand::Apps
|
||||
| SlashCommand::Plugins
|
||||
| SlashCommand::Logout
|
||||
| SlashCommand::Quit
|
||||
| SlashCommand::Exit
|
||||
| SlashCommand::Feedback
|
||||
| SlashCommand::Rollout
|
||||
| SlashCommand::Ps
|
||||
| SlashCommand::Stop
|
||||
| SlashCommand::Clear
|
||||
| SlashCommand::Personality
|
||||
| SlashCommand::Realtime
|
||||
| SlashCommand::Settings
|
||||
| SlashCommand::TestApproval
|
||||
| SlashCommand::MultiAgents
|
||||
| SlashCommand::MemoryDrop
|
||||
| SlashCommand::MemoryUpdate => Err(SlashCommandUsageError {
|
||||
command: self,
|
||||
kind: SlashCommandUsageErrorKind::UnexpectedInlineArgs,
|
||||
}),
|
||||
SlashCommandParseKind::Rename => Ok(ParsedSlashCommand::Rename),
|
||||
SlashCommandParseKind::Plan => Ok(ParsedSlashCommand::Plan),
|
||||
SlashCommandParseKind::Review => Ok(ParsedSlashCommand::Review),
|
||||
SlashCommandParseKind::SandboxReadRoot => Ok(ParsedSlashCommand::SandboxReadRoot),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,266 +65,411 @@ pub enum SlashCommand {
|
||||
MemoryUpdate,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub(crate) enum SlashCommandBareBehavior {
|
||||
DispatchesDirectly,
|
||||
OpensUi,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub(crate) enum SlashCommandParseKind {
|
||||
NoArgs,
|
||||
Fast,
|
||||
Rename,
|
||||
Plan,
|
||||
Review,
|
||||
SandboxReadRoot,
|
||||
}
|
||||
|
||||
impl SlashCommand {
|
||||
fn spec(self) -> SlashCommandSpec {
|
||||
pub(crate) fn spec(self) -> SlashCommandSpec {
|
||||
match self {
|
||||
SlashCommand::Model => SlashCommandSpec {
|
||||
description: "choose what model and reasoning effort to use",
|
||||
available_during_task: false,
|
||||
is_disabled: false,
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/model"],
|
||||
bare_behavior: SlashCommandBareBehavior::OpensUi,
|
||||
parse_kind: SlashCommandParseKind::NoArgs,
|
||||
},
|
||||
SlashCommand::Fast => SlashCommandSpec {
|
||||
description: "toggle Fast mode to enable fastest inference at 2X plan usage",
|
||||
available_during_task: false,
|
||||
is_disabled: false,
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/fast", "/fast [on|off|status]"],
|
||||
bare_behavior: SlashCommandBareBehavior::DispatchesDirectly,
|
||||
parse_kind: SlashCommandParseKind::Fast,
|
||||
},
|
||||
SlashCommand::Approvals => SlashCommandSpec {
|
||||
description: "choose what Codex is allowed to do",
|
||||
available_during_task: false,
|
||||
is_disabled: false,
|
||||
hide_in_command_popup: true,
|
||||
usage_lines: &["/approvals"],
|
||||
bare_behavior: SlashCommandBareBehavior::OpensUi,
|
||||
parse_kind: SlashCommandParseKind::NoArgs,
|
||||
},
|
||||
SlashCommand::Permissions => SlashCommandSpec {
|
||||
description: "choose what Codex is allowed to do",
|
||||
available_during_task: false,
|
||||
is_disabled: false,
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/permissions"],
|
||||
bare_behavior: SlashCommandBareBehavior::OpensUi,
|
||||
parse_kind: SlashCommandParseKind::NoArgs,
|
||||
},
|
||||
SlashCommand::ElevateSandbox => SlashCommandSpec {
|
||||
description: "set up elevated agent sandbox",
|
||||
available_during_task: false,
|
||||
is_disabled: false,
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/setup-default-sandbox"],
|
||||
bare_behavior: SlashCommandBareBehavior::DispatchesDirectly,
|
||||
parse_kind: SlashCommandParseKind::NoArgs,
|
||||
},
|
||||
SlashCommand::SandboxReadRoot => SlashCommandSpec {
|
||||
description: "let sandbox read a directory: /sandbox-add-read-dir <absolute_path>",
|
||||
available_during_task: false,
|
||||
is_disabled: !cfg!(target_os = "windows"),
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/sandbox-add-read-dir <absolute-path>"],
|
||||
bare_behavior: SlashCommandBareBehavior::DispatchesDirectly,
|
||||
parse_kind: SlashCommandParseKind::SandboxReadRoot,
|
||||
},
|
||||
SlashCommand::Experimental => SlashCommandSpec {
|
||||
description: "toggle experimental features",
|
||||
available_during_task: false,
|
||||
is_disabled: false,
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/experimental"],
|
||||
bare_behavior: SlashCommandBareBehavior::OpensUi,
|
||||
parse_kind: SlashCommandParseKind::NoArgs,
|
||||
},
|
||||
SlashCommand::Skills => SlashCommandSpec {
|
||||
description: "use skills to improve how Codex performs specific tasks",
|
||||
available_during_task: true,
|
||||
is_disabled: false,
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/skills"],
|
||||
bare_behavior: SlashCommandBareBehavior::OpensUi,
|
||||
parse_kind: SlashCommandParseKind::NoArgs,
|
||||
},
|
||||
SlashCommand::Review => SlashCommandSpec {
|
||||
description: "review my current changes and find issues",
|
||||
available_during_task: false,
|
||||
is_disabled: false,
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/review", "/review <instructions>"],
|
||||
bare_behavior: SlashCommandBareBehavior::OpensUi,
|
||||
parse_kind: SlashCommandParseKind::Review,
|
||||
},
|
||||
SlashCommand::Rename => SlashCommandSpec {
|
||||
description: "rename the current thread",
|
||||
available_during_task: true,
|
||||
is_disabled: false,
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/rename", "/rename <title>"],
|
||||
bare_behavior: SlashCommandBareBehavior::OpensUi,
|
||||
parse_kind: SlashCommandParseKind::Rename,
|
||||
},
|
||||
SlashCommand::New => SlashCommandSpec {
|
||||
description: "start a new chat during a conversation",
|
||||
available_during_task: false,
|
||||
is_disabled: false,
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/new"],
|
||||
bare_behavior: SlashCommandBareBehavior::DispatchesDirectly,
|
||||
parse_kind: SlashCommandParseKind::NoArgs,
|
||||
},
|
||||
SlashCommand::Resume => SlashCommandSpec {
|
||||
description: "resume a saved chat",
|
||||
available_during_task: false,
|
||||
is_disabled: false,
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/resume"],
|
||||
bare_behavior: SlashCommandBareBehavior::OpensUi,
|
||||
parse_kind: SlashCommandParseKind::NoArgs,
|
||||
},
|
||||
SlashCommand::Fork => SlashCommandSpec {
|
||||
description: "fork the current chat",
|
||||
available_during_task: false,
|
||||
is_disabled: false,
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/fork"],
|
||||
bare_behavior: SlashCommandBareBehavior::DispatchesDirectly,
|
||||
parse_kind: SlashCommandParseKind::NoArgs,
|
||||
},
|
||||
SlashCommand::Init => SlashCommandSpec {
|
||||
description: "create an AGENTS.md file with instructions for Codex",
|
||||
available_during_task: false,
|
||||
is_disabled: false,
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/init"],
|
||||
bare_behavior: SlashCommandBareBehavior::DispatchesDirectly,
|
||||
parse_kind: SlashCommandParseKind::NoArgs,
|
||||
},
|
||||
SlashCommand::Compact => SlashCommandSpec {
|
||||
description: "summarize conversation to prevent hitting the context limit",
|
||||
available_during_task: false,
|
||||
is_disabled: false,
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/compact"],
|
||||
bare_behavior: SlashCommandBareBehavior::DispatchesDirectly,
|
||||
parse_kind: SlashCommandParseKind::NoArgs,
|
||||
},
|
||||
SlashCommand::Plan => SlashCommandSpec {
|
||||
description: "switch to Plan mode",
|
||||
available_during_task: false,
|
||||
is_disabled: false,
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/plan", "/plan <prompt>"],
|
||||
bare_behavior: SlashCommandBareBehavior::DispatchesDirectly,
|
||||
parse_kind: SlashCommandParseKind::Plan,
|
||||
},
|
||||
SlashCommand::Collab => SlashCommandSpec {
|
||||
description: "change collaboration mode (experimental)",
|
||||
available_during_task: true,
|
||||
is_disabled: false,
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/collab"],
|
||||
bare_behavior: SlashCommandBareBehavior::OpensUi,
|
||||
parse_kind: SlashCommandParseKind::NoArgs,
|
||||
},
|
||||
SlashCommand::Agent => SlashCommandSpec {
|
||||
description: "switch the active agent thread",
|
||||
available_during_task: true,
|
||||
is_disabled: false,
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/agent"],
|
||||
bare_behavior: SlashCommandBareBehavior::OpensUi,
|
||||
parse_kind: SlashCommandParseKind::NoArgs,
|
||||
},
|
||||
SlashCommand::Diff => SlashCommandSpec {
|
||||
description: "show git diff (including untracked files)",
|
||||
available_during_task: true,
|
||||
is_disabled: false,
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/diff"],
|
||||
bare_behavior: SlashCommandBareBehavior::DispatchesDirectly,
|
||||
parse_kind: SlashCommandParseKind::NoArgs,
|
||||
},
|
||||
SlashCommand::Copy => SlashCommandSpec {
|
||||
description: "copy the latest Codex output to your clipboard",
|
||||
available_during_task: true,
|
||||
is_disabled: cfg!(target_os = "android"),
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/copy"],
|
||||
bare_behavior: SlashCommandBareBehavior::DispatchesDirectly,
|
||||
parse_kind: SlashCommandParseKind::NoArgs,
|
||||
},
|
||||
SlashCommand::Mention => SlashCommandSpec {
|
||||
description: "mention a file",
|
||||
available_during_task: true,
|
||||
is_disabled: false,
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/mention"],
|
||||
bare_behavior: SlashCommandBareBehavior::DispatchesDirectly,
|
||||
parse_kind: SlashCommandParseKind::NoArgs,
|
||||
},
|
||||
SlashCommand::Status => SlashCommandSpec {
|
||||
description: "show current session configuration and token usage",
|
||||
available_during_task: true,
|
||||
is_disabled: false,
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/status"],
|
||||
bare_behavior: SlashCommandBareBehavior::DispatchesDirectly,
|
||||
parse_kind: SlashCommandParseKind::NoArgs,
|
||||
},
|
||||
SlashCommand::DebugConfig => SlashCommandSpec {
|
||||
description: "show config layers and requirement sources for debugging",
|
||||
available_during_task: true,
|
||||
is_disabled: false,
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/debug-config"],
|
||||
bare_behavior: SlashCommandBareBehavior::DispatchesDirectly,
|
||||
parse_kind: SlashCommandParseKind::NoArgs,
|
||||
},
|
||||
SlashCommand::Statusline => SlashCommandSpec {
|
||||
description: "configure which items appear in the status line",
|
||||
available_during_task: false,
|
||||
is_disabled: false,
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/statusline"],
|
||||
bare_behavior: SlashCommandBareBehavior::OpensUi,
|
||||
parse_kind: SlashCommandParseKind::NoArgs,
|
||||
},
|
||||
SlashCommand::Theme => SlashCommandSpec {
|
||||
description: "choose a syntax highlighting theme",
|
||||
available_during_task: false,
|
||||
is_disabled: false,
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/theme"],
|
||||
bare_behavior: SlashCommandBareBehavior::OpensUi,
|
||||
parse_kind: SlashCommandParseKind::NoArgs,
|
||||
},
|
||||
SlashCommand::Mcp => SlashCommandSpec {
|
||||
description: "list configured MCP tools",
|
||||
available_during_task: true,
|
||||
is_disabled: false,
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/mcp"],
|
||||
bare_behavior: SlashCommandBareBehavior::DispatchesDirectly,
|
||||
parse_kind: SlashCommandParseKind::NoArgs,
|
||||
},
|
||||
SlashCommand::Apps => SlashCommandSpec {
|
||||
description: "manage apps",
|
||||
available_during_task: true,
|
||||
is_disabled: false,
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/apps"],
|
||||
bare_behavior: SlashCommandBareBehavior::DispatchesDirectly,
|
||||
parse_kind: SlashCommandParseKind::NoArgs,
|
||||
},
|
||||
SlashCommand::Plugins => SlashCommandSpec {
|
||||
description: "browse plugins",
|
||||
available_during_task: true,
|
||||
is_disabled: false,
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/plugins"],
|
||||
bare_behavior: SlashCommandBareBehavior::DispatchesDirectly,
|
||||
parse_kind: SlashCommandParseKind::NoArgs,
|
||||
},
|
||||
SlashCommand::Logout => SlashCommandSpec {
|
||||
description: "log out of Codex",
|
||||
available_during_task: false,
|
||||
is_disabled: false,
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/logout"],
|
||||
bare_behavior: SlashCommandBareBehavior::DispatchesDirectly,
|
||||
parse_kind: SlashCommandParseKind::NoArgs,
|
||||
},
|
||||
SlashCommand::Quit => SlashCommandSpec {
|
||||
description: "exit Codex",
|
||||
available_during_task: true,
|
||||
is_disabled: false,
|
||||
hide_in_command_popup: true,
|
||||
usage_lines: &["/quit"],
|
||||
bare_behavior: SlashCommandBareBehavior::DispatchesDirectly,
|
||||
parse_kind: SlashCommandParseKind::NoArgs,
|
||||
},
|
||||
SlashCommand::Exit => SlashCommandSpec {
|
||||
description: "exit Codex",
|
||||
available_during_task: true,
|
||||
is_disabled: false,
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/exit"],
|
||||
bare_behavior: SlashCommandBareBehavior::DispatchesDirectly,
|
||||
parse_kind: SlashCommandParseKind::NoArgs,
|
||||
},
|
||||
SlashCommand::Feedback => SlashCommandSpec {
|
||||
description: "send logs to maintainers",
|
||||
available_during_task: true,
|
||||
is_disabled: false,
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/feedback"],
|
||||
bare_behavior: SlashCommandBareBehavior::OpensUi,
|
||||
parse_kind: SlashCommandParseKind::NoArgs,
|
||||
},
|
||||
SlashCommand::Rollout => SlashCommandSpec {
|
||||
description: "print the rollout file path",
|
||||
available_during_task: true,
|
||||
is_disabled: !cfg!(debug_assertions),
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/rollout"],
|
||||
bare_behavior: SlashCommandBareBehavior::DispatchesDirectly,
|
||||
parse_kind: SlashCommandParseKind::NoArgs,
|
||||
},
|
||||
SlashCommand::Ps => SlashCommandSpec {
|
||||
description: "list background terminals",
|
||||
available_during_task: true,
|
||||
is_disabled: false,
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/ps"],
|
||||
bare_behavior: SlashCommandBareBehavior::DispatchesDirectly,
|
||||
parse_kind: SlashCommandParseKind::NoArgs,
|
||||
},
|
||||
SlashCommand::Stop => SlashCommandSpec {
|
||||
description: "stop all background terminals",
|
||||
available_during_task: true,
|
||||
is_disabled: false,
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/stop"],
|
||||
bare_behavior: SlashCommandBareBehavior::DispatchesDirectly,
|
||||
parse_kind: SlashCommandParseKind::NoArgs,
|
||||
},
|
||||
SlashCommand::Clear => SlashCommandSpec {
|
||||
description: "clear the terminal and start a new chat",
|
||||
available_during_task: false,
|
||||
is_disabled: false,
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/clear"],
|
||||
bare_behavior: SlashCommandBareBehavior::DispatchesDirectly,
|
||||
parse_kind: SlashCommandParseKind::NoArgs,
|
||||
},
|
||||
SlashCommand::Personality => SlashCommandSpec {
|
||||
description: "choose a communication style for Codex",
|
||||
available_during_task: false,
|
||||
is_disabled: false,
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/personality"],
|
||||
bare_behavior: SlashCommandBareBehavior::OpensUi,
|
||||
parse_kind: SlashCommandParseKind::NoArgs,
|
||||
},
|
||||
SlashCommand::Realtime => SlashCommandSpec {
|
||||
description: "toggle realtime voice mode (experimental)",
|
||||
available_during_task: true,
|
||||
is_disabled: false,
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/realtime"],
|
||||
bare_behavior: SlashCommandBareBehavior::DispatchesDirectly,
|
||||
parse_kind: SlashCommandParseKind::NoArgs,
|
||||
},
|
||||
SlashCommand::Settings => SlashCommandSpec {
|
||||
description: "configure realtime microphone/speaker",
|
||||
available_during_task: true,
|
||||
is_disabled: false,
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/settings"],
|
||||
bare_behavior: SlashCommandBareBehavior::OpensUi,
|
||||
parse_kind: SlashCommandParseKind::NoArgs,
|
||||
},
|
||||
SlashCommand::TestApproval => SlashCommandSpec {
|
||||
description: "test approval request",
|
||||
available_during_task: true,
|
||||
is_disabled: !cfg!(debug_assertions),
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/test-approval"],
|
||||
bare_behavior: SlashCommandBareBehavior::DispatchesDirectly,
|
||||
parse_kind: SlashCommandParseKind::NoArgs,
|
||||
},
|
||||
SlashCommand::MultiAgents => SlashCommandSpec {
|
||||
description: "switch the active agent thread",
|
||||
available_during_task: true,
|
||||
is_disabled: false,
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/subagents"],
|
||||
bare_behavior: SlashCommandBareBehavior::OpensUi,
|
||||
parse_kind: SlashCommandParseKind::NoArgs,
|
||||
},
|
||||
SlashCommand::MemoryDrop => SlashCommandSpec {
|
||||
description: "DO NOT USE",
|
||||
available_during_task: false,
|
||||
is_disabled: false,
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/debug-m-drop"],
|
||||
bare_behavior: SlashCommandBareBehavior::DispatchesDirectly,
|
||||
parse_kind: SlashCommandParseKind::NoArgs,
|
||||
},
|
||||
SlashCommand::MemoryUpdate => SlashCommandSpec {
|
||||
description: "DO NOT USE",
|
||||
available_during_task: false,
|
||||
is_disabled: false,
|
||||
hide_in_command_popup: false,
|
||||
usage_lines: &["/debug-m-update"],
|
||||
bare_behavior: SlashCommandBareBehavior::DispatchesDirectly,
|
||||
parse_kind: SlashCommandParseKind::NoArgs,
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -342,51 +487,7 @@ impl SlashCommand {
|
||||
|
||||
/// User-visible usage forms for this command.
|
||||
pub(crate) fn usage_lines(self) -> &'static [&'static str] {
|
||||
match self {
|
||||
SlashCommand::Model => &["/model"],
|
||||
SlashCommand::Fast => &["/fast", "/fast [on|off|status]"],
|
||||
SlashCommand::Approvals => &["/approvals"],
|
||||
SlashCommand::Permissions => &["/permissions"],
|
||||
SlashCommand::ElevateSandbox => &["/setup-default-sandbox"],
|
||||
SlashCommand::SandboxReadRoot => &["/sandbox-add-read-dir <absolute-path>"],
|
||||
SlashCommand::Experimental => &["/experimental"],
|
||||
SlashCommand::Skills => &["/skills"],
|
||||
SlashCommand::Review => &["/review", "/review <instructions>"],
|
||||
SlashCommand::Rename => &["/rename", "/rename <title>"],
|
||||
SlashCommand::New => &["/new"],
|
||||
SlashCommand::Resume => &["/resume"],
|
||||
SlashCommand::Fork => &["/fork"],
|
||||
SlashCommand::Init => &["/init"],
|
||||
SlashCommand::Compact => &["/compact"],
|
||||
SlashCommand::Plan => &["/plan", "/plan <prompt>"],
|
||||
SlashCommand::Collab => &["/collab"],
|
||||
SlashCommand::Agent => &["/agent"],
|
||||
SlashCommand::Diff => &["/diff"],
|
||||
SlashCommand::Copy => &["/copy"],
|
||||
SlashCommand::Mention => &["/mention"],
|
||||
SlashCommand::Status => &["/status"],
|
||||
SlashCommand::DebugConfig => &["/debug-config"],
|
||||
SlashCommand::Statusline => &["/statusline"],
|
||||
SlashCommand::Theme => &["/theme"],
|
||||
SlashCommand::Mcp => &["/mcp"],
|
||||
SlashCommand::Apps => &["/apps"],
|
||||
SlashCommand::Plugins => &["/plugins"],
|
||||
SlashCommand::Logout => &["/logout"],
|
||||
SlashCommand::Quit => &["/quit"],
|
||||
SlashCommand::Exit => &["/exit"],
|
||||
SlashCommand::Feedback => &["/feedback"],
|
||||
SlashCommand::Rollout => &["/rollout"],
|
||||
SlashCommand::Ps => &["/ps"],
|
||||
SlashCommand::Stop => &["/stop"],
|
||||
SlashCommand::Clear => &["/clear"],
|
||||
SlashCommand::Personality => &["/personality"],
|
||||
SlashCommand::Realtime => &["/realtime"],
|
||||
SlashCommand::Settings => &["/settings"],
|
||||
SlashCommand::TestApproval => &["/test-approval"],
|
||||
SlashCommand::MultiAgents => &["/subagents"],
|
||||
SlashCommand::MemoryDrop => &["/debug-m-drop"],
|
||||
SlashCommand::MemoryUpdate => &["/debug-m-update"],
|
||||
}
|
||||
self.spec().usage_lines
|
||||
}
|
||||
|
||||
/// Whether this command can be run while a task is in progress.
|
||||
@@ -415,11 +516,14 @@ pub fn built_in_slash_commands() -> Vec<(&'static str, SlashCommand)> {
|
||||
.collect()
|
||||
}
|
||||
|
||||
struct SlashCommandSpec {
|
||||
description: &'static str,
|
||||
available_during_task: bool,
|
||||
is_disabled: bool,
|
||||
hide_in_command_popup: bool,
|
||||
pub(crate) struct SlashCommandSpec {
|
||||
pub(crate) description: &'static str,
|
||||
pub(crate) available_during_task: bool,
|
||||
pub(crate) is_disabled: bool,
|
||||
pub(crate) hide_in_command_popup: bool,
|
||||
pub(crate) usage_lines: &'static [&'static str],
|
||||
pub(crate) bare_behavior: SlashCommandBareBehavior,
|
||||
pub(crate) parse_kind: SlashCommandParseKind,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
use crate::slash_command::SlashCommand;
|
||||
use crate::slash_command::SlashCommandBareBehavior;
|
||||
use crate::slash_command::SlashCommandParseKind;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub(crate) enum FastSlashCommandArgs {
|
||||
@@ -7,12 +9,6 @@ pub(crate) enum FastSlashCommandArgs {
|
||||
Status,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub(crate) enum SlashCommandBareBehavior {
|
||||
DispatchesDirectly,
|
||||
OpensUi,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub(crate) enum ParsedSlashCommand {
|
||||
Bare(SlashCommandBareBehavior),
|
||||
@@ -49,65 +45,22 @@ impl SlashCommandUsageError {
|
||||
}
|
||||
|
||||
impl SlashCommand {
|
||||
pub(crate) fn bare_behavior(self) -> SlashCommandBareBehavior {
|
||||
match self {
|
||||
SlashCommand::Model
|
||||
| SlashCommand::Approvals
|
||||
| SlashCommand::Permissions
|
||||
| SlashCommand::Experimental
|
||||
| SlashCommand::Skills
|
||||
| SlashCommand::Review
|
||||
| SlashCommand::Rename
|
||||
| SlashCommand::Resume
|
||||
| SlashCommand::Collab
|
||||
| SlashCommand::Agent
|
||||
| SlashCommand::Statusline
|
||||
| SlashCommand::Theme
|
||||
| SlashCommand::Feedback
|
||||
| SlashCommand::Personality
|
||||
| SlashCommand::Settings
|
||||
| SlashCommand::MultiAgents => SlashCommandBareBehavior::OpensUi,
|
||||
SlashCommand::Fast
|
||||
| SlashCommand::ElevateSandbox
|
||||
| SlashCommand::SandboxReadRoot
|
||||
| SlashCommand::New
|
||||
| SlashCommand::Fork
|
||||
| SlashCommand::Init
|
||||
| SlashCommand::Compact
|
||||
| SlashCommand::Plan
|
||||
| SlashCommand::Diff
|
||||
| SlashCommand::Copy
|
||||
| SlashCommand::Mention
|
||||
| SlashCommand::Status
|
||||
| SlashCommand::DebugConfig
|
||||
| SlashCommand::Mcp
|
||||
| SlashCommand::Apps
|
||||
| SlashCommand::Plugins
|
||||
| SlashCommand::Logout
|
||||
| SlashCommand::Quit
|
||||
| SlashCommand::Exit
|
||||
| SlashCommand::Rollout
|
||||
| SlashCommand::Ps
|
||||
| SlashCommand::Stop
|
||||
| SlashCommand::Clear
|
||||
| SlashCommand::Realtime
|
||||
| SlashCommand::TestApproval
|
||||
| SlashCommand::MemoryDrop
|
||||
| SlashCommand::MemoryUpdate => SlashCommandBareBehavior::DispatchesDirectly,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn parse_invocation(
|
||||
self,
|
||||
args: &str,
|
||||
) -> Result<ParsedSlashCommand, SlashCommandUsageError> {
|
||||
let trimmed = args.trim();
|
||||
let spec = self.spec();
|
||||
if trimmed.is_empty() {
|
||||
return Ok(ParsedSlashCommand::Bare(self.bare_behavior()));
|
||||
return Ok(ParsedSlashCommand::Bare(spec.bare_behavior));
|
||||
}
|
||||
|
||||
match self {
|
||||
SlashCommand::Fast => match trimmed.to_ascii_lowercase().as_str() {
|
||||
match spec.parse_kind {
|
||||
SlashCommandParseKind::NoArgs => Err(SlashCommandUsageError {
|
||||
command: self,
|
||||
kind: SlashCommandUsageErrorKind::UnexpectedInlineArgs,
|
||||
}),
|
||||
SlashCommandParseKind::Fast => match trimmed.to_ascii_lowercase().as_str() {
|
||||
"on" => Ok(ParsedSlashCommand::Fast(FastSlashCommandArgs::On)),
|
||||
"off" => Ok(ParsedSlashCommand::Fast(FastSlashCommandArgs::Off)),
|
||||
"status" => Ok(ParsedSlashCommand::Fast(FastSlashCommandArgs::Status)),
|
||||
@@ -116,51 +69,10 @@ impl SlashCommand {
|
||||
kind: SlashCommandUsageErrorKind::InvalidInlineArgs,
|
||||
}),
|
||||
},
|
||||
SlashCommand::Rename => Ok(ParsedSlashCommand::Rename),
|
||||
SlashCommand::Plan => Ok(ParsedSlashCommand::Plan),
|
||||
SlashCommand::Review => Ok(ParsedSlashCommand::Review),
|
||||
SlashCommand::SandboxReadRoot => Ok(ParsedSlashCommand::SandboxReadRoot),
|
||||
SlashCommand::Model
|
||||
| SlashCommand::Approvals
|
||||
| SlashCommand::Permissions
|
||||
| SlashCommand::ElevateSandbox
|
||||
| SlashCommand::Experimental
|
||||
| SlashCommand::Skills
|
||||
| SlashCommand::New
|
||||
| SlashCommand::Resume
|
||||
| SlashCommand::Fork
|
||||
| SlashCommand::Init
|
||||
| SlashCommand::Compact
|
||||
| SlashCommand::Collab
|
||||
| SlashCommand::Agent
|
||||
| SlashCommand::Diff
|
||||
| SlashCommand::Copy
|
||||
| SlashCommand::Mention
|
||||
| SlashCommand::Status
|
||||
| SlashCommand::DebugConfig
|
||||
| SlashCommand::Statusline
|
||||
| SlashCommand::Theme
|
||||
| SlashCommand::Mcp
|
||||
| SlashCommand::Apps
|
||||
| SlashCommand::Plugins
|
||||
| SlashCommand::Logout
|
||||
| SlashCommand::Quit
|
||||
| SlashCommand::Exit
|
||||
| SlashCommand::Feedback
|
||||
| SlashCommand::Rollout
|
||||
| SlashCommand::Ps
|
||||
| SlashCommand::Stop
|
||||
| SlashCommand::Clear
|
||||
| SlashCommand::Personality
|
||||
| SlashCommand::Realtime
|
||||
| SlashCommand::Settings
|
||||
| SlashCommand::TestApproval
|
||||
| SlashCommand::MultiAgents
|
||||
| SlashCommand::MemoryDrop
|
||||
| SlashCommand::MemoryUpdate => Err(SlashCommandUsageError {
|
||||
command: self,
|
||||
kind: SlashCommandUsageErrorKind::UnexpectedInlineArgs,
|
||||
}),
|
||||
SlashCommandParseKind::Rename => Ok(ParsedSlashCommand::Rename),
|
||||
SlashCommandParseKind::Plan => Ok(ParsedSlashCommand::Plan),
|
||||
SlashCommandParseKind::Review => Ok(ParsedSlashCommand::Review),
|
||||
SlashCommandParseKind::SandboxReadRoot => Ok(ParsedSlashCommand::SandboxReadRoot),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user