use crate::RuleFormat;
use std::path::{Path, PathBuf};
#[derive(Debug, Clone)]
pub struct ToolRuleDir {
pub path: &'static str,
pub format: RuleFormat,
pub extensions: &'static [&'static str],
pub suffix: Option<&'static str>,
}
pub const TOOL_RULE_DIRS: &[ToolRuleDir] = &[
ToolRuleDir {
path: ".agents/rules",
format: RuleFormat::Agents,
extensions: &["md"],
suffix: None,
},
ToolRuleDir {
path: ".cursor/rules",
format: RuleFormat::Cursor,
extensions: &["mdc", "md"],
suffix: None,
},
ToolRuleDir {
path: ".windsurf/rules",
format: RuleFormat::Windsurf,
extensions: &["md"],
suffix: None,
},
ToolRuleDir {
path: ".github/instructions",
format: RuleFormat::Copilot,
extensions: &["md"],
suffix: Some(".instructions.md"),
},
ToolRuleDir {
path: ".clinerules",
format: RuleFormat::Cline,
extensions: &["md"],
suffix: None,
},
ToolRuleDir {
path: ".claude/rules",
format: RuleFormat::Claude,
extensions: &["md"],
suffix: None,
},
ToolRuleDir {
path: ".aiassistant/rules",
format: RuleFormat::Jetbrains,
extensions: &["md"],
suffix: None,
},
ToolRuleDir {
path: ".amazonq/rules",
format: RuleFormat::AmazonQ,
extensions: &["md"],
suffix: None,
},
];
pub fn infer_format_from_path(path: &Path) -> Option<RuleFormat> {
let path_str = path.to_string_lossy().replace('\\', "/");
for dir in TOOL_RULE_DIRS {
if path_str.contains(dir.path) {
return Some(dir.format);
}
}
None
}
pub fn find_tool_dir(path: &Path) -> Option<&'static ToolRuleDir> {
let path_str = path.to_string_lossy().replace('\\', "/");
TOOL_RULE_DIRS
.iter()
.find(|dir| path_str.contains(dir.path))
}
pub fn existing_tool_dirs(project_root: &Path) -> Vec<(PathBuf, &'static ToolRuleDir)> {
TOOL_RULE_DIRS
.iter()
.filter_map(|dir| {
let full = project_root.join(dir.path);
if full.exists() {
Some((full, dir))
} else {
None
}
})
.collect()
}