use anyhow::Result;
use crate::utils::db::{Database, Project};
use dirs::data_dir;
use uuid::Uuid;
use chrono::Utc;
pub struct ProjectManager {
db: Database,
}
impl ProjectManager {
pub fn new() -> Result<Self> {
let data_path = data_dir()
.unwrap_or_else(|| std::env::current_dir().unwrap())
.join("kandil_code");
std::fs::create_dir_all(&data_path)?;
let db_path = data_path.join("kandil.db");
let db = Database::new(db_path.to_str().unwrap())?;
Ok(Self { db })
}
pub fn create_project(&self, name: &str, root_path: &str, ai_provider: &str, ai_model: &str) -> Result<Project> {
let project = Project {
id: Uuid::new_v4().to_string(),
name: name.to_string(),
root_path: root_path.to_string(),
ai_provider: ai_provider.to_string(),
ai_model: ai_model.to_string(),
last_opened: None,
memory_enabled: true,
created_at: Utc::now(),
};
self.db.create_project(&project)?;
std::fs::create_dir_all(root_path)?;
Ok(project)
}
pub fn get_project(&self, id: &str) -> Result<Option<Project>> {
self.db.get_project(id)
}
pub fn get_project_by_path(&self, path: &str) -> Result<Option<Project>> {
self.db.get_project_by_path(path)
}
pub fn list_projects(&self) -> Result<Vec<Project>> {
self.db.list_projects()
}
pub fn switch_project(&self, id: &str) -> Result<Project> {
self.db.update_project_last_opened(id)?;
if let Some(project) = self.db.get_project(id)? {
Ok(project)
} else {
Err(anyhow::anyhow!("Project with id {} not found", id))
}
}
pub fn ensure_active_project(&self, project_path: Option<&str>) -> Result<Project> {
if let Some(path) = project_path {
if let Some(project) = self.db.get_project_by_path(path)? {
self.db.update_project_last_opened(&project.id)?;
return Ok(project);
}
}
let current_dir_str = std::env::current_dir()?.to_string_lossy().to_string();
let path = project_path.unwrap_or(¤t_dir_str);
self.create_project(
&format!("Project_{}", Utc::now().format("%Y%m%d_%H%M%S")),
path,
"ollama", "llama3:70b" )
}
pub fn save_project_memory(&self, project_id: &str, session_id: &str, role: &str, content: &str, tokens_used: Option<i64>) -> Result<()> {
let memory = crate::utils::db::Memory {
id: 0, project_id: project_id.to_string(),
session_id: session_id.to_string(),
role: role.to_string(),
content: content.to_string(),
timestamp: Utc::now(),
tokens_used,
};
self.db.save_memory(&memory)?;
let data = serde_json::to_string(&memory)?;
self.db.add_to_sync_queue("INSERT", "memory", &memory.id.to_string(), &data)?;
Ok(())
}
pub fn get_project_memory(&self, project_id: &str, limit: Option<i32>) -> Result<Vec<crate::utils::db::Memory>> {
self.db.get_memory_for_project(project_id, limit)
}
}