mirror of
https://github.com/instructkr/claw-code.git
synced 2026-04-05 23:54:50 +08:00
fix: auto compaction threshold default 200k tokens
This commit is contained in:
12
rust/crates/commands/Cargo.toml
Normal file
12
rust/crates/commands/Cargo.toml
Normal file
@@ -0,0 +1,12 @@
|
||||
[package]
|
||||
name = "commands"
|
||||
version.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
publish.workspace = true
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
||||
[dependencies]
|
||||
runtime = { path = "../runtime" }
|
||||
622
rust/crates/commands/src/lib.rs
Normal file
622
rust/crates/commands/src/lib.rs
Normal file
@@ -0,0 +1,622 @@
|
||||
use runtime::{compact_session, CompactionConfig, Session};
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct CommandManifestEntry {
|
||||
pub name: String,
|
||||
pub source: CommandSource,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum CommandSource {
|
||||
Builtin,
|
||||
InternalOnly,
|
||||
FeatureGated,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default, PartialEq, Eq)]
|
||||
pub struct CommandRegistry {
|
||||
entries: Vec<CommandManifestEntry>,
|
||||
}
|
||||
|
||||
impl CommandRegistry {
|
||||
#[must_use]
|
||||
pub fn new(entries: Vec<CommandManifestEntry>) -> Self {
|
||||
Self { entries }
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn entries(&self) -> &[CommandManifestEntry] {
|
||||
&self.entries
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub struct SlashCommandSpec {
|
||||
pub name: &'static str,
|
||||
pub summary: &'static str,
|
||||
pub argument_hint: Option<&'static str>,
|
||||
pub resume_supported: bool,
|
||||
}
|
||||
|
||||
const SLASH_COMMAND_SPECS: &[SlashCommandSpec] = &[
|
||||
SlashCommandSpec {
|
||||
name: "help",
|
||||
summary: "Show available slash commands",
|
||||
argument_hint: None,
|
||||
resume_supported: true,
|
||||
},
|
||||
SlashCommandSpec {
|
||||
name: "status",
|
||||
summary: "Show current session status",
|
||||
argument_hint: None,
|
||||
resume_supported: true,
|
||||
},
|
||||
SlashCommandSpec {
|
||||
name: "compact",
|
||||
summary: "Compact local session history",
|
||||
argument_hint: None,
|
||||
resume_supported: true,
|
||||
},
|
||||
SlashCommandSpec {
|
||||
name: "model",
|
||||
summary: "Show or switch the active model",
|
||||
argument_hint: Some("[model]"),
|
||||
resume_supported: false,
|
||||
},
|
||||
SlashCommandSpec {
|
||||
name: "permissions",
|
||||
summary: "Show or switch the active permission mode",
|
||||
argument_hint: Some("[read-only|workspace-write|danger-full-access]"),
|
||||
resume_supported: false,
|
||||
},
|
||||
SlashCommandSpec {
|
||||
name: "clear",
|
||||
summary: "Start a fresh local session",
|
||||
argument_hint: Some("[--confirm]"),
|
||||
resume_supported: true,
|
||||
},
|
||||
SlashCommandSpec {
|
||||
name: "cost",
|
||||
summary: "Show cumulative token usage for this session",
|
||||
argument_hint: None,
|
||||
resume_supported: true,
|
||||
},
|
||||
SlashCommandSpec {
|
||||
name: "resume",
|
||||
summary: "Load a saved session into the REPL",
|
||||
argument_hint: Some("<session-path>"),
|
||||
resume_supported: false,
|
||||
},
|
||||
SlashCommandSpec {
|
||||
name: "config",
|
||||
summary: "Inspect Claude config files or merged sections",
|
||||
argument_hint: Some("[env|hooks|model]"),
|
||||
resume_supported: true,
|
||||
},
|
||||
SlashCommandSpec {
|
||||
name: "memory",
|
||||
summary: "Inspect loaded Claude instruction memory files",
|
||||
argument_hint: None,
|
||||
resume_supported: true,
|
||||
},
|
||||
SlashCommandSpec {
|
||||
name: "init",
|
||||
summary: "Create a starter CLAUDE.md for this repo",
|
||||
argument_hint: None,
|
||||
resume_supported: true,
|
||||
},
|
||||
SlashCommandSpec {
|
||||
name: "diff",
|
||||
summary: "Show git diff for current workspace changes",
|
||||
argument_hint: None,
|
||||
resume_supported: true,
|
||||
},
|
||||
SlashCommandSpec {
|
||||
name: "version",
|
||||
summary: "Show CLI version and build information",
|
||||
argument_hint: None,
|
||||
resume_supported: true,
|
||||
},
|
||||
SlashCommandSpec {
|
||||
name: "bughunter",
|
||||
summary: "Inspect the codebase for likely bugs",
|
||||
argument_hint: Some("[scope]"),
|
||||
resume_supported: false,
|
||||
},
|
||||
SlashCommandSpec {
|
||||
name: "commit",
|
||||
summary: "Generate a commit message and create a git commit",
|
||||
argument_hint: None,
|
||||
resume_supported: false,
|
||||
},
|
||||
SlashCommandSpec {
|
||||
name: "pr",
|
||||
summary: "Draft or create a pull request from the conversation",
|
||||
argument_hint: Some("[context]"),
|
||||
resume_supported: false,
|
||||
},
|
||||
SlashCommandSpec {
|
||||
name: "issue",
|
||||
summary: "Draft or create a GitHub issue from the conversation",
|
||||
argument_hint: Some("[context]"),
|
||||
resume_supported: false,
|
||||
},
|
||||
SlashCommandSpec {
|
||||
name: "ultraplan",
|
||||
summary: "Run a deep planning prompt with multi-step reasoning",
|
||||
argument_hint: Some("[task]"),
|
||||
resume_supported: false,
|
||||
},
|
||||
SlashCommandSpec {
|
||||
name: "teleport",
|
||||
summary: "Jump to a file or symbol by searching the workspace",
|
||||
argument_hint: Some("<symbol-or-path>"),
|
||||
resume_supported: false,
|
||||
},
|
||||
SlashCommandSpec {
|
||||
name: "debug-tool-call",
|
||||
summary: "Replay the last tool call with debug details",
|
||||
argument_hint: None,
|
||||
resume_supported: false,
|
||||
},
|
||||
SlashCommandSpec {
|
||||
name: "export",
|
||||
summary: "Export the current conversation to a file",
|
||||
argument_hint: Some("[file]"),
|
||||
resume_supported: true,
|
||||
},
|
||||
SlashCommandSpec {
|
||||
name: "session",
|
||||
summary: "List or switch managed local sessions",
|
||||
argument_hint: Some("[list|switch <session-id>]"),
|
||||
resume_supported: false,
|
||||
},
|
||||
];
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum SlashCommand {
|
||||
Help,
|
||||
Status,
|
||||
Compact,
|
||||
Bughunter {
|
||||
scope: Option<String>,
|
||||
},
|
||||
Commit,
|
||||
Pr {
|
||||
context: Option<String>,
|
||||
},
|
||||
Issue {
|
||||
context: Option<String>,
|
||||
},
|
||||
Ultraplan {
|
||||
task: Option<String>,
|
||||
},
|
||||
Teleport {
|
||||
target: Option<String>,
|
||||
},
|
||||
DebugToolCall,
|
||||
Model {
|
||||
model: Option<String>,
|
||||
},
|
||||
Permissions {
|
||||
mode: Option<String>,
|
||||
},
|
||||
Clear {
|
||||
confirm: bool,
|
||||
},
|
||||
Cost,
|
||||
Resume {
|
||||
session_path: Option<String>,
|
||||
},
|
||||
Config {
|
||||
section: Option<String>,
|
||||
},
|
||||
Memory,
|
||||
Init,
|
||||
Diff,
|
||||
Version,
|
||||
Export {
|
||||
path: Option<String>,
|
||||
},
|
||||
Session {
|
||||
action: Option<String>,
|
||||
target: Option<String>,
|
||||
},
|
||||
Unknown(String),
|
||||
}
|
||||
|
||||
impl SlashCommand {
|
||||
#[must_use]
|
||||
pub fn parse(input: &str) -> Option<Self> {
|
||||
let trimmed = input.trim();
|
||||
if !trimmed.starts_with('/') {
|
||||
return None;
|
||||
}
|
||||
|
||||
let mut parts = trimmed.trim_start_matches('/').split_whitespace();
|
||||
let command = parts.next().unwrap_or_default();
|
||||
Some(match command {
|
||||
"help" => Self::Help,
|
||||
"status" => Self::Status,
|
||||
"compact" => Self::Compact,
|
||||
"bughunter" => Self::Bughunter {
|
||||
scope: remainder_after_command(trimmed, command),
|
||||
},
|
||||
"commit" => Self::Commit,
|
||||
"pr" => Self::Pr {
|
||||
context: remainder_after_command(trimmed, command),
|
||||
},
|
||||
"issue" => Self::Issue {
|
||||
context: remainder_after_command(trimmed, command),
|
||||
},
|
||||
"ultraplan" => Self::Ultraplan {
|
||||
task: remainder_after_command(trimmed, command),
|
||||
},
|
||||
"teleport" => Self::Teleport {
|
||||
target: remainder_after_command(trimmed, command),
|
||||
},
|
||||
"debug-tool-call" => Self::DebugToolCall,
|
||||
"model" => Self::Model {
|
||||
model: parts.next().map(ToOwned::to_owned),
|
||||
},
|
||||
"permissions" => Self::Permissions {
|
||||
mode: parts.next().map(ToOwned::to_owned),
|
||||
},
|
||||
"clear" => Self::Clear {
|
||||
confirm: parts.next() == Some("--confirm"),
|
||||
},
|
||||
"cost" => Self::Cost,
|
||||
"resume" => Self::Resume {
|
||||
session_path: parts.next().map(ToOwned::to_owned),
|
||||
},
|
||||
"config" => Self::Config {
|
||||
section: parts.next().map(ToOwned::to_owned),
|
||||
},
|
||||
"memory" => Self::Memory,
|
||||
"init" => Self::Init,
|
||||
"diff" => Self::Diff,
|
||||
"version" => Self::Version,
|
||||
"export" => Self::Export {
|
||||
path: parts.next().map(ToOwned::to_owned),
|
||||
},
|
||||
"session" => Self::Session {
|
||||
action: parts.next().map(ToOwned::to_owned),
|
||||
target: parts.next().map(ToOwned::to_owned),
|
||||
},
|
||||
other => Self::Unknown(other.to_string()),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn remainder_after_command(input: &str, command: &str) -> Option<String> {
|
||||
input
|
||||
.trim()
|
||||
.strip_prefix(&format!("/{command}"))
|
||||
.map(str::trim)
|
||||
.filter(|value| !value.is_empty())
|
||||
.map(ToOwned::to_owned)
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn slash_command_specs() -> &'static [SlashCommandSpec] {
|
||||
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]
|
||||
pub fn render_slash_command_help() -> String {
|
||||
let mut lines = vec![
|
||||
"Slash commands".to_string(),
|
||||
" [resume] means the command also works with --resume SESSION.json".to_string(),
|
||||
];
|
||||
for spec in slash_command_specs() {
|
||||
let name = match spec.argument_hint {
|
||||
Some(argument_hint) => format!("/{} {}", spec.name, argument_hint),
|
||||
None => format!("/{}", spec.name),
|
||||
};
|
||||
let resume = if spec.resume_supported {
|
||||
" [resume]"
|
||||
} else {
|
||||
""
|
||||
};
|
||||
lines.push(format!(" {name:<20} {}{}", spec.summary, resume));
|
||||
}
|
||||
lines.join("\n")
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct SlashCommandResult {
|
||||
pub message: String,
|
||||
pub session: Session,
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn handle_slash_command(
|
||||
input: &str,
|
||||
session: &Session,
|
||||
compaction: CompactionConfig,
|
||||
) -> Option<SlashCommandResult> {
|
||||
match SlashCommand::parse(input)? {
|
||||
SlashCommand::Compact => {
|
||||
let result = compact_session(session, compaction);
|
||||
let message = if result.removed_message_count == 0 {
|
||||
"Compaction skipped: session is below the compaction threshold.".to_string()
|
||||
} else {
|
||||
format!(
|
||||
"Compacted {} messages into a resumable system summary.",
|
||||
result.removed_message_count
|
||||
)
|
||||
};
|
||||
Some(SlashCommandResult {
|
||||
message,
|
||||
session: result.compacted_session,
|
||||
})
|
||||
}
|
||||
SlashCommand::Help => Some(SlashCommandResult {
|
||||
message: render_slash_command_help(),
|
||||
session: session.clone(),
|
||||
}),
|
||||
SlashCommand::Status
|
||||
| SlashCommand::Bughunter { .. }
|
||||
| SlashCommand::Commit
|
||||
| SlashCommand::Pr { .. }
|
||||
| SlashCommand::Issue { .. }
|
||||
| SlashCommand::Ultraplan { .. }
|
||||
| SlashCommand::Teleport { .. }
|
||||
| SlashCommand::DebugToolCall
|
||||
| SlashCommand::Model { .. }
|
||||
| SlashCommand::Permissions { .. }
|
||||
| SlashCommand::Clear { .. }
|
||||
| SlashCommand::Cost
|
||||
| SlashCommand::Resume { .. }
|
||||
| SlashCommand::Config { .. }
|
||||
| SlashCommand::Memory
|
||||
| SlashCommand::Init
|
||||
| SlashCommand::Diff
|
||||
| SlashCommand::Version
|
||||
| SlashCommand::Export { .. }
|
||||
| SlashCommand::Session { .. }
|
||||
| SlashCommand::Unknown(_) => None,
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::{
|
||||
handle_slash_command, render_slash_command_help, resume_supported_slash_commands,
|
||||
slash_command_specs, SlashCommand,
|
||||
};
|
||||
use runtime::{CompactionConfig, ContentBlock, ConversationMessage, MessageRole, Session};
|
||||
|
||||
#[test]
|
||||
fn parses_supported_slash_commands() {
|
||||
assert_eq!(SlashCommand::parse("/help"), Some(SlashCommand::Help));
|
||||
assert_eq!(SlashCommand::parse(" /status "), Some(SlashCommand::Status));
|
||||
assert_eq!(
|
||||
SlashCommand::parse("/bughunter runtime"),
|
||||
Some(SlashCommand::Bughunter {
|
||||
scope: Some("runtime".to_string())
|
||||
})
|
||||
);
|
||||
assert_eq!(SlashCommand::parse("/commit"), Some(SlashCommand::Commit));
|
||||
assert_eq!(
|
||||
SlashCommand::parse("/pr ready for review"),
|
||||
Some(SlashCommand::Pr {
|
||||
context: Some("ready for review".to_string())
|
||||
})
|
||||
);
|
||||
assert_eq!(
|
||||
SlashCommand::parse("/issue flaky test"),
|
||||
Some(SlashCommand::Issue {
|
||||
context: Some("flaky test".to_string())
|
||||
})
|
||||
);
|
||||
assert_eq!(
|
||||
SlashCommand::parse("/ultraplan ship both features"),
|
||||
Some(SlashCommand::Ultraplan {
|
||||
task: Some("ship both features".to_string())
|
||||
})
|
||||
);
|
||||
assert_eq!(
|
||||
SlashCommand::parse("/teleport conversation.rs"),
|
||||
Some(SlashCommand::Teleport {
|
||||
target: Some("conversation.rs".to_string())
|
||||
})
|
||||
);
|
||||
assert_eq!(
|
||||
SlashCommand::parse("/debug-tool-call"),
|
||||
Some(SlashCommand::DebugToolCall)
|
||||
);
|
||||
assert_eq!(
|
||||
SlashCommand::parse("/model claude-opus"),
|
||||
Some(SlashCommand::Model {
|
||||
model: Some("claude-opus".to_string()),
|
||||
})
|
||||
);
|
||||
assert_eq!(
|
||||
SlashCommand::parse("/model"),
|
||||
Some(SlashCommand::Model { model: None })
|
||||
);
|
||||
assert_eq!(
|
||||
SlashCommand::parse("/permissions read-only"),
|
||||
Some(SlashCommand::Permissions {
|
||||
mode: Some("read-only".to_string()),
|
||||
})
|
||||
);
|
||||
assert_eq!(
|
||||
SlashCommand::parse("/clear"),
|
||||
Some(SlashCommand::Clear { confirm: false })
|
||||
);
|
||||
assert_eq!(
|
||||
SlashCommand::parse("/clear --confirm"),
|
||||
Some(SlashCommand::Clear { confirm: true })
|
||||
);
|
||||
assert_eq!(SlashCommand::parse("/cost"), Some(SlashCommand::Cost));
|
||||
assert_eq!(
|
||||
SlashCommand::parse("/resume session.json"),
|
||||
Some(SlashCommand::Resume {
|
||||
session_path: Some("session.json".to_string()),
|
||||
})
|
||||
);
|
||||
assert_eq!(
|
||||
SlashCommand::parse("/config"),
|
||||
Some(SlashCommand::Config { section: None })
|
||||
);
|
||||
assert_eq!(
|
||||
SlashCommand::parse("/config env"),
|
||||
Some(SlashCommand::Config {
|
||||
section: Some("env".to_string())
|
||||
})
|
||||
);
|
||||
assert_eq!(SlashCommand::parse("/memory"), Some(SlashCommand::Memory));
|
||||
assert_eq!(SlashCommand::parse("/init"), Some(SlashCommand::Init));
|
||||
assert_eq!(SlashCommand::parse("/diff"), Some(SlashCommand::Diff));
|
||||
assert_eq!(SlashCommand::parse("/version"), Some(SlashCommand::Version));
|
||||
assert_eq!(
|
||||
SlashCommand::parse("/export notes.txt"),
|
||||
Some(SlashCommand::Export {
|
||||
path: Some("notes.txt".to_string())
|
||||
})
|
||||
);
|
||||
assert_eq!(
|
||||
SlashCommand::parse("/session switch abc123"),
|
||||
Some(SlashCommand::Session {
|
||||
action: Some("switch".to_string()),
|
||||
target: Some("abc123".to_string())
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn renders_help_from_shared_specs() {
|
||||
let help = render_slash_command_help();
|
||||
assert!(help.contains("works with --resume SESSION.json"));
|
||||
assert!(help.contains("/help"));
|
||||
assert!(help.contains("/status"));
|
||||
assert!(help.contains("/compact"));
|
||||
assert!(help.contains("/bughunter [scope]"));
|
||||
assert!(help.contains("/commit"));
|
||||
assert!(help.contains("/pr [context]"));
|
||||
assert!(help.contains("/issue [context]"));
|
||||
assert!(help.contains("/ultraplan [task]"));
|
||||
assert!(help.contains("/teleport <symbol-or-path>"));
|
||||
assert!(help.contains("/debug-tool-call"));
|
||||
assert!(help.contains("/model [model]"));
|
||||
assert!(help.contains("/permissions [read-only|workspace-write|danger-full-access]"));
|
||||
assert!(help.contains("/clear [--confirm]"));
|
||||
assert!(help.contains("/cost"));
|
||||
assert!(help.contains("/resume <session-path>"));
|
||||
assert!(help.contains("/config [env|hooks|model]"));
|
||||
assert!(help.contains("/memory"));
|
||||
assert!(help.contains("/init"));
|
||||
assert!(help.contains("/diff"));
|
||||
assert!(help.contains("/version"));
|
||||
assert!(help.contains("/export [file]"));
|
||||
assert!(help.contains("/session [list|switch <session-id>]"));
|
||||
assert_eq!(slash_command_specs().len(), 22);
|
||||
assert_eq!(resume_supported_slash_commands().len(), 11);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn compacts_sessions_via_slash_command() {
|
||||
let session = Session {
|
||||
version: 1,
|
||||
messages: vec![
|
||||
ConversationMessage::user_text("a ".repeat(200)),
|
||||
ConversationMessage::assistant(vec![ContentBlock::Text {
|
||||
text: "b ".repeat(200),
|
||||
}]),
|
||||
ConversationMessage::tool_result("1", "bash", "ok ".repeat(200), false),
|
||||
ConversationMessage::assistant(vec![ContentBlock::Text {
|
||||
text: "recent".to_string(),
|
||||
}]),
|
||||
],
|
||||
};
|
||||
|
||||
let result = handle_slash_command(
|
||||
"/compact",
|
||||
&session,
|
||||
CompactionConfig {
|
||||
preserve_recent_messages: 2,
|
||||
max_estimated_tokens: 1,
|
||||
},
|
||||
)
|
||||
.expect("slash command should be handled");
|
||||
|
||||
assert!(result.message.contains("Compacted 2 messages"));
|
||||
assert_eq!(result.session.messages[0].role, MessageRole::System);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn help_command_is_non_mutating() {
|
||||
let session = Session::new();
|
||||
let result = handle_slash_command("/help", &session, CompactionConfig::default())
|
||||
.expect("help command should be handled");
|
||||
assert_eq!(result.session, session);
|
||||
assert!(result.message.contains("Slash commands"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ignores_unknown_or_runtime_bound_slash_commands() {
|
||||
let session = Session::new();
|
||||
assert!(handle_slash_command("/unknown", &session, CompactionConfig::default()).is_none());
|
||||
assert!(handle_slash_command("/status", &session, CompactionConfig::default()).is_none());
|
||||
assert!(
|
||||
handle_slash_command("/bughunter", &session, CompactionConfig::default()).is_none()
|
||||
);
|
||||
assert!(handle_slash_command("/commit", &session, CompactionConfig::default()).is_none());
|
||||
assert!(handle_slash_command("/pr", &session, CompactionConfig::default()).is_none());
|
||||
assert!(handle_slash_command("/issue", &session, CompactionConfig::default()).is_none());
|
||||
assert!(
|
||||
handle_slash_command("/ultraplan", &session, CompactionConfig::default()).is_none()
|
||||
);
|
||||
assert!(
|
||||
handle_slash_command("/teleport foo", &session, CompactionConfig::default()).is_none()
|
||||
);
|
||||
assert!(
|
||||
handle_slash_command("/debug-tool-call", &session, CompactionConfig::default())
|
||||
.is_none()
|
||||
);
|
||||
assert!(
|
||||
handle_slash_command("/model claude", &session, CompactionConfig::default()).is_none()
|
||||
);
|
||||
assert!(handle_slash_command(
|
||||
"/permissions read-only",
|
||||
&session,
|
||||
CompactionConfig::default()
|
||||
)
|
||||
.is_none());
|
||||
assert!(handle_slash_command("/clear", &session, CompactionConfig::default()).is_none());
|
||||
assert!(
|
||||
handle_slash_command("/clear --confirm", &session, CompactionConfig::default())
|
||||
.is_none()
|
||||
);
|
||||
assert!(handle_slash_command("/cost", &session, CompactionConfig::default()).is_none());
|
||||
assert!(handle_slash_command(
|
||||
"/resume session.json",
|
||||
&session,
|
||||
CompactionConfig::default()
|
||||
)
|
||||
.is_none());
|
||||
assert!(handle_slash_command("/config", &session, CompactionConfig::default()).is_none());
|
||||
assert!(
|
||||
handle_slash_command("/config env", &session, CompactionConfig::default()).is_none()
|
||||
);
|
||||
assert!(handle_slash_command("/diff", &session, CompactionConfig::default()).is_none());
|
||||
assert!(handle_slash_command("/version", &session, CompactionConfig::default()).is_none());
|
||||
assert!(
|
||||
handle_slash_command("/export note.txt", &session, CompactionConfig::default())
|
||||
.is_none()
|
||||
);
|
||||
assert!(
|
||||
handle_slash_command("/session list", &session, CompactionConfig::default()).is_none()
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user