agent_rules.rs

 1use std::sync::Arc;
 2
 3use anyhow::{Context as _, Result};
 4use fs::Fs;
 5use gpui::{App, AppContext, Task};
 6use prompt_store::SystemPromptRulesFile;
 7use util::maybe;
 8use worktree::Worktree;
 9
10const RULES_FILE_NAMES: [&'static str; 6] = [
11    ".rules",
12    ".cursorrules",
13    ".windsurfrules",
14    ".clinerules",
15    ".github/copilot-instructions.md",
16    "CLAUDE.md",
17];
18
19pub fn load_worktree_rules_file(
20    fs: Arc<dyn Fs>,
21    worktree: &Worktree,
22    cx: &App,
23) -> Option<Task<Result<SystemPromptRulesFile>>> {
24    let selected_rules_file = RULES_FILE_NAMES
25        .into_iter()
26        .filter_map(|name| {
27            worktree
28                .entry_for_path(name)
29                .filter(|entry| entry.is_file())
30                .map(|entry| (entry.path.clone(), worktree.absolutize(&entry.path)))
31        })
32        .next();
33
34    // Note that Cline supports `.clinerules` being a directory, but that is not currently
35    // supported. This doesn't seem to occur often in GitHub repositories.
36    selected_rules_file.map(|(path_in_worktree, abs_path)| {
37        let fs = fs.clone();
38        cx.background_spawn(maybe!(async move {
39            let abs_path = abs_path?;
40            let text = fs
41                .load(&abs_path)
42                .await
43                .with_context(|| format!("Failed to load assistant rules file {:?}", abs_path))?;
44            anyhow::Ok(SystemPromptRulesFile {
45                path_in_worktree,
46                abs_path: abs_path.into(),
47                text: text.trim().to_string(),
48            })
49        }))
50    })
51}