use std::path::{Path, PathBuf};
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct LegacyRulesFile {
pub name: String,
pub path: PathBuf,
pub body: String,
}
pub const INIT_FILENAMES: &[&str] = &["AGENTS.md", ".cursorrules", ".windsurfrules"];
#[must_use]
pub fn scan_init_files(workspace_root: &Path) -> Vec<LegacyRulesFile> {
let mut out = Vec::new();
for name in INIT_FILENAMES {
let path = workspace_root.join(name);
if !path.is_file() {
continue;
}
match std::fs::read(&path) {
Ok(bytes) => out.push(LegacyRulesFile {
name: (*name).to_string(),
path,
body: String::from_utf8_lossy(&bytes).into_owned(),
}),
Err(e) => tracing::warn!(
target: caliban_common::tracing_targets::TARGET_MEMORY_INIT,
path = %path.display(),
error = %e,
"failed to read init file",
),
}
}
out
}
#[cfg(test)]
mod tests {
use super::*;
use std::fs;
use tempfile::TempDir;
#[test]
fn init_reads_agents_md_cursorrules_and_windsurfrules() {
let tmp = TempDir::new().unwrap();
let root = tmp.path();
fs::write(root.join("AGENTS.md"), "AGENTS-BODY").unwrap();
fs::write(root.join(".cursorrules"), "CURSOR-BODY").unwrap();
fs::write(root.join(".windsurfrules"), "WINDSURF-BODY").unwrap();
let found = scan_init_files(root);
let names: Vec<&str> = found.iter().map(|f| f.name.as_str()).collect();
assert_eq!(names, vec!["AGENTS.md", ".cursorrules", ".windsurfrules"]);
assert!(found[0].body.contains("AGENTS-BODY"));
assert!(found[1].body.contains("CURSOR-BODY"));
assert!(found[2].body.contains("WINDSURF-BODY"));
}
#[test]
fn init_omits_missing_files() {
let tmp = TempDir::new().unwrap();
let root = tmp.path();
fs::write(root.join(".cursorrules"), "ONLY-CURSOR").unwrap();
let found = scan_init_files(root);
assert_eq!(found.len(), 1);
assert_eq!(found[0].name, ".cursorrules");
}
}