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