intent_engine/
project.rs

1use crate::db::{create_pool, run_migrations};
2use crate::error::{IntentError, Result};
3use sqlx::SqlitePool;
4use std::path::PathBuf;
5
6const INTENT_DIR: &str = ".intent-engine";
7const DB_FILE: &str = "project.db";
8
9pub struct ProjectContext {
10    pub root: PathBuf,
11    pub db_path: PathBuf,
12    pub pool: SqlitePool,
13}
14
15impl ProjectContext {
16    /// Find the project root by searching upwards for .intent-engine directory
17    pub fn find_project_root() -> Option<PathBuf> {
18        let mut current = std::env::current_dir().ok()?;
19
20        loop {
21            let intent_dir = current.join(INTENT_DIR);
22            if intent_dir.exists() && intent_dir.is_dir() {
23                return Some(current);
24            }
25
26            if !current.pop() {
27                break;
28            }
29        }
30
31        None
32    }
33
34    /// Initialize a new Intent-Engine project in the current directory
35    pub async fn initialize_project() -> Result<Self> {
36        let root = std::env::current_dir()?;
37        let intent_dir = root.join(INTENT_DIR);
38        let db_path = intent_dir.join(DB_FILE);
39
40        // Create .intent-engine directory if it doesn't exist
41        if !intent_dir.exists() {
42            std::fs::create_dir_all(&intent_dir)?;
43        }
44
45        // Create database connection
46        let pool = create_pool(&db_path).await?;
47
48        // Run migrations
49        run_migrations(&pool).await?;
50
51        Ok(ProjectContext {
52            root,
53            db_path,
54            pool,
55        })
56    }
57
58    /// Load an existing project context
59    pub async fn load() -> Result<Self> {
60        let root = Self::find_project_root().ok_or(IntentError::NotAProject)?;
61        let db_path = root.join(INTENT_DIR).join(DB_FILE);
62
63        let pool = create_pool(&db_path).await?;
64
65        Ok(ProjectContext {
66            root,
67            db_path,
68            pool,
69        })
70    }
71
72    /// Load project context, initializing if necessary (for write commands)
73    pub async fn load_or_init() -> Result<Self> {
74        match Self::load().await {
75            Ok(ctx) => Ok(ctx),
76            Err(IntentError::NotAProject) => Self::initialize_project().await,
77            Err(e) => Err(e),
78        }
79    }
80}