saorsa_agent/session/
path.rs1use crate::SaorsaAgentError;
4use crate::session::SessionId;
5use std::path::{Path, PathBuf};
6
7pub fn sessions_dir() -> Result<PathBuf, SaorsaAgentError> {
13 let base = if let Ok(xdg_data) = std::env::var("XDG_DATA_HOME") {
14 PathBuf::from(xdg_data).join("saorsa")
15 } else if let Some(home) = std::env::var_os("HOME").or_else(|| std::env::var_os("USERPROFILE"))
16 {
17 PathBuf::from(home).join(".saorsa")
18 } else {
19 return Err(SaorsaAgentError::Session(
20 "Cannot determine home directory".to_string(),
21 ));
22 };
23
24 Ok(base.join("sessions"))
25}
26
27pub fn session_dir(session_id: &SessionId) -> Result<PathBuf, SaorsaAgentError> {
29 Ok(sessions_dir()?.join(session_id.as_str()))
30}
31
32pub fn manifest_path(session_id: &SessionId) -> Result<PathBuf, SaorsaAgentError> {
34 Ok(session_dir(session_id)?.join("manifest.json"))
35}
36
37pub fn tree_path(session_id: &SessionId) -> Result<PathBuf, SaorsaAgentError> {
39 Ok(session_dir(session_id)?.join("tree.json"))
40}
41
42pub fn messages_dir(session_id: &SessionId) -> Result<PathBuf, SaorsaAgentError> {
44 Ok(session_dir(session_id)?.join("messages"))
45}
46
47pub fn message_path(
52 session_id: &SessionId,
53 index: usize,
54 message_type: &str,
55) -> Result<PathBuf, SaorsaAgentError> {
56 Ok(messages_dir(session_id)?.join(format!("{}-{}.json", index, message_type)))
57}
58
59pub fn ensure_dir(path: &Path) -> Result<(), SaorsaAgentError> {
61 std::fs::create_dir_all(path).map_err(|e| {
62 SaorsaAgentError::Session(format!("Failed to create directory {:?}: {}", path, e))
63 })?;
64 Ok(())
65}
66
67#[cfg(test)]
68#[allow(clippy::unwrap_used)]
69mod tests {
70 use super::*;
71
72 #[test]
73 fn test_sessions_dir_uses_xdg() {
74 unsafe {
75 std::env::set_var("XDG_DATA_HOME", "/tmp/xdg_test");
76 }
77 let path = sessions_dir().unwrap();
78 assert!(path.to_string_lossy().contains("xdg_test"));
79 assert!(path.ends_with("saorsa/sessions"));
80 unsafe {
81 std::env::remove_var("XDG_DATA_HOME");
82 }
83 }
84
85 #[test]
86 fn test_sessions_dir_falls_back_to_home() {
87 unsafe {
88 std::env::remove_var("XDG_DATA_HOME");
89 }
90 let path = sessions_dir().unwrap();
91 assert!(path.to_string_lossy().contains(".saorsa"));
92 assert!(path.ends_with(".saorsa/sessions"));
93 }
94
95 #[test]
96 fn test_session_dir_includes_id() {
97 let id = SessionId::new();
98 let path = session_dir(&id).unwrap();
99 assert!(path.to_string_lossy().contains(&id.as_str()));
100 }
101
102 #[test]
103 fn test_manifest_path() {
104 let id = SessionId::new();
105 let p = manifest_path(&id).unwrap();
106 assert!(p.ends_with("manifest.json"));
107 assert!(p.to_string_lossy().contains(&id.as_str()));
108 }
109
110 #[test]
111 fn test_tree_path() {
112 let id = SessionId::new();
113 let p = tree_path(&id).unwrap();
114 assert!(p.ends_with("tree.json"));
115 }
116
117 #[test]
118 fn test_messages_dir() {
119 let id = SessionId::new();
120 let p = messages_dir(&id).unwrap();
121 assert!(p.ends_with("messages"));
122 }
123
124 #[test]
125 fn test_message_path_format() {
126 let id = SessionId::new();
127 let p = message_path(&id, 0, "user").unwrap();
128 assert!(p.ends_with(Path::new("messages").join("0-user.json")));
129
130 let p2 = message_path(&id, 42, "assistant").unwrap();
131 assert!(p2.ends_with(Path::new("messages").join("42-assistant.json")));
132 }
133}