use serde::{Deserialize, Serialize};
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub enum PermissionMode {
#[default]
Default,
AcceptEdits,
BypassPermissions,
Plan,
}
impl PermissionMode {
pub fn allows_all(&self) -> bool {
matches!(self, PermissionMode::BypassPermissions)
}
pub fn is_read_only(&self) -> bool {
matches!(self, PermissionMode::Plan)
}
pub fn auto_approves_files(&self) -> bool {
matches!(self, PermissionMode::AcceptEdits)
}
pub fn is_default(&self) -> bool {
matches!(self, PermissionMode::Default)
}
pub fn description(&self) -> &'static str {
match self {
PermissionMode::Default => "Standard permission flow with allow/deny rules",
PermissionMode::AcceptEdits => "Auto-approve file operations",
PermissionMode::BypassPermissions => "Allow all operations (dangerous)",
PermissionMode::Plan => "Read-only mode",
}
}
}
impl std::fmt::Display for PermissionMode {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
PermissionMode::Default => write!(f, "default"),
PermissionMode::AcceptEdits => write!(f, "acceptEdits"),
PermissionMode::BypassPermissions => write!(f, "bypassPermissions"),
PermissionMode::Plan => write!(f, "plan"),
}
}
}
impl std::str::FromStr for PermissionMode {
type Err = String;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s.to_lowercase().as_str() {
"default" => Ok(PermissionMode::Default),
"acceptedits" | "accept-edits" | "accept_edits" => Ok(PermissionMode::AcceptEdits),
"bypasspermissions" | "bypass-permissions" | "bypass_permissions" | "bypass" => {
Ok(PermissionMode::BypassPermissions)
}
"plan" | "readonly" | "read-only" | "read_only" => Ok(PermissionMode::Plan),
_ => Err(format!("Unknown permission mode: {}", s)),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_default_mode() {
let mode = PermissionMode::default();
assert!(mode.is_default());
assert!(!mode.allows_all());
assert!(!mode.is_read_only());
assert!(!mode.auto_approves_files());
}
#[test]
fn test_accept_edits_mode() {
let mode = PermissionMode::AcceptEdits;
assert!(!mode.is_default());
assert!(!mode.allows_all());
assert!(!mode.is_read_only());
assert!(mode.auto_approves_files());
}
#[test]
fn test_bypass_mode() {
let mode = PermissionMode::BypassPermissions;
assert!(!mode.is_default());
assert!(mode.allows_all());
assert!(!mode.is_read_only());
assert!(!mode.auto_approves_files());
}
#[test]
fn test_plan_mode() {
let mode = PermissionMode::Plan;
assert!(!mode.is_default());
assert!(!mode.allows_all());
assert!(mode.is_read_only());
assert!(!mode.auto_approves_files());
}
#[test]
fn test_display() {
assert_eq!(PermissionMode::Default.to_string(), "default");
assert_eq!(PermissionMode::AcceptEdits.to_string(), "acceptEdits");
assert_eq!(
PermissionMode::BypassPermissions.to_string(),
"bypassPermissions"
);
assert_eq!(PermissionMode::Plan.to_string(), "plan");
}
#[test]
fn test_from_str() {
assert_eq!(
"default".parse::<PermissionMode>().unwrap(),
PermissionMode::Default
);
assert_eq!(
"acceptEdits".parse::<PermissionMode>().unwrap(),
PermissionMode::AcceptEdits
);
assert_eq!(
"accept-edits".parse::<PermissionMode>().unwrap(),
PermissionMode::AcceptEdits
);
assert_eq!(
"bypass".parse::<PermissionMode>().unwrap(),
PermissionMode::BypassPermissions
);
assert_eq!(
"plan".parse::<PermissionMode>().unwrap(),
PermissionMode::Plan
);
assert_eq!(
"readonly".parse::<PermissionMode>().unwrap(),
PermissionMode::Plan
);
}
#[test]
fn test_serde() {
let mode = PermissionMode::AcceptEdits;
let json = serde_json::to_string(&mode).unwrap();
assert_eq!(json, "\"acceptEdits\"");
let parsed: PermissionMode = serde_json::from_str(&json).unwrap();
assert_eq!(parsed, mode);
}
}