use parking_lot::Mutex;
use prollytree::diff::{ConflictResolver, MergeConflict, MergeResult, SemanticMergeResolver};
use prollytree::git::versioned_store::GitVersionedKvStore;
use prollytree::git::worktree::WorktreeManager;
use std::sync::Arc;
use tempfile::TempDir;
fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("Multi-Agent Worktree Integration Demo");
println!("=====================================");
let temp_dir = TempDir::new()?;
let repo_path = temp_dir.path();
init_git_repo(repo_path)?;
let mut main_store = GitVersionedKvStore::<16>::init(repo_path.join("data"))?;
main_store.insert(
b"shared_config".to_vec(),
br#"{"version": 1, "mode": "production"}"#.to_vec(),
)?;
main_store.insert(b"global_counter".to_vec(), b"0".to_vec())?;
main_store.commit("Initial shared data")?;
println!("[main] Initialized shared repository with shared_config + global_counter");
let manager_arc = Arc::new(Mutex::new(WorktreeManager::new(repo_path)?));
let agent_scenarios = vec![
(
"agent1",
"customer-service",
br#"{"id": "cust_001", "issue": "billing", "priority": "high"}"#.as_slice(),
),
(
"agent2",
"data-analysis",
br#"{"users": 1250, "sessions": 3400, "conversion": 0.045}"#.as_slice(),
),
(
"agent3",
"content-generation",
br#"{"title": "Summer Sale", "body": "Get 20% off...", "target": "email"}"#.as_slice(),
),
];
let agent_data_root = temp_dir.path().join("agent_data");
std::fs::create_dir_all(&agent_data_root)?;
let mut agent_stores: Vec<(String, GitVersionedKvStore<16>, String)> = Vec::new();
for (agent_id, session_id, _payload) in &agent_scenarios {
let workspace = repo_path.join(format!("{}_workspace", agent_id));
let branch_name = format!("{}-{}", agent_id, session_id);
let worktree_info = {
let mut manager = manager_arc.lock();
manager.add_worktree(&workspace, &branch_name, true)?
};
println!(
"[{}] Worktree id={} branch={}",
agent_id, worktree_info.id, worktree_info.branch
);
let agent_repo = agent_data_root.join(agent_id);
std::fs::create_dir_all(&agent_repo)?;
init_git_repo(&agent_repo)?;
let mut agent_store = GitVersionedKvStore::<16>::init(agent_repo.join("data"))?;
agent_store.commit("agent workspace bootstrap")?;
agent_stores.push((agent_id.to_string(), agent_store, branch_name));
}
println!("\n[agents] running independent workloads...");
for ((agent_id, agent_store, _branch), (_, _session, payload)) in
agent_stores.iter_mut().zip(agent_scenarios.iter())
{
match agent_id.as_str() {
"agent1" => {
agent_store.insert(b"customer:latest".to_vec(), payload.to_vec())?;
agent_store.insert(
b"response_templates".to_vec(),
br#"{"billing": "Thank you for contacting us about billing..."}"#.to_vec(),
)?;
agent_store.commit("agent1: customer-service updates")?;
}
"agent2" => {
agent_store.insert(b"analytics:daily".to_vec(), payload.to_vec())?;
agent_store.insert(b"global_counter".to_vec(), b"25".to_vec())?;
agent_store.commit("agent2: analytics updates")?;
}
"agent3" => {
agent_store.insert(b"content:campaign".to_vec(), payload.to_vec())?;
agent_store.insert(
b"shared_config".to_vec(),
br#"{"version": 1, "mode": "production", "feature_flags": {"new_ui": true}}"#
.to_vec(),
)?;
agent_store.commit("agent3: content updates")?;
}
_ => {}
}
}
println!("[agents] all completed.");
println!("\n[merge] bringing agent work into main store...");
let semantic = SemanticMergeResolver::default();
for (agent_id, agent_store, _branch) in agent_stores.iter() {
for key in agent_store.list_keys() {
let value = agent_store.get(&key).expect("agent value");
let merged = match main_store.get(&key) {
Some(existing) if existing != value => {
let conflict = MergeConflict {
key: key.clone(),
base_value: None,
source_value: Some(value.clone()),
destination_value: Some(existing.clone()),
};
match semantic.resolve_conflict(&conflict) {
Some(MergeResult::Modified(_, merged_value))
| Some(MergeResult::Added(_, merged_value)) => merged_value,
_ => value.clone(),
}
}
Some(_) => value.clone(),
None => value.clone(),
};
main_store.insert(key.clone(), merged)?;
}
main_store.commit(&format!("merge {}'s work into main", agent_id))?;
}
println!("[merge] done.");
println!("\n[main] converged state:");
for key in main_store.list_keys() {
let value = main_store.get(&key).expect("key present");
let key_str = String::from_utf8_lossy(&key);
let val_str = String::from_utf8_lossy(&value);
println!(" {} -> {}", key_str, val_str);
}
println!("\n[manager] worktree housekeeping...");
{
let manager = manager_arc.lock();
let listed = manager.list_worktrees();
println!(" {} worktrees registered", listed.len());
for info in &listed {
println!(" - id={} branch={}", info.id, info.branch);
}
}
{
let mut manager = manager_arc.lock();
let first_id = manager
.list_worktrees()
.first()
.map(|w| w.id.clone())
.expect("at least one worktree");
manager.lock_worktree(&first_id, "demo: hold for a long-running job")?;
println!(
" locked worktree {}: {}",
first_id,
manager.is_locked(&first_id)
);
manager.unlock_worktree(&first_id)?;
println!(
" unlocked worktree {}: {}",
first_id,
manager.is_locked(&first_id)
);
}
println!("\nDemo complete.");
Ok(())
}
fn init_git_repo(repo_path: &std::path::Path) -> Result<(), Box<dyn std::error::Error>> {
use std::process::Command;
Command::new("git")
.args(["init"])
.current_dir(repo_path)
.output()?;
Command::new("git")
.args(["config", "user.name", "Multi-Agent Demo"])
.current_dir(repo_path)
.output()?;
Command::new("git")
.args(["config", "user.email", "demo@multiagent.ai"])
.current_dir(repo_path)
.output()?;
std::fs::write(repo_path.join("README.md"), "# Multi-Agent Repository")?;
Command::new("git")
.args(["add", "."])
.current_dir(repo_path)
.output()?;
Command::new("git")
.args(["commit", "-m", "Initial repository setup"])
.current_dir(repo_path)
.output()?;
Ok(())
}