use std::path::PathBuf;
use clap::{Parser, ValueEnum};
use determinishtic::Determinishtic;
use agent_client_protocol_tokio::AcpAgent;
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use tracing_subscriber::EnvFilter;
use walkdir::WalkDir;
#[derive(Parser, Debug)]
#[command(name = "summarize_docs")]
#[command(about = "Summarize all markdown files in a directory using an LLM")]
struct Args {
#[arg(short, long, value_enum, default_value = "claude-code")]
agent: Agent,
#[arg(default_value = ".")]
directory: PathBuf,
}
#[derive(Debug, Clone, Copy, ValueEnum)]
#[value(rename_all = "kebab-case")]
enum Agent {
ClaudeCode,
Gemini,
Codex,
}
impl Agent {
fn to_acp_agent(self) -> AcpAgent {
match self {
Agent::ClaudeCode => AcpAgent::zed_claude_code(),
Agent::Gemini => AcpAgent::google_gemini(),
Agent::Codex => AcpAgent::zed_codex(),
}
}
}
#[derive(Debug, Serialize, Deserialize, JsonSchema)]
struct FileSummary {
summary: String,
topics: Vec<String>,
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
tracing_subscriber::fmt()
.with_env_filter(EnvFilter::from_default_env())
.with_writer(std::io::stderr)
.init();
let args = Args::parse();
println!("Agent: {:?}", args.agent);
println!("Directory: {}", args.directory.display());
let md_files: Vec<PathBuf> = WalkDir::new(&args.directory)
.into_iter()
.filter_map(|e| e.ok())
.filter(|e| e.path().extension().is_some_and(|ext| ext == "md"))
.map(|e| e.path().to_path_buf())
.collect();
println!("\nFound {} markdown files", md_files.len());
if md_files.is_empty() {
println!("No markdown files found.");
return Ok(());
}
let agent = args.agent.to_acp_agent();
let d = Determinishtic::new(agent).await?;
let mut summaries = Vec::new();
for path in &md_files {
println!("\nSummarizing: {}", path.display());
let contents = std::fs::read_to_string(path)?;
let summary: FileSummary = d
.think()
.text("Summarize this markdown file in one sentence and list the key topics:")
.text("\n\n")
.display(&contents)
.await?;
println!(" Summary: {}", summary.summary);
println!(" Topics: {}", summary.topics.join(", "));
summaries.push((path.clone(), summary));
}
println!("\n=== Summary Report ===\n");
for (path, summary) in &summaries {
println!("{}", path.display());
println!(" {}", summary.summary);
println!(" Topics: {}", summary.topics.join(", "));
println!();
}
Ok(())
}