use std::path::Path;
use crate::sandbox::SandboxPolicy;
use crate::tui::app::AppMode;
use crate::tui::approval::ApprovalMode;
use crate::worker_profile::ShellPolicy;
use super::ops::UserInputProvenance;
#[derive(Debug, Clone, Copy)]
pub(crate) struct ModeSessionPrefs {
pub(crate) agent_allow_shell: bool,
pub(crate) agent_trust_mode: bool,
pub(crate) agent_approval_mode: ApprovalMode,
}
#[derive(Debug, Clone, Copy)]
pub(crate) struct EffectiveModePolicy {
#[allow(dead_code)]
pub(crate) mode: AppMode,
pub(crate) allow_shell: bool,
pub(crate) trust_mode: bool,
pub(crate) approval_mode: ApprovalMode,
}
#[must_use]
pub(crate) fn base_policy_for_mode(mode: AppMode, prefs: &ModeSessionPrefs) -> EffectiveModePolicy {
match mode {
AppMode::Plan => EffectiveModePolicy {
mode,
allow_shell: false,
trust_mode: false,
approval_mode: ApprovalMode::Suggest,
},
AppMode::Agent | AppMode::Auto | AppMode::Operate => EffectiveModePolicy {
mode,
allow_shell: prefs.agent_allow_shell,
trust_mode: prefs.agent_trust_mode,
approval_mode: prefs.agent_approval_mode,
},
AppMode::Yolo => EffectiveModePolicy {
mode,
allow_shell: true,
trust_mode: true,
approval_mode: ApprovalMode::Bypass,
},
}
}
#[derive(Debug, Clone)]
pub(crate) struct TurnAuthority {
pub(crate) mode: AppMode,
pub(crate) allow_shell: bool,
pub(crate) trust_mode: bool,
pub(crate) auto_approve: bool,
pub(crate) approval_mode: ApprovalMode,
pub(crate) dynamic_active_tools: Vec<&'static str>,
pub(crate) status: Option<String>,
}
impl TurnAuthority {
#[must_use]
pub(crate) fn from_effective_fields(
mode: AppMode,
allow_shell: bool,
trust_mode: bool,
auto_approve: bool,
approval_mode: ApprovalMode,
) -> Self {
Self {
mode,
allow_shell,
trust_mode,
auto_approve,
approval_mode,
dynamic_active_tools: Vec::new(),
status: None,
}
}
#[must_use]
pub(crate) fn approval_mode_for_session(&self) -> ApprovalMode {
agent_approval_mode_for_turn(self.auto_approve, self.approval_mode)
}
#[must_use]
pub(crate) fn shell_policy(&self) -> ShellPolicy {
shell_policy_for_mode(self.mode, self.allow_shell)
}
#[must_use]
pub(crate) fn sandbox_policy(&self, workspace: &Path) -> SandboxPolicy {
sandbox_policy_for_mode(self.mode, workspace)
}
}
#[must_use]
pub(crate) fn effective_input_policy(
provenance: UserInputProvenance,
requested_mode: AppMode,
_content: &str,
allow_shell: bool,
trust_mode: bool,
auto_approve: bool,
approval_mode: ApprovalMode,
) -> TurnAuthority {
let mut mode = requested_mode;
let mut trust_mode = trust_mode;
let mut auto_approve = auto_approve;
let mut approval_mode = approval_mode;
let mut status = None;
if !provenance_can_inherit_standing_auto_authority(provenance) {
let had_auto_authority = matches!(mode, AppMode::Yolo)
|| trust_mode
|| auto_approve
|| matches!(approval_mode, ApprovalMode::Bypass);
if matches!(mode, AppMode::Yolo) {
mode = AppMode::Agent;
}
trust_mode = false;
auto_approve = false;
if matches!(approval_mode, ApprovalMode::Auto | ApprovalMode::Bypass) {
approval_mode = ApprovalMode::Suggest;
}
if had_auto_authority {
status = Some(format!(
"Input provenance '{}' cannot inherit standing auto-approval authority; continuing with approvals required.",
provenance.as_str()
));
}
}
TurnAuthority {
mode,
allow_shell,
trust_mode,
auto_approve,
approval_mode,
dynamic_active_tools: Vec::new(),
status,
}
}
#[must_use]
pub(crate) fn provenance_can_inherit_standing_auto_authority(
provenance: UserInputProvenance,
) -> bool {
matches!(
provenance,
UserInputProvenance::ExternalUser | UserInputProvenance::Runtime
)
}
#[must_use]
pub(crate) fn agent_approval_mode_for_turn(
auto_approve: bool,
approval_mode: ApprovalMode,
) -> ApprovalMode {
if auto_approve {
ApprovalMode::Bypass
} else {
approval_mode
}
}
#[must_use]
pub(crate) fn sandbox_policy_for_mode(mode: AppMode, workspace: &Path) -> SandboxPolicy {
match mode {
AppMode::Plan => SandboxPolicy::ReadOnly,
AppMode::Agent | AppMode::Auto | AppMode::Operate => SandboxPolicy::WorkspaceWrite {
writable_roots: vec![workspace.to_path_buf()],
network_access: true,
exclude_tmpdir: false,
exclude_slash_tmp: false,
},
AppMode::Yolo => SandboxPolicy::DangerFullAccess,
}
}
#[must_use]
pub(crate) fn shell_policy_for_mode(mode: AppMode, allow_shell: bool) -> ShellPolicy {
if !allow_shell {
return ShellPolicy::None;
}
match mode {
AppMode::Plan => ShellPolicy::None,
AppMode::Agent | AppMode::Auto | AppMode::Operate | AppMode::Yolo => ShellPolicy::Full,
}
}