use std::collections::HashMap;
use rigg_core::normalize::normalize;
use rigg_core::resources::ResourceKind;
use rigg_core::resources::agent::{agent_volatile_fields, strip_agent_empty_fields};
use rigg_core::state::Checksums;
use rigg_diff::Change;
use crate::commands::common::{ResourceSelection, read_agent_yaml};
use super::report::check_agent_remote_conflict;
#[allow(clippy::too_many_arguments)]
pub(super) async fn collect_foundry_agents(
env: &rigg_core::config::ResolvedEnvironment,
files_root: &std::path::Path,
selection: &ResourceSelection,
filter: &Option<String>,
resources_to_push: &mut Vec<(ResourceKind, String, serde_json::Value, bool)>,
total_unchanged: &mut usize,
change_details: &mut HashMap<(ResourceKind, String), Vec<Change>>,
remote_values: &mut HashMap<(ResourceKind, String), serde_json::Value>,
checksums: &Checksums,
remote_conflicts: &mut Vec<(ResourceKind, String)>,
) -> anyhow::Result<()> {
for foundry_config in &env.foundry {
eprintln!(
"Comparing local agents against {}/{}...",
foundry_config.name, foundry_config.project
);
let foundry_client = rigg_client::FoundryClient::new(foundry_config)?;
tracing::info!(
"Connected to Foundry {}/{} using {}",
foundry_config.name,
foundry_config.project,
foundry_client.auth_method()
);
let agents_dir = env
.foundry_service_dir(files_root, foundry_config)
.join("agents");
if !agents_dir.exists() {
continue;
}
let existing_agents = foundry_client.list_agents().await?;
let remote_agent_map: HashMap<String, &serde_json::Value> = existing_agents
.iter()
.filter_map(|a| {
let name = a.get("name")?.as_str()?.to_string();
Some((name, a))
})
.collect();
let volatile = agent_volatile_fields();
for entry in std::fs::read_dir(&agents_dir)? {
let entry = entry?;
let path = entry.path();
if path.extension().and_then(|e| e.to_str()) != Some("yaml") {
continue;
}
let name = match path.file_stem().and_then(|n| n.to_str()) {
Some(n) => n.to_string(),
None => continue,
};
if let Some(exact_name) = selection.name_filter(ResourceKind::Agent) {
if name != exact_name {
continue;
}
}
if let Some(pattern) = filter {
if !name.contains(pattern) {
continue;
}
}
let mut payload = read_agent_yaml(&path)?;
if let Some(obj) = payload.as_object_mut() {
obj.insert("name".to_string(), serde_json::Value::String(name.clone()));
}
strip_agent_empty_fields(&mut payload);
match remote_agent_map.get(&name) {
Some(remote) => {
let mut remote_cleaned = (*remote).clone();
strip_agent_empty_fields(&mut remote_cleaned);
let normalized_local = normalize(&payload, volatile);
let normalized_remote = normalize(&remote_cleaned, volatile);
check_agent_remote_conflict(
&normalized_remote,
&name,
checksums,
remote_conflicts,
);
if normalized_local == normalized_remote {
*total_unchanged += 1;
} else {
let diff_result =
rigg_diff::diff(&normalized_remote, &normalized_local, "name");
change_details
.insert((ResourceKind::Agent, name.clone()), diff_result.changes);
remote_values
.insert((ResourceKind::Agent, name.clone()), normalized_remote);
resources_to_push.push((ResourceKind::Agent, name, payload, true));
}
}
None => {
resources_to_push.push((ResourceKind::Agent, name, payload, false));
}
}
}
}
Ok(())
}