mirror of
https://github.com/lWolvesl/claw-code.git
synced 2026-04-02 07:41:52 +08:00
feat(cli): add permissions clear and cost commands
Expand the shared slash registry and REPL dispatcher with real session-management commands so the CLI feels closer to Claude Code during interactive use. /permissions now reports or switches the active permission mode, /clear rebuilds a fresh local session without restarting the process, and /cost reports cumulative token usage honestly from the runtime tracker. The implementation keeps command parsing centralized in the commands crate and preserves the existing prompt-mode path while rebuilding runtime state safely when commands change session configuration. Constraint: Commands must be genuinely useful local behavior rather than placeholders Constraint: Preserve REPL continuity when changing permissions or clearing session state Rejected: Store permission-mode changes only in environment variables | would not update the live runtime for the current session Confidence: high Scope-risk: moderate Reversibility: clean Directive: Keep future stateful slash commands rebuilding from current session + system prompt instead of mutating hidden runtime internals Tested: cargo fmt; cargo clippy --workspace --all-targets -- -D warnings; cargo test --workspace Not-tested: manual live API session exercising permission changes mid-conversation
This commit is contained in:
@@ -58,6 +58,21 @@ const SLASH_COMMAND_SPECS: &[SlashCommandSpec] = &[
|
||||
summary: "Show or switch the active model",
|
||||
argument_hint: Some("[model]"),
|
||||
},
|
||||
SlashCommandSpec {
|
||||
name: "permissions",
|
||||
summary: "Show or switch the active permission mode",
|
||||
argument_hint: Some("[read-only|workspace-write|danger-full-access]"),
|
||||
},
|
||||
SlashCommandSpec {
|
||||
name: "clear",
|
||||
summary: "Start a fresh local session",
|
||||
argument_hint: None,
|
||||
},
|
||||
SlashCommandSpec {
|
||||
name: "cost",
|
||||
summary: "Show cumulative token usage for this session",
|
||||
argument_hint: None,
|
||||
},
|
||||
];
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
@@ -66,6 +81,9 @@ pub enum SlashCommand {
|
||||
Status,
|
||||
Compact,
|
||||
Model { model: Option<String> },
|
||||
Permissions { mode: Option<String> },
|
||||
Clear,
|
||||
Cost,
|
||||
Unknown(String),
|
||||
}
|
||||
|
||||
@@ -86,6 +104,11 @@ impl SlashCommand {
|
||||
"model" => Self::Model {
|
||||
model: parts.next().map(ToOwned::to_owned),
|
||||
},
|
||||
"permissions" => Self::Permissions {
|
||||
mode: parts.next().map(ToOwned::to_owned),
|
||||
},
|
||||
"clear" => Self::Clear,
|
||||
"cost" => Self::Cost,
|
||||
other => Self::Unknown(other.to_string()),
|
||||
})
|
||||
}
|
||||
@@ -141,7 +164,12 @@ pub fn handle_slash_command(
|
||||
message: render_slash_command_help(),
|
||||
session: session.clone(),
|
||||
}),
|
||||
SlashCommand::Status | SlashCommand::Model { .. } | SlashCommand::Unknown(_) => None,
|
||||
SlashCommand::Status
|
||||
| SlashCommand::Model { .. }
|
||||
| SlashCommand::Permissions { .. }
|
||||
| SlashCommand::Clear
|
||||
| SlashCommand::Cost
|
||||
| SlashCommand::Unknown(_) => None,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -166,6 +194,14 @@ mod tests {
|
||||
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));
|
||||
assert_eq!(SlashCommand::parse("/cost"), Some(SlashCommand::Cost));
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -175,7 +211,10 @@ mod tests {
|
||||
assert!(help.contains("/status"));
|
||||
assert!(help.contains("/compact"));
|
||||
assert!(help.contains("/model [model]"));
|
||||
assert_eq!(slash_command_specs().len(), 4);
|
||||
assert!(help.contains("/permissions [read-only|workspace-write|danger-full-access]"));
|
||||
assert!(help.contains("/clear"));
|
||||
assert!(help.contains("/cost"));
|
||||
assert_eq!(slash_command_specs().len(), 7);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -225,5 +264,13 @@ mod tests {
|
||||
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("/cost", &session, CompactionConfig::default()).is_none());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user