prodigy 0.4.4

Turn ad-hoc Claude sessions into reproducible development pipelines with parallel AI agents
Documentation
//! Merge I/O effects for MapReduce agent results
//!
//! This module provides Effect-based abstractions for merging agent
//! worktree results back to the parent branch.
//!
//! NOTE: This demonstrates the Effect pattern with real WorktreeManager dependency.
//! Full merge integration is incremental and ongoing.

use crate::cook::execution::errors::MapReduceError;
use crate::cook::execution::mapreduce::effects::worktree::Worktree;
use crate::cook::execution::mapreduce::environment::MapEnv;
use stillwater::{from_async, Effect};

/// Result from merge operation
#[derive(Debug, Clone)]
pub struct MergeResult {
    /// Whether the merge succeeded
    pub success: bool,
    /// Commits that were merged
    pub commits: Vec<String>,
    /// Any conflicts encountered
    pub conflicts: Vec<String>,
}

/// Effect: Merge agent worktree results to parent branch
///
/// Merges commits from an agent's worktree back to the parent branch,
/// making the agent's work available for the reduce phase.
///
/// NOTE: Full integration requires additional WorktreeManager methods
/// that will be added incrementally.
///
/// # Example
///
/// ```ignore
/// let effect = merge_to_parent_effect(&worktree, "parent-branch");
/// let result = effect.run_async(&env).await?;
/// ```
pub fn merge_to_parent_effect(
    worktree: &Worktree,
    _parent_branch: &str,
) -> impl Effect<Output = MergeResult, Error = MapReduceError, Env = MapEnv> {
    let _worktree_name = worktree.name.clone();

    from_async(move |env: &MapEnv| {
        let _worktree_manager = env.worktree_manager.clone();

        async move {
            // TODO: Full integration with WorktreeManager merge methods
            // This will use worktree_manager.merge_to_parent() once available

            Ok(MergeResult {
                success: true,
                commits: vec!["abc123".to_string()],
                conflicts: vec![],
            })
        }
    })
}

/// Effect: Check if worktree has commits to merge
///
/// Checks whether an agent's worktree has any commits that need to be merged.
/// Used for commit validation and optimization.
pub fn has_commits_effect(
    _worktree: &Worktree,
) -> impl Effect<Output = bool, Error = MapReduceError, Env = MapEnv> {
    from_async(move |env: &MapEnv| {
        let _worktree_manager = env.worktree_manager.clone();

        async move {
            // TODO: Check if worktree has commits
            Ok(true)
        }
    })
}

/// Effect: Get list of commits in worktree
///
/// Retrieves the list of commits made in an agent's worktree.
pub fn list_commits_effect(
    _worktree: &Worktree,
) -> impl Effect<Output = Vec<String>, Error = MapReduceError, Env = MapEnv> {
    from_async(move |env: &MapEnv| {
        let _worktree_manager = env.worktree_manager.clone();

        async move {
            // TODO: Get commit list from worktree
            Ok(vec!["abc123".to_string()])
        }
    })
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_merge_result_structure() {
        let result = MergeResult {
            success: true,
            commits: vec!["abc123".to_string()],
            conflicts: vec![],
        };

        assert!(result.success);
        assert_eq!(result.commits.len(), 1);
        assert!(result.conflicts.is_empty());
    }
}