1use std::path::Path;
2
3use anyhow::{Context, Result};
4use async_trait::async_trait;
5use vtcode_core::config::WorkspaceTrustLevel;
6use vtcode_core::utils::dot_config::{load_workspace_trust_level, update_workspace_trust};
7
8#[derive(Debug, Clone, Copy, PartialEq, Eq)]
9pub enum WorkspaceTrustSyncOutcome {
10 AlreadyMatches(WorkspaceTrustLevel),
11 Upgraded {
12 previous: Option<WorkspaceTrustLevel>,
13 new: WorkspaceTrustLevel,
14 },
15 SkippedDowngrade(WorkspaceTrustLevel),
16}
17
18#[async_trait]
19pub trait WorkspaceTrustSynchronizer {
20 async fn synchronize(
21 &self,
22 workspace: &Path,
23 desired_level: WorkspaceTrustLevel,
24 ) -> Result<WorkspaceTrustSyncOutcome>;
25}
26
27#[derive(Default, Clone, Copy)]
28pub struct DefaultWorkspaceTrustSynchronizer;
29
30impl DefaultWorkspaceTrustSynchronizer {
31 pub fn new() -> Self {
32 Self
33 }
34}
35
36#[async_trait]
37impl WorkspaceTrustSynchronizer for DefaultWorkspaceTrustSynchronizer {
38 async fn synchronize(
39 &self,
40 workspace: &Path,
41 desired_level: WorkspaceTrustLevel,
42 ) -> Result<WorkspaceTrustSyncOutcome> {
43 ensure_workspace_trust_level_silent(workspace, desired_level).await
44 }
45}
46
47pub async fn ensure_workspace_trust_level_silent(
48 workspace: &Path,
49 desired_level: WorkspaceTrustLevel,
50) -> Result<WorkspaceTrustSyncOutcome> {
51 let current_level = load_workspace_trust_level(workspace)
52 .await
53 .context("Failed to load user configuration for trust sync")?;
54
55 if let Some(level) = current_level {
56 if level == desired_level {
57 return Ok(WorkspaceTrustSyncOutcome::AlreadyMatches(level));
58 }
59
60 if level == WorkspaceTrustLevel::FullAuto
61 && desired_level == WorkspaceTrustLevel::ToolsPolicy
62 {
63 return Ok(WorkspaceTrustSyncOutcome::SkippedDowngrade(level));
64 }
65 }
66
67 update_workspace_trust(workspace, desired_level)
68 .await
69 .context("Failed to persist workspace trust sync")?;
70
71 Ok(WorkspaceTrustSyncOutcome::Upgraded {
72 previous: current_level,
73 new: desired_level,
74 })
75}