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}