| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111 |
- //! Markdown output writer.
- use std::path::PathBuf;
- use crate::models::{CodebaseSummary, FileSummary, Symbol, SymbolKind};
- pub const AGENTS_INSTRUCTIONS: &str = r#"# Codebase Navigation Protocol
- You have access to codebase_summary.md. This file contains a compressed map of the codebase, including exported signatures and their associated documentation comments.
- Protocol:
- Consult Summary First: Use the doc-strings in codebase_summary.md to understand the intent and usage of functions without reading the full implementation.
- Identify Targets: Identify the specific files containing the logic you need.
- Deep Dive: Open the identified files to study the internal logic/edge cases before proposing a solution.
- After making changes: run the codebase_summarizer tool to update the codebase_summary.md again if you changed the directory structure, added or removed code files, changed function signatures, changed comments
- or if you see otherwise necessary
- "#;
- /// Writer for generating markdown output.
- pub struct MarkdownWriter;
- impl MarkdownWriter {
- pub fn new() -> Self {
- Self
- }
- /// Write the codebase summary to a markdown file.
- pub fn write_summary(&self, summary: &CodebaseSummary, output_path: &PathBuf) -> std::io::Result<()> {
- let mut content = String::new();
-
- content.push_str("# Codebase Architecture Map\n\n");
-
- // Sort files by path for consistent output
- let mut files = summary.files.clone();
- files.sort_by(|a, b| a.path.cmp(&b.path));
-
- for file_summary in files {
- self.write_file_summary(&mut content, &file_summary);
- }
-
- std::fs::write(output_path, content)?;
- Ok(())
- }
- fn write_file_summary(&self, content: &mut String, file_summary: &FileSummary) {
- // Only write files that have symbols
- if file_summary.symbols.is_empty() {
- return;
- }
-
- let relative_path = self.get_relative_path(&file_summary.path);
- content.push_str(&format!("## File: {}\n", relative_path));
- content.push('\n');
-
- for symbol in &file_summary.symbols {
- self.write_symbol(content, symbol);
- }
-
- content.push('\n');
- }
- fn write_symbol(&self, content: &mut String, symbol: &Symbol) {
- let kind_str = match symbol.kind {
- SymbolKind::Function => "func",
- SymbolKind::Method => "method",
- SymbolKind::Struct => "struct",
- SymbolKind::Enum => "enum",
- SymbolKind::Class => "class",
- SymbolKind::Interface => "interface",
- SymbolKind::Trait => "trait",
- SymbolKind::TypeAlias => "type",
- SymbolKind::Const => "const",
- SymbolKind::Static => "static",
- SymbolKind::Field => "field",
- SymbolKind::Module => "module",
- SymbolKind::Import => "import",
- };
-
- content.push_str(&format!("### {} {}\n", kind_str, symbol.name));
-
- if let Some(doc) = &symbol.doc {
- content.push_str(&format!("**Doc:** \n{}\n", doc));
- } else {
- content.push_str("**Doc:** \n");
- }
-
- content.push('\n');
- }
- fn get_relative_path(&self, path: &PathBuf) -> String {
- path.to_string_lossy().to_string()
- }
- /// Write the AGENTS.md file if it doesn't exist.
- pub fn write_agents_md(&self, output_dir: &PathBuf) -> std::io::Result<bool> {
- let agents_path = output_dir.join("AGENTS.md");
-
- if agents_path.exists() {
- return Ok(false);
- }
-
- std::fs::write(&agents_path, AGENTS_INSTRUCTIONS)?;
- Ok(true)
- }
- }
- impl Default for MarkdownWriter {
- fn default() -> Self {
- Self::new()
- }
- }
|