systemprompt_cli/commands/cloud/tenant/
select.rs1use anyhow::{Result, anyhow, bail};
7use systemprompt_cloud::{
8 CloudCredentials, CloudPath, CredentialsBootstrap, StoredTenant, TenantType, get_cloud_paths,
9};
10use systemprompt_config::ProfileBootstrap;
11use systemprompt_identifiers::TenantId;
12
13use crate::interactive::Prompter;
14
15pub fn get_credentials() -> Result<CloudCredentials> {
16 if CredentialsBootstrap::is_initialized() {
17 return CredentialsBootstrap::require()
18 .map_err(|e| {
19 anyhow!(
20 "Credentials required. Run 'systemprompt cloud login': {}",
21 e
22 )
23 })?
24 .clone()
25 .pipe(Ok);
26 }
27
28 let cloud_paths = get_cloud_paths();
29 let creds_path = cloud_paths.resolve(CloudPath::Credentials);
30
31 if creds_path.exists() {
32 CloudCredentials::load_from_path(&creds_path).map_err(Into::into)
33 } else {
34 bail!("Not logged in. Run 'systemprompt cloud login' first.")
35 }
36}
37
38pub fn select_tenant<'a>(
39 prompter: &dyn Prompter,
40 tenants: &'a [StoredTenant],
41) -> Result<&'a StoredTenant> {
42 let options: Vec<String> = tenants
43 .iter()
44 .map(|t| {
45 let type_str = match t.tenant_type {
46 TenantType::Local => "local",
47 TenantType::Cloud => "cloud",
48 };
49 format!("{} ({})", t.name, type_str)
50 })
51 .collect();
52
53 let selection = prompter.select("Select tenant", &options)?;
54
55 Ok(&tenants[selection])
56}
57
58pub fn resolve_tenant_id(tenant: Option<String>) -> Result<TenantId> {
59 if let Some(id) = tenant {
60 return Ok(TenantId::new(id));
61 }
62
63 ProfileBootstrap::get()
64 .ok()
65 .and_then(|p| p.cloud.as_ref()?.tenant_id.as_ref().map(TenantId::new))
66 .ok_or_else(|| {
67 anyhow!("No tenant specified. Use --tenant or configure a tenant in your profile.")
68 })
69}
70
71trait Pipe: Sized {
72 fn pipe<F, R>(self, f: F) -> R
73 where
74 F: FnOnce(Self) -> R,
75 {
76 f(self)
77 }
78}
79
80impl<T> Pipe for T {}