systemprompt_cloud/paths/
cloud.rs1use std::path::{Path, PathBuf};
2
3use crate::constants::{cli_session, credentials, dir_names, tenants};
4
5use super::{ProjectContext, resolve_path};
6
7#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
8pub enum CloudPath {
9 Credentials,
10 Tenants,
11 CliSession,
12 SessionsDir,
13}
14
15impl CloudPath {
16 #[must_use]
17 pub const fn default_filename(&self) -> &'static str {
18 match self {
19 Self::Credentials => credentials::DEFAULT_FILE_NAME,
20 Self::Tenants => tenants::DEFAULT_FILE_NAME,
21 Self::CliSession => cli_session::DEFAULT_FILE_NAME,
22 Self::SessionsDir => dir_names::SESSIONS,
23 }
24 }
25
26 #[must_use]
27 pub const fn default_dirname(&self) -> &'static str {
28 match self {
29 Self::Credentials => credentials::DEFAULT_DIR_NAME,
30 Self::Tenants => tenants::DEFAULT_DIR_NAME,
31 Self::CliSession | Self::SessionsDir => cli_session::DEFAULT_DIR_NAME,
32 }
33 }
34
35 #[must_use]
36 pub const fn is_dir(&self) -> bool {
37 matches!(self, Self::SessionsDir)
38 }
39}
40
41#[derive(Debug, Clone)]
42pub struct CloudPaths {
43 base_dir: PathBuf,
44 credentials_path: Option<PathBuf>,
45 tenants_path: Option<PathBuf>,
46}
47
48impl CloudPaths {
49 #[must_use]
50 pub fn new(profile_dir: &Path) -> Self {
51 Self {
52 base_dir: profile_dir.join(credentials::DEFAULT_DIR_NAME),
53 credentials_path: None,
54 tenants_path: None,
55 }
56 }
57
58 #[must_use]
59 pub fn from_project_context(ctx: &ProjectContext) -> Self {
60 Self {
61 base_dir: ctx.systemprompt_dir(),
62 credentials_path: Some(ctx.local_credentials()),
63 tenants_path: Some(ctx.local_tenants()),
64 }
65 }
66
67 #[must_use]
68 pub fn from_config(
69 profile_dir: &Path,
70 credentials_path_str: &str,
71 tenants_path_str: &str,
72 ) -> Self {
73 let credentials_path = if credentials_path_str.is_empty() {
74 None
75 } else {
76 Some(resolve_path(profile_dir, credentials_path_str))
77 };
78
79 let tenants_path = if tenants_path_str.is_empty() {
80 None
81 } else {
82 Some(resolve_path(profile_dir, tenants_path_str))
83 };
84
85 let base_dir = credentials_path
86 .as_ref()
87 .and_then(|p| p.parent())
88 .map_or_else(
89 || {
90 profile_dir
91 .ancestors()
92 .find(|p| p.file_name().is_some_and(|n| n == ".systemprompt"))
93 .map_or_else(
94 || profile_dir.join(credentials::DEFAULT_DIR_NAME),
95 PathBuf::from,
96 )
97 },
98 PathBuf::from,
99 );
100
101 Self {
102 base_dir,
103 credentials_path,
104 tenants_path,
105 }
106 }
107
108 #[must_use]
109 pub fn resolve(&self, path: CloudPath) -> PathBuf {
110 match path {
111 CloudPath::Credentials => self
112 .credentials_path
113 .clone()
114 .unwrap_or_else(|| self.base_dir.join(credentials::DEFAULT_FILE_NAME)),
115 CloudPath::Tenants => self
116 .tenants_path
117 .clone()
118 .unwrap_or_else(|| self.base_dir.join(tenants::DEFAULT_FILE_NAME)),
119 CloudPath::CliSession => self.base_dir.join(cli_session::DEFAULT_FILE_NAME),
120 CloudPath::SessionsDir => self.base_dir.join(dir_names::SESSIONS),
121 }
122 }
123
124 #[must_use]
125 pub fn base_dir(&self) -> &Path {
126 &self.base_dir
127 }
128
129 #[must_use]
130 pub fn exists(&self, path: CloudPath) -> bool {
131 self.resolve(path).exists()
132 }
133}
134
135#[must_use]
136pub fn get_cloud_paths() -> CloudPaths {
137 let project_ctx = ProjectContext::discover();
138 CloudPaths::from_project_context(&project_ctx)
139}