use super::types::ClaudeTerminalError;
use crate::sdk::EffortLevel;
const ALLOWED_PERMISSION_MODES: &[&str] = &[
"bypassPermissions",
"default",
"acceptEdits",
"acceptEditsAndAutoApprove",
];
pub struct BuildClaudeCommandOptions {
pub claude_bin: String,
pub permission_mode: String,
pub model: Option<String>,
pub effort: Option<EffortLevel>,
pub system_prompt: Option<String>,
pub resume_session_id: Option<String>,
}
pub fn build_claude_command(
opts: &BuildClaudeCommandOptions,
) -> Result<Vec<String>, ClaudeTerminalError> {
if !ALLOWED_PERMISSION_MODES.contains(&opts.permission_mode.as_str()) {
return Err(ClaudeTerminalError::Other(format!(
"invalid permission_mode {:?}; allowed: {}",
opts.permission_mode,
ALLOWED_PERMISSION_MODES.join(", ")
)));
}
let mut args = vec![opts.claude_bin.clone()];
if let Some(id) = &opts.resume_session_id {
args.push("--resume".to_string());
args.push(id.clone());
}
if let Some(m) = &opts.model {
args.push("--model".to_string());
args.push(m.clone());
}
if let Some(e) = opts.effort {
args.push("--effort".to_string());
args.push(e.as_str().to_string());
}
if let Some(s) = &opts.system_prompt {
args.push("--append-system-prompt".to_string());
args.push(s.clone());
}
args.push("--permission-mode".to_string());
args.push(opts.permission_mode.clone());
Ok(args)
}
#[cfg(test)]
#[expect(clippy::expect_used, reason = "tests panic on unexpected fixtures")]
mod tests {
use super::*;
fn cmd(opts: &BuildClaudeCommandOptions) -> Vec<String> {
build_claude_command(opts).expect("valid permission mode")
}
#[test]
fn minimal_no_model_no_system() {
let args = cmd(&BuildClaudeCommandOptions {
claude_bin: "claude".to_string(),
permission_mode: "bypassPermissions".to_string(),
model: None,
effort: None,
system_prompt: None,
resume_session_id: None,
});
assert_eq!(args, ["claude", "--permission-mode", "bypassPermissions"]);
}
#[test]
fn with_model() {
let args = cmd(&BuildClaudeCommandOptions {
claude_bin: "claude".to_string(),
permission_mode: "bypassPermissions".to_string(),
model: Some("claude-opus-4-7".to_string()),
effort: None,
system_prompt: None,
resume_session_id: None,
});
assert_eq!(
args,
[
"claude",
"--model",
"claude-opus-4-7",
"--permission-mode",
"bypassPermissions"
]
);
}
#[test]
fn with_system_prompt() {
let args = cmd(&BuildClaudeCommandOptions {
claude_bin: "claude".to_string(),
permission_mode: "bypassPermissions".to_string(),
model: None,
effort: None,
system_prompt: Some("Be concise.".to_string()),
resume_session_id: None,
});
assert_eq!(
args,
[
"claude",
"--append-system-prompt",
"Be concise.",
"--permission-mode",
"bypassPermissions"
]
);
}
#[test]
fn with_model_and_system() {
let args = cmd(&BuildClaudeCommandOptions {
claude_bin: "/usr/local/bin/claude".to_string(),
permission_mode: "bypassPermissions".to_string(),
model: Some("claude-sonnet-4-6".to_string()),
effort: None,
system_prompt: Some("sys".to_string()),
resume_session_id: None,
});
assert_eq!(
args,
[
"/usr/local/bin/claude",
"--model",
"claude-sonnet-4-6",
"--append-system-prompt",
"sys",
"--permission-mode",
"bypassPermissions"
]
);
}
#[test]
fn with_effort() {
let args = cmd(&BuildClaudeCommandOptions {
claude_bin: "claude".to_string(),
permission_mode: "bypassPermissions".to_string(),
model: None,
effort: Some(EffortLevel::High),
system_prompt: None,
resume_session_id: None,
});
assert_eq!(
args,
[
"claude",
"--effort",
"high",
"--permission-mode",
"bypassPermissions"
]
);
}
#[test]
fn rejects_invalid_permission_mode() {
let result = build_claude_command(&BuildClaudeCommandOptions {
claude_bin: "claude".to_string(),
permission_mode: "dangerousMode".to_string(),
model: None,
effort: None,
system_prompt: None,
resume_session_id: None,
});
assert!(result.is_err());
}
#[test]
fn with_resume_session_id() {
let args = cmd(&BuildClaudeCommandOptions {
claude_bin: "claude".to_string(),
permission_mode: "bypassPermissions".to_string(),
model: None,
effort: None,
system_prompt: None,
resume_session_id: Some("abc-123".to_string()),
});
assert_eq!(
args,
[
"claude",
"--resume",
"abc-123",
"--permission-mode",
"bypassPermissions"
]
);
}
}