Skip to main content

vtcode_core/pods/
store.rs

1use super::catalog::PodCatalog;
2use super::state::PodsState;
3use anyhow::{Context, Result};
4use std::path::PathBuf;
5use vtcode_commons::VtCodePaths;
6use vtcode_commons::fs::{read_private_json_file, write_private_json_file};
7
8/// Persisted pod storage rooted in the user state directory's `pods` path.
9#[derive(Debug, Clone)]
10pub struct PodsStore {
11    base_dir: PathBuf,
12}
13
14impl PodsStore {
15    /// Create a store rooted at the given directory.
16    pub fn new(base_dir: impl Into<PathBuf>) -> Self {
17        Self { base_dir: base_dir.into() }
18    }
19
20    /// Create a store using the default user-state `pods` directory.
21    pub fn default_store() -> Result<Self> {
22        let paths = VtCodePaths::resolve().context("failed to resolve VT Code paths")?;
23        Ok(Self::new(paths.state_path("pods")?))
24    }
25
26    /// Return the path to the `state.json` file.
27    pub fn state_path(&self) -> PathBuf {
28        self.base_dir.join("state.json")
29    }
30
31    /// Return the path to the `catalog.json` file.
32    pub fn catalog_path(&self) -> PathBuf {
33        self.base_dir.join("catalog.json")
34    }
35
36    /// Create the base directory and seed default files if they do not exist.
37    pub async fn ensure_initialized(&self) -> Result<()> {
38        ensure_user_dir(&self.base_dir)?;
39
40        if !tokio::fs::try_exists(&self.catalog_path()).await.unwrap_or(false) {
41            self.save_catalog(&PodCatalog::embedded_default()).await?;
42        }
43
44        if !tokio::fs::try_exists(&self.state_path()).await.unwrap_or(false) {
45            self.save_state(&PodsState::default()).await?;
46        }
47
48        Ok(())
49    }
50
51    /// Load the persisted pod state from disk.
52    pub async fn load_state(&self) -> Result<PodsState> {
53        self.ensure_initialized().await?;
54        read_private_json_file(&self.state_path())
55            .await
56            .with_context(|| format!("failed to read pod state at {}", self.state_path().display()))
57    }
58
59    /// Persist the pod state to disk.
60    pub async fn save_state(&self, state: &PodsState) -> Result<()> {
61        ensure_user_dir(&self.base_dir)?;
62        write_private_json_file(&self.state_path(), state)
63            .await
64            .with_context(|| format!("failed to write pod state at {}", self.state_path().display()))
65    }
66
67    /// Load the deployment catalog from disk.
68    pub async fn load_catalog(&self) -> Result<PodCatalog> {
69        self.ensure_initialized().await?;
70        read_private_json_file(&self.catalog_path())
71            .await
72            .with_context(|| format!("failed to read pod catalog at {}", self.catalog_path().display()))
73    }
74
75    pub async fn save_catalog(&self, catalog: &PodCatalog) -> Result<()> {
76        ensure_user_dir(&self.base_dir)?;
77        write_private_json_file(&self.catalog_path(), catalog)
78            .await
79            .with_context(|| format!("failed to write pod catalog at {}", self.catalog_path().display()))
80    }
81}
82
83fn ensure_user_dir(path: &std::path::Path) -> Result<()> {
84    VtCodePaths::ensure_user_dir(path).context("failed to create private pod state directory")?;
85    Ok(())
86}