devist 0.7.0

Project bootstrap CLI for AI-assisted development. Spin up new projects from templates, manage backends, and keep your codebase comprehensible.
use anyhow::{Context, Result};
use serde::{Deserialize, Serialize};
use std::fs;

use crate::paths;

/// Tracks which project is currently running its backend.
/// Stored at ~/.devist/state.toml
#[derive(Debug, Default, Serialize, Deserialize)]
pub struct State {
    /// Name of the currently active (backend running) project, if any.
    pub active_project: Option<String>,
}

impl State {
    fn file_path() -> Result<std::path::PathBuf> {
        Ok(paths::devist_root()?.join("state.toml"))
    }

    pub fn load() -> Result<Self> {
        let path = Self::file_path()?;
        if !path.exists() {
            return Ok(State::default());
        }
        let text = fs::read_to_string(&path)
            .with_context(|| format!("Failed to read {}", path.display()))?;
        let state: State =
            toml::from_str(&text).with_context(|| format!("Failed to parse {}", path.display()))?;
        Ok(state)
    }

    pub fn save(&self) -> Result<()> {
        let path = Self::file_path()?;
        if let Some(parent) = path.parent() {
            fs::create_dir_all(parent)?;
        }
        let text = toml::to_string_pretty(self)?;
        fs::write(&path, text)?;
        Ok(())
    }

    pub fn set_active(&mut self, name: Option<String>) {
        self.active_project = name;
    }
}