Skip to main content

vs_cli/
paths.rs

1//! Filesystem layout known to the CLI.
2//!
3//! Mirrors `vs_daemon::config::Paths` deliberately rather than pulling
4//! the daemon crate as a dependency — the CLI shouldn't compile the
5//! daemon's engine + store stack just to know where its socket lives.
6
7use std::path::{Path, PathBuf};
8
9/// Daemon-side filesystem layout, from the CLI's perspective.
10#[derive(Debug, Clone)]
11pub struct Paths {
12    pub root: PathBuf,
13}
14
15impl Paths {
16    #[must_use]
17    pub fn at(root: impl Into<PathBuf>) -> Self {
18        Self { root: root.into() }
19    }
20
21    /// Conventional location: `$HOME/.vibesurfer`. Falls back to `.` if
22    /// `$HOME` is unset.
23    #[must_use]
24    pub fn home() -> Self {
25        let root = std::env::var_os("HOME").map_or_else(
26            || PathBuf::from(".vibesurfer"),
27            |h| Path::new(&h).join(".vibesurfer"),
28        );
29        Self::at(root)
30    }
31
32    #[must_use]
33    pub fn socket(&self) -> PathBuf {
34        self.root.join("daemon.sock")
35    }
36
37    #[must_use]
38    pub fn active_session(&self) -> PathBuf {
39        self.root.join("active-session")
40    }
41
42    /// Where the session id is stored for a given caller key. The
43    /// directory is created lazily on first write so a read-only
44    /// `vs status` doesn't side-effect.
45    #[must_use]
46    pub fn caller_session(&self, caller_key: &str) -> PathBuf {
47        self.root.join("callers").join(caller_key)
48    }
49}