fn compute_cohesion(
local_indices: &[usize],
index: &AgentContextIndex,
func_indices: &[usize],
global_to_local: &HashMap<usize, usize>,
) -> f64 {
if local_indices.len() < 2 {
return 1.0;
}
let local_set: HashSet<usize> = local_indices.iter().copied().collect();
let mut internal_edges = 0usize;
for &li in local_indices {
let global_idx = func_indices[li];
if let Some(callees) = index.calls.get(&global_idx) {
for &callee_global in callees {
if let Some(&callee_local) = global_to_local.get(&callee_global) {
if local_set.contains(&callee_local) && callee_local != li {
internal_edges += 1;
}
}
}
}
}
let n = local_indices.len() as f64;
let max_edges = n * (n - 1.0);
if max_edges == 0.0 {
return 1.0;
}
internal_edges as f64 / max_edges
}
fn compute_impact(index: &AgentContextIndex, file_path: &str) -> SplitImpact {
let mut importing_files = Vec::new();
let target_indices: HashSet<usize> = index
.file_index
.get(file_path)
.map(|v| v.iter().copied().collect())
.unwrap_or_default();
for (other_file, other_indices) in &index.file_index {
if other_file == file_path {
continue;
}
let has_dependency = other_indices.iter().any(|&gi| {
index
.calls
.get(&gi)
.map(|callees| callees.iter().any(|c| target_indices.contains(c)))
.unwrap_or(false)
});
if has_dependency {
importing_files.push(other_file.clone());
}
}
importing_files.sort();
SplitImpact {
importing_files,
circular_risks: Vec::new(), }
}
pub fn execute_split(plan: &SplitPlan, project_root: &Path) -> anyhow::Result<Vec<PathBuf>> {
use std::fs;
let source_path = project_root.join(&plan.source_file);
let source_content = fs::read_to_string(&source_path)?;
let source_lines: Vec<&str> = source_content.lines().collect();
let parent_dir = source_path
.parent()
.ok_or_else(|| anyhow::anyhow!("No parent directory for {}", plan.source_file))?;
let stem = source_path
.file_stem()
.and_then(|s| s.to_str())
.ok_or_else(|| anyhow::anyhow!("Invalid file stem for {}", plan.source_file))?;
let mut created_files = Vec::new();
let mut include_directives = Vec::new();
for cluster in &plan.clusters {
let cluster_filename = format!("{}_{}.rs", stem, cluster.suggested_name);
let cluster_path = parent_dir.join(&cluster_filename);
let mut cluster_lines = Vec::new();
let mut ranges: Vec<(usize, usize)> = cluster
.items
.iter()
.map(|item| (item.line_range.0, item.line_range.1))
.collect();
ranges.sort_by_key(|r| r.0);
for (start, end) in &ranges {
let start_idx = start.saturating_sub(1);
let total_lines = source_lines.len();
let end_idx = (*end).min(total_lines);
for line in &source_lines[start_idx..end_idx] {
cluster_lines.push(*line);
}
cluster_lines.push(""); }
let cluster_content = cluster_lines.join("\n");
fs::write(&cluster_path, &cluster_content)?;
created_files.push(cluster_path);
include_directives.push(format!("include!(\"{}\");", cluster_filename));
}
Ok(created_files)
}