use std::env;
use ninmu_runtime::{ConfigLoader, PermissionMode, ResolvedPermissionMode};
pub(crate) fn parse_permission_mode_arg(value: &str) -> Result<PermissionMode, String> {
normalize_permission_mode(value)
.ok_or_else(|| {
format!(
"unsupported permission mode '{value}'. Use read-only, workspace-write, or danger-full-access."
)
})
.map(permission_mode_from_label)
}
pub(crate) fn permission_mode_from_label(mode: &str) -> PermissionMode {
match mode {
"read-only" => PermissionMode::ReadOnly,
"workspace-write" => PermissionMode::WorkspaceWrite,
"danger-full-access" => PermissionMode::DangerFullAccess,
other => panic!("unsupported permission mode label: {other}"),
}
}
pub(crate) fn permission_mode_from_resolved(mode: ResolvedPermissionMode) -> PermissionMode {
match mode {
ResolvedPermissionMode::ReadOnly => PermissionMode::ReadOnly,
ResolvedPermissionMode::WorkspaceWrite => PermissionMode::WorkspaceWrite,
ResolvedPermissionMode::DangerFullAccess => PermissionMode::DangerFullAccess,
}
}
pub(crate) fn default_permission_mode() -> PermissionMode {
env::var("RUSTY_CLAUDE_PERMISSION_MODE")
.ok()
.as_deref()
.and_then(normalize_permission_mode)
.map(permission_mode_from_label)
.or_else(config_permission_mode_for_current_dir)
.unwrap_or(PermissionMode::DangerFullAccess)
}
pub(crate) fn config_permission_mode_for_current_dir() -> Option<PermissionMode> {
let cwd = env::current_dir().ok()?;
let loader = ConfigLoader::default_for(&cwd);
loader
.load()
.ok()?
.permission_mode()
.map(permission_mode_from_resolved)
}
pub(crate) fn format_permissions_report(mode: &str) -> String {
let modes = [
("read-only", "Read/search tools only", mode == "read-only"),
(
"workspace-write",
"Edit files inside the workspace",
mode == "workspace-write",
),
(
"danger-full-access",
"Unrestricted tool access",
mode == "danger-full-access",
),
]
.into_iter()
.map(|(name, description, is_current)| {
let marker = if is_current {
"● current"
} else {
"○ available"
};
format!(" {name:<18} {marker:<11} {description}")
})
.collect::<Vec<_>>()
.join(
"
",
);
format!(
"Permissions
Active mode {mode}
Mode status live session default
Modes
{modes}
Usage
Inspect current mode with /permissions
Switch modes with /permissions <mode>"
)
}
pub(crate) fn format_permissions_switch_report(previous: &str, next: &str) -> String {
format!(
"Permissions updated
Result mode switched
Previous mode {previous}
Active mode {next}
Applies to subsequent tool calls
Usage /permissions to inspect current mode"
)
}
pub(crate) fn normalize_permission_mode(mode: &str) -> Option<&'static str> {
match mode.trim() {
"read-only" => Some("read-only"),
"workspace-write" => Some("workspace-write"),
"danger-full-access" => Some("danger-full-access"),
_ => None,
}
}