ast-bro 3.0.0

Fast, AST-based code-navigation: shape, public API, deps & call graphs, hybrid semantic search, structural rewrite, and log squeezing. MCP server included.
Documentation
//! Agent prompt content. The source of truth lives in
//! `skills/ast-bro/SKILL.md` (YAML frontmatter + the agent prompt body).
//! This module embeds that file at compile time via `include_str!` and
//! strips the YAML frontmatter on demand so `ast-bro prompt`, the CLI
//! installers, and the manual skill file all stay in lockstep.

/// Raw SKILL.md — frontmatter + prompt body. Embedded at compile time,
/// so any edit to `skills/ast-bro/SKILL.md` triggers a rebuild.
pub const SKILL_MD: &str = include_str!("../skills/ast-bro/SKILL.md");

/// The prompt body: SKILL.md with its YAML frontmatter block removed.
///
/// Computed once on first access and cached in a `OnceLock<&'static str>` —
/// subsequent calls return the memoized slice with no allocation. Exposing
/// this as a function (rather than a const) keeps the compile-time cost
/// free: `include_str!` + const slicing would require a const-eval-friendly
/// parser, whereas this is just eight lines of runtime string splitting.
pub fn agent_prompt() -> &'static str {
    static CACHED: std::sync::OnceLock<&'static str> = std::sync::OnceLock::new();
    CACHED.get_or_init(|| strip_frontmatter(SKILL_MD))
}

/// Strip YAML frontmatter (bounded by two `---` lines) from `s`. Returns
/// the original string unchanged if no `---` opener is found — defensive
/// against a future SKILL.md without frontmatter.
fn strip_frontmatter(s: &'static str) -> &'static str {
    if !s.starts_with("---\n") && !s.starts_with("---\r\n") && s != "---" {
        return s;
    }
    let mut offset = 4;
    let bytes = s.as_bytes();
    while offset < bytes.len() {
        let rest = &s[offset..];
        if rest.starts_with("---\r\n") {
            return skip_one_newline(&s[offset + 5..]);
        }
        if rest.starts_with("---\n") {
            return skip_one_newline(&s[offset + 4..]);
        }
        if rest == "---" {
            return "";
        }
        match rest.find('\n') {
            Some(nl) => offset += nl + 1,
            None => break,
        }
    }
    s
}

/// Skip one leading `\r\n` or `\n` if present after the closing `---`.
#[inline]
fn skip_one_newline(s: &'static str) -> &'static str {
    if let Some(stripped) = s.strip_prefix("\r\n") {
        stripped
    } else if let Some(stripped) = s.strip_prefix('\n') {
        stripped
    } else {
        s
    }
}

/// Returns the complete SKILL.md content (frontmatter + body) as a static
/// string. Used by installers that write the file directly.
pub fn agent_skill_md() -> &'static str {
    SKILL_MD
}

/// YAML frontmatter written at the top of `.claude/agents/Explore.md` on a
/// fresh install. A marker block wrapping the agent-prompt body is appended
/// after it, so Claude Code sees valid frontmatter at file offset 0.
pub const EXPLORE_FRONTMATTER: &str = "---\nname: Explore\ndescription: Fast read-only search agent for locating code. Use it to find files by pattern, grep for symbols or keywords, or answer \"where is X defined / which files reference Y.\" Do NOT use it for code review, design-doc auditing, cross-file consistency checks, or open-ended analysis — it reads excerpts rather than whole files and will miss content past its read window. When calling, specify search breadth: \"quick\" for a single targeted lookup, \"medium\" for moderate exploration, or \"very thorough\" to search across multiple locations and naming conventions.\n---\n";

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn skill_md_starts_with_yaml_frontmatter() {
        // Newline-agnostic: `lines()` strips a trailing \r, so this accepts
        // both LF and CRLF checkouts.
        assert!(
            SKILL_MD.lines().next() == Some("---"),
            "SKILL.md must open with a YAML frontmatter marker"
        );
    }

    #[test]
    fn agent_prompt_strips_frontmatter() {
        let body = agent_prompt();
        assert!(
            !body.starts_with("---"),
            "stripped prompt should not start with `---`"
        );
        assert!(
            body.starts_with("## Use `sb`"),
            "prompt body should start with the H1; got: {:?}",
            &body[..body.len().min(40)]
        );
    }

    #[test]
    fn round_trip_matches_skill_md() {
        let expected = strip_frontmatter(SKILL_MD);
        assert_eq!(agent_prompt(), expected, "memoized value must equal fresh strip");
        assert!(
            SKILL_MD.contains(expected),
            "stripped body must appear verbatim inside SKILL.md"
        );
    }

    #[test]
    fn strip_handles_no_frontmatter() {
        // A string without `---` should be returned unchanged.
        let s: &str = "## Plain content\n\nNo frontmatter here.\n";
        // SAFETY: we pass a static str to the helper; this mirrors what
        // include_str! provides at compile time.
        let leaked: &'static str = Box::leak(s.to_string().into_boxed_str());
        assert_eq!(strip_frontmatter(leaked), leaked);
    }
}