|
@@ -35,6 +35,7 @@ pub struct SlashCommandSpec {
|
|
|
pub name: &'static str,
|
|
pub name: &'static str,
|
|
|
pub summary: &'static str,
|
|
pub summary: &'static str,
|
|
|
pub argument_hint: Option<&'static str>,
|
|
pub argument_hint: Option<&'static str>,
|
|
|
|
|
+ pub resume_supported: bool,
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
const SLASH_COMMAND_SPECS: &[SlashCommandSpec] = &[
|
|
const SLASH_COMMAND_SPECS: &[SlashCommandSpec] = &[
|
|
@@ -42,56 +43,67 @@ const SLASH_COMMAND_SPECS: &[SlashCommandSpec] = &[
|
|
|
name: "help",
|
|
name: "help",
|
|
|
summary: "Show available slash commands",
|
|
summary: "Show available slash commands",
|
|
|
argument_hint: None,
|
|
argument_hint: None,
|
|
|
|
|
+ resume_supported: true,
|
|
|
},
|
|
},
|
|
|
SlashCommandSpec {
|
|
SlashCommandSpec {
|
|
|
name: "status",
|
|
name: "status",
|
|
|
summary: "Show current session status",
|
|
summary: "Show current session status",
|
|
|
argument_hint: None,
|
|
argument_hint: None,
|
|
|
|
|
+ resume_supported: true,
|
|
|
},
|
|
},
|
|
|
SlashCommandSpec {
|
|
SlashCommandSpec {
|
|
|
name: "compact",
|
|
name: "compact",
|
|
|
summary: "Compact local session history",
|
|
summary: "Compact local session history",
|
|
|
argument_hint: None,
|
|
argument_hint: None,
|
|
|
|
|
+ resume_supported: true,
|
|
|
},
|
|
},
|
|
|
SlashCommandSpec {
|
|
SlashCommandSpec {
|
|
|
name: "model",
|
|
name: "model",
|
|
|
summary: "Show or switch the active model",
|
|
summary: "Show or switch the active model",
|
|
|
argument_hint: Some("[model]"),
|
|
argument_hint: Some("[model]"),
|
|
|
|
|
+ resume_supported: false,
|
|
|
},
|
|
},
|
|
|
SlashCommandSpec {
|
|
SlashCommandSpec {
|
|
|
name: "permissions",
|
|
name: "permissions",
|
|
|
summary: "Show or switch the active permission mode",
|
|
summary: "Show or switch the active permission mode",
|
|
|
argument_hint: Some("[read-only|workspace-write|danger-full-access]"),
|
|
argument_hint: Some("[read-only|workspace-write|danger-full-access]"),
|
|
|
|
|
+ resume_supported: false,
|
|
|
},
|
|
},
|
|
|
SlashCommandSpec {
|
|
SlashCommandSpec {
|
|
|
name: "clear",
|
|
name: "clear",
|
|
|
summary: "Start a fresh local session",
|
|
summary: "Start a fresh local session",
|
|
|
argument_hint: None,
|
|
argument_hint: None,
|
|
|
|
|
+ resume_supported: true,
|
|
|
},
|
|
},
|
|
|
SlashCommandSpec {
|
|
SlashCommandSpec {
|
|
|
name: "cost",
|
|
name: "cost",
|
|
|
summary: "Show cumulative token usage for this session",
|
|
summary: "Show cumulative token usage for this session",
|
|
|
argument_hint: None,
|
|
argument_hint: None,
|
|
|
|
|
+ resume_supported: true,
|
|
|
},
|
|
},
|
|
|
SlashCommandSpec {
|
|
SlashCommandSpec {
|
|
|
name: "resume",
|
|
name: "resume",
|
|
|
summary: "Load a saved session into the REPL",
|
|
summary: "Load a saved session into the REPL",
|
|
|
argument_hint: Some("<session-path>"),
|
|
argument_hint: Some("<session-path>"),
|
|
|
|
|
+ resume_supported: false,
|
|
|
},
|
|
},
|
|
|
SlashCommandSpec {
|
|
SlashCommandSpec {
|
|
|
name: "config",
|
|
name: "config",
|
|
|
summary: "Inspect discovered Claude config files",
|
|
summary: "Inspect discovered Claude config files",
|
|
|
argument_hint: None,
|
|
argument_hint: None,
|
|
|
|
|
+ resume_supported: true,
|
|
|
},
|
|
},
|
|
|
SlashCommandSpec {
|
|
SlashCommandSpec {
|
|
|
name: "memory",
|
|
name: "memory",
|
|
|
summary: "Inspect loaded Claude instruction memory files",
|
|
summary: "Inspect loaded Claude instruction memory files",
|
|
|
argument_hint: None,
|
|
argument_hint: None,
|
|
|
|
|
+ resume_supported: true,
|
|
|
},
|
|
},
|
|
|
SlashCommandSpec {
|
|
SlashCommandSpec {
|
|
|
name: "init",
|
|
name: "init",
|
|
|
summary: "Create a starter CLAUDE.md for this repo",
|
|
summary: "Create a starter CLAUDE.md for this repo",
|
|
|
argument_hint: None,
|
|
argument_hint: None,
|
|
|
|
|
+ resume_supported: true,
|
|
|
},
|
|
},
|
|
|
];
|
|
];
|
|
|
|
|
|
|
@@ -149,15 +161,31 @@ pub fn slash_command_specs() -> &'static [SlashCommandSpec] {
|
|
|
SLASH_COMMAND_SPECS
|
|
SLASH_COMMAND_SPECS
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+#[must_use]
|
|
|
|
|
+pub fn resume_supported_slash_commands() -> Vec<&'static SlashCommandSpec> {
|
|
|
|
|
+ slash_command_specs()
|
|
|
|
|
+ .iter()
|
|
|
|
|
+ .filter(|spec| spec.resume_supported)
|
|
|
|
|
+ .collect()
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
#[must_use]
|
|
#[must_use]
|
|
|
pub fn render_slash_command_help() -> String {
|
|
pub fn render_slash_command_help() -> String {
|
|
|
- let mut lines = vec!["Available commands:".to_string()];
|
|
|
|
|
|
|
+ let mut lines = vec![
|
|
|
|
|
+ "Available commands:".to_string(),
|
|
|
|
|
+ " (resume-safe commands are marked with [resume])".to_string(),
|
|
|
|
|
+ ];
|
|
|
for spec in slash_command_specs() {
|
|
for spec in slash_command_specs() {
|
|
|
let name = match spec.argument_hint {
|
|
let name = match spec.argument_hint {
|
|
|
Some(argument_hint) => format!("/{} {}", spec.name, argument_hint),
|
|
Some(argument_hint) => format!("/{} {}", spec.name, argument_hint),
|
|
|
None => format!("/{}", spec.name),
|
|
None => format!("/{}", spec.name),
|
|
|
};
|
|
};
|
|
|
- lines.push(format!(" {name:<20} {}", spec.summary));
|
|
|
|
|
|
|
+ let resume = if spec.resume_supported {
|
|
|
|
|
+ " [resume]"
|
|
|
|
|
+ } else {
|
|
|
|
|
+ ""
|
|
|
|
|
+ };
|
|
|
|
|
+ lines.push(format!(" {name:<20} {}{}", spec.summary, resume));
|
|
|
}
|
|
}
|
|
|
lines.join("\n")
|
|
lines.join("\n")
|
|
|
}
|
|
}
|
|
@@ -210,7 +238,8 @@ pub fn handle_slash_command(
|
|
|
#[cfg(test)]
|
|
#[cfg(test)]
|
|
|
mod tests {
|
|
mod tests {
|
|
|
use super::{
|
|
use super::{
|
|
|
- handle_slash_command, render_slash_command_help, slash_command_specs, SlashCommand,
|
|
|
|
|
|
|
+ handle_slash_command, render_slash_command_help, resume_supported_slash_commands,
|
|
|
|
|
+ slash_command_specs, SlashCommand,
|
|
|
};
|
|
};
|
|
|
use runtime::{CompactionConfig, ContentBlock, ConversationMessage, MessageRole, Session};
|
|
use runtime::{CompactionConfig, ContentBlock, ConversationMessage, MessageRole, Session};
|
|
|
|
|
|
|
@@ -250,6 +279,7 @@ mod tests {
|
|
|
#[test]
|
|
#[test]
|
|
|
fn renders_help_from_shared_specs() {
|
|
fn renders_help_from_shared_specs() {
|
|
|
let help = render_slash_command_help();
|
|
let help = render_slash_command_help();
|
|
|
|
|
+ assert!(help.contains("resume-safe commands"));
|
|
|
assert!(help.contains("/help"));
|
|
assert!(help.contains("/help"));
|
|
|
assert!(help.contains("/status"));
|
|
assert!(help.contains("/status"));
|
|
|
assert!(help.contains("/compact"));
|
|
assert!(help.contains("/compact"));
|
|
@@ -262,6 +292,7 @@ mod tests {
|
|
|
assert!(help.contains("/memory"));
|
|
assert!(help.contains("/memory"));
|
|
|
assert!(help.contains("/init"));
|
|
assert!(help.contains("/init"));
|
|
|
assert_eq!(slash_command_specs().len(), 11);
|
|
assert_eq!(slash_command_specs().len(), 11);
|
|
|
|
|
+ assert_eq!(resume_supported_slash_commands().len(), 8);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
#[test]
|