vs_daemon/config.rs
1//! Filesystem layout: where the daemon keeps state on disk.
2//!
3//! ```text
4//! ~/.vibesurfer/
5//! daemon.sock # the IPC socket
6//! active-session # one-line session id
7//! state.db # SQLite, WAL mode
8//! key # AES-256 fallback if OS keyring unavailable
9//! log/ # rotating tracing output (M5+)
10//! captures/ # screenshot output paths (M5+)
11//! ```
12
13use std::path::{Path, PathBuf};
14
15/// Daemon-side filesystem layout.
16#[derive(Debug, Clone)]
17pub struct Paths {
18 /// Root directory; usually `$HOME/.vibesurfer`.
19 pub root: PathBuf,
20}
21
22impl Paths {
23 /// Construct from a custom root (tests use a temp dir).
24 #[must_use]
25 pub fn at(root: impl Into<PathBuf>) -> Self {
26 Self { root: root.into() }
27 }
28
29 /// Conventional location: `$HOME/.vibesurfer`. Falls back to the
30 /// current directory if `$HOME` is unset (rare; CI containers).
31 #[must_use]
32 pub fn home() -> Self {
33 let root = std::env::var_os("HOME").map_or_else(
34 || PathBuf::from(".vibesurfer"),
35 |h| Path::new(&h).join(".vibesurfer"),
36 );
37 Self::at(root)
38 }
39
40 #[must_use]
41 pub fn socket(&self) -> PathBuf {
42 self.root.join("daemon.sock")
43 }
44
45 #[must_use]
46 pub fn db(&self) -> PathBuf {
47 self.root.join("state.db")
48 }
49
50 #[must_use]
51 pub fn active_session(&self) -> PathBuf {
52 self.root.join("active-session")
53 }
54
55 #[must_use]
56 pub fn key_file(&self) -> PathBuf {
57 self.root.join("key")
58 }
59
60 /// Where the daemon writes screenshot PNGs from `vs_capture`.
61 /// Defaults to `<root>/captures`. Overridable per-process via the
62 /// `VS_CAPTURES_DIR` environment variable.
63 #[must_use]
64 pub fn captures(&self) -> PathBuf {
65 if let Some(p) = std::env::var_os("VS_CAPTURES_DIR") {
66 return PathBuf::from(p);
67 }
68 self.root.join("captures")
69 }
70
71 /// Ensure the root directory exists.
72 pub fn ensure_root(&self) -> std::io::Result<()> {
73 std::fs::create_dir_all(&self.root)
74 }
75}