Skip to main content

vibe_workspace/worktree/
manager.rs

1//! WorktreeManager - main coordinator for worktree operations
2
3use anyhow::Result;
4use std::path::PathBuf;
5
6use crate::workspace::WorkspaceManager;
7use crate::worktree::config::WorktreeConfig;
8use crate::worktree::config_manager::{
9    ConfigSummary, ConfigValidationError, WorktreeConfigManager,
10};
11use crate::worktree::operations::{CreateOptions, RemoveOptions, WorktreeOperations};
12use crate::worktree::status::WorktreeInfo;
13
14/// Main coordinator for all worktree operations
15pub struct WorktreeManager {
16    operations: WorktreeOperations,
17    pub workspace_root: PathBuf,
18    config: WorktreeConfig,
19    config_manager: Option<WorktreeConfigManager>,
20}
21
22impl WorktreeManager {
23    /// Create a new WorktreeManager
24    pub async fn new(workspace_root: PathBuf, config: Option<WorktreeConfig>) -> Result<Self> {
25        let config =
26            config.unwrap_or_else(|| WorktreeConfig::load_with_overrides().unwrap_or_default());
27
28        config
29            .validate()
30            .map_err(|e| anyhow::anyhow!("Invalid config: {}", e))?;
31
32        // Extract repository name from workspace_root
33        let repo_name = workspace_root
34            .file_name()
35            .and_then(|n| n.to_str())
36            .map(|s| s.to_string());
37
38        let operations = if let Some(name) = repo_name {
39            WorktreeOperations::new_with_repo_name(workspace_root.clone(), config.clone(), name)
40        } else {
41            WorktreeOperations::new(workspace_root.clone(), config.clone())
42        };
43
44        Ok(Self {
45            operations,
46            workspace_root,
47            config,
48            config_manager: None,
49        })
50    }
51
52    /// Create a new WorktreeManager with workspace integration
53    pub async fn new_with_workspace_manager(
54        workspace_manager: &WorkspaceManager,
55        repo_path: Option<PathBuf>,
56    ) -> Result<Self> {
57        let config_manager =
58            WorktreeConfigManager::new(workspace_manager.get_config_path().clone());
59
60        // Migrate legacy configuration if needed
61        config_manager.migrate_legacy_config().await?;
62
63        // Extract repository name if repo_path is provided
64        let repo_name = repo_path
65            .as_ref()
66            .and_then(|p| p.file_name())
67            .and_then(|n| n.to_str())
68            .map(|s| s.to_string());
69
70        // Load configuration for specific repository or use global
71        let config = if let Some(ref path) = repo_path {
72            config_manager.load_config_for_repo(path).await?
73        } else {
74            WorktreeConfig::load_with_overrides()
75                .map_err(|e| anyhow::anyhow!("Failed to load config: {}", e))?
76        };
77
78        // Use the appropriate repo root (repo_path if provided, otherwise workspace root)
79        let repo_root = repo_path
80            .as_ref()
81            .unwrap_or(workspace_manager.get_workspace_root())
82            .clone();
83
84        let operations = if let Some(name) = repo_name {
85            WorktreeOperations::new_with_repo_name(repo_root.clone(), config.clone(), name)
86        } else {
87            WorktreeOperations::new(repo_root.clone(), config.clone())
88        };
89
90        Ok(Self {
91            operations,
92            workspace_root: repo_root,
93            config,
94            config_manager: Some(config_manager),
95        })
96    }
97
98    /// Create a new worktree
99    pub async fn create_worktree(&self, task_id: String) -> Result<WorktreeInfo> {
100        let options = CreateOptions {
101            task_id,
102            base_branch: None,
103            force: false,
104            custom_path: None,
105        };
106
107        self.operations.create_worktree(options).await
108    }
109
110    /// Create a worktree with custom options
111    pub async fn create_worktree_with_options(
112        &self,
113        options: CreateOptions,
114    ) -> Result<WorktreeInfo> {
115        self.operations.create_worktree(options).await
116    }
117
118    /// Remove a worktree
119    pub async fn remove_worktree(&self, branch_or_path: String, force: bool) -> Result<()> {
120        let options = RemoveOptions {
121            target: branch_or_path,
122            force,
123            delete_branch: false,
124        };
125
126        self.operations.remove_worktree(options).await
127    }
128
129    /// Remove a worktree with custom options
130    pub async fn remove_worktree_with_options(&self, options: RemoveOptions) -> Result<()> {
131        self.operations.remove_worktree(options).await
132    }
133
134    /// List all worktrees
135    pub async fn list_worktrees(&self) -> Result<Vec<WorktreeInfo>> {
136        self.operations.list_worktrees().await
137    }
138
139    /// Get the git repository root
140    pub async fn get_git_root(&self) -> Result<PathBuf> {
141        self.operations.find_git_root().await
142    }
143
144    /// Get a reference to the config
145    pub fn get_config(&self) -> &WorktreeConfig {
146        &self.config
147    }
148
149    /// Resolve target (task ID, branch name, or path) to worktree info
150    pub async fn resolve_worktree_target(&self, target: &str) -> Result<WorktreeInfo> {
151        self.operations.resolve_worktree_target(target).await
152    }
153
154    /// Get a clone of the operations (for cleanup)
155    pub fn get_operations(&self) -> WorktreeOperations {
156        self.operations.clone()
157    }
158
159    /// Get configuration summary for diagnostics
160    pub async fn get_config_summary(&self) -> Result<ConfigSummary> {
161        if let Some(config_manager) = &self.config_manager {
162            config_manager.get_config_summary().await
163        } else {
164            Err(anyhow::anyhow!("Config manager not available"))
165        }
166    }
167
168    /// Validate current configuration
169    pub async fn validate_configuration(&self) -> Result<Vec<ConfigValidationError>> {
170        if let Some(config_manager) = &self.config_manager {
171            config_manager.validate_all_configs().await
172        } else {
173            Ok(Vec::new())
174        }
175    }
176}