use crate::abstractions::git::GitOperations;
use crate::cook::execution::{ClaudeExecutor, CommandExecutor};
use crate::cook::interaction::UserInteraction;
use crate::cook::session::SessionManager;
use crate::subprocess::SubprocessManager;
use std::sync::Arc;
#[derive(Clone)]
pub struct OrchestratorEnv {
pub session_manager: Arc<dyn SessionManager>,
pub command_executor: Arc<dyn CommandExecutor>,
pub claude_executor: Arc<dyn ClaudeExecutor>,
pub user_interaction: Arc<dyn UserInteraction>,
pub git_operations: Arc<dyn GitOperations>,
pub subprocess_manager: SubprocessManager,
}
impl OrchestratorEnv {
pub fn new(
session_manager: Arc<dyn SessionManager>,
command_executor: Arc<dyn CommandExecutor>,
claude_executor: Arc<dyn ClaudeExecutor>,
user_interaction: Arc<dyn UserInteraction>,
git_operations: Arc<dyn GitOperations>,
subprocess_manager: SubprocessManager,
) -> Self {
Self {
session_manager,
command_executor,
claude_executor,
user_interaction,
git_operations,
subprocess_manager,
}
}
}
impl std::fmt::Debug for OrchestratorEnv {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("OrchestratorEnv")
.field("session_manager", &"<dyn SessionManager>")
.field("command_executor", &"<dyn CommandExecutor>")
.field("claude_executor", &"<dyn ClaudeExecutor>")
.field("user_interaction", &"<dyn UserInteraction>")
.field("git_operations", &"<dyn GitOperations>")
.field("subprocess_manager", &self.subprocess_manager)
.finish()
}
}
#[cfg(test)]
pub mod mocks {
use crate::cook::session::{SessionManager, SessionState, SessionSummary, SessionUpdate};
use async_trait::async_trait;
use std::path::Path;
#[derive(Debug, Clone)]
pub struct MockSessionManager;
#[async_trait]
impl SessionManager for MockSessionManager {
async fn start_session(&self, _session_id: &str) -> Result<(), anyhow::Error> {
Ok(())
}
async fn update_session(&self, _update: SessionUpdate) -> Result<(), anyhow::Error> {
Ok(())
}
async fn complete_session(&self) -> Result<SessionSummary, anyhow::Error> {
Ok(SessionSummary {
iterations: 0,
files_changed: 0,
})
}
fn get_state(&self) -> Result<SessionState, anyhow::Error> {
use std::path::PathBuf;
Ok(SessionState::new(
"test-session".to_string(),
PathBuf::from("/tmp"),
))
}
async fn save_state(&self, _path: &Path) -> Result<(), anyhow::Error> {
Ok(())
}
async fn load_state(&self, _path: &Path) -> Result<(), anyhow::Error> {
Ok(())
}
async fn load_session(&self, _session_id: &str) -> Result<SessionState, anyhow::Error> {
use std::path::PathBuf;
Ok(SessionState::new(
_session_id.to_string(),
PathBuf::from("/tmp"),
))
}
async fn save_checkpoint(&self, _state: &SessionState) -> Result<(), anyhow::Error> {
Ok(())
}
async fn list_resumable(
&self,
) -> Result<Vec<crate::cook::session::SessionInfo>, anyhow::Error> {
Ok(vec![])
}
async fn get_last_interrupted(&self) -> Result<Option<String>, anyhow::Error> {
Ok(None)
}
}
}
#[cfg(test)]
impl OrchestratorEnv {
#[allow(dead_code)]
pub fn test() -> Self {
todo!("Full mock environment implementation deferred - use Effect::pure() for testing")
}
}
#[cfg(test)]
mod tests {
use super::*;
#[tokio::test]
async fn test_mock_session_manager() {
use mocks::MockSessionManager;
let manager = MockSessionManager;
assert!(manager.start_session("test-123").await.is_ok());
assert!(manager.load_session("test-123").await.is_ok());
}
}