use std::path::Path;
use tracing::debug;
use crate::domain::{ObjectType, WrappedBlob, WrappedNeuralCommit};
use crate::mcp::protocol::ToolCallResult;
use crate::storage::{
FileHeadStore, FileObjectStore, FileRefStore, HeadStore, ObjectStore, RefStore,
};
pub fn execute(agit_dir: &Path) -> ToolCallResult {
if !agit_dir.exists() {
return ToolCallResult::error("AGIT not initialized. Run 'agit init' first.");
}
let roadmap = match read_latest_roadmap(agit_dir) {
Ok(content) => content,
Err(e) => {
debug!("No roadmap found: {}", e);
return ToolCallResult::text(
"No roadmap set yet.\n\n\
The roadmap captures high-level project goals and direction.\n\n\
To set a roadmap, create an 'agit commit' with context that includes\n\
your project goals, or add a ROADMAP.md file to your project.",
);
},
};
ToolCallResult::text(&roadmap)
}
fn read_latest_roadmap(agit_dir: &Path) -> Result<String, String> {
let head_store = FileHeadStore::new(agit_dir);
let branch = head_store
.get()
.map_err(|e| format!("Failed to read HEAD: {}", e))?
.unwrap_or_else(|| "main".to_string());
let ref_store = FileRefStore::new(agit_dir);
let commit_hash = ref_store
.get(&branch)
.map_err(|e| format!("Failed to read ref: {}", e))?
.ok_or_else(|| "No commits yet".to_string())?;
let object_store = FileObjectStore::new(agit_dir);
let commit_data = object_store
.load(&commit_hash)
.map_err(|e| format!("Failed to load commit: {}", e))?;
let wrapped: WrappedNeuralCommit = serde_json::from_slice(&commit_data)
.map_err(|e| format!("Failed to parse commit: {}", e))?;
let roadmap_data = object_store
.load(&wrapped.data.roadmap_hash)
.map_err(|e| format!("Failed to load roadmap: {}", e))?;
let roadmap_blob: WrappedBlob = serde_json::from_slice(&roadmap_data)
.map_err(|e| format!("Failed to parse roadmap: {}", e))?;
if roadmap_blob.object_type != ObjectType::Blob {
return Err("Invalid roadmap object type".to_string());
}
Ok(roadmap_blob.data.content)
}
#[cfg(test)]
mod tests {
use super::*;
use tempfile::TempDir;
#[test]
fn test_read_roadmap_not_initialized() {
let temp = TempDir::new().unwrap();
let agit_dir = temp.path().join(".agit");
let result = execute(&agit_dir);
assert_eq!(result.is_error, Some(true));
}
#[test]
fn test_read_roadmap_no_commits() {
let temp = TempDir::new().unwrap();
let agit_dir = temp.path().join(".agit");
std::fs::create_dir_all(agit_dir.join("objects")).unwrap();
std::fs::create_dir_all(agit_dir.join("refs/heads")).unwrap();
std::fs::write(agit_dir.join("HEAD"), "main").unwrap();
std::fs::write(agit_dir.join("index"), "").unwrap();
let result = execute(&agit_dir);
assert!(result.is_error.is_none());
}
}