systemprompt_cli/commands/admin/session/
mod.rs1mod list;
7pub mod login;
8pub mod login_helpers;
9mod logout;
10pub mod show;
11mod switch;
12pub mod types;
13
14use std::path::Path;
15
16use anyhow::Result;
17use clap::Subcommand;
18use systemprompt_cloud::{CloudError, SessionStore};
19use systemprompt_identifiers::ProfileName;
20use systemprompt_logging::CliService;
21
22use crate::context::CommandContext;
23use crate::descriptor::{CommandDescriptor, DescribeCommand};
24use crate::shared::render_result;
25
26#[derive(Debug, Subcommand)]
27pub enum SessionCommands {
28 #[command(about = "Show current session and routing info", alias = "current")]
29 Show,
30
31 #[command(about = "Switch to a different profile")]
32 Switch {
33 #[arg(value_parser = crate::shared::parse_profile_name)]
34 profile_name: ProfileName,
35 },
36
37 #[command(about = "List available profiles")]
38 List,
39
40 #[command(about = "Create an admin session for CLI access")]
41 Login(login::LoginArgs),
42
43 #[command(about = "Remove a session")]
44 Logout(logout::LogoutArgs),
45}
46
47impl DescribeCommand for SessionCommands {
48 fn descriptor(&self) -> CommandDescriptor {
49 match self {
50 Self::Login(_) => CommandDescriptor::PROFILE_SECRETS_AND_PATHS.with_skip_validation(),
51 Self::Switch { .. } | Self::Show | Self::List | Self::Logout(_) => {
52 CommandDescriptor::NONE
53 },
54 }
55 }
56}
57
58pub async fn execute(cmd: SessionCommands, ctx: &CommandContext) -> Result<()> {
59 match cmd {
60 SessionCommands::Show => {
61 let result = show::execute(&ctx.cli);
62 render_result(&result, &ctx.cli);
63 Ok(())
64 },
65 SessionCommands::Switch { profile_name } => {
66 let result = switch::execute(&profile_name)?;
67 render_result(&result, &ctx.cli);
68 Ok(())
69 },
70 SessionCommands::List => {
71 let result = list::execute(&ctx.cli);
72 render_result(&result, &ctx.cli);
73 Ok(())
74 },
75 SessionCommands::Login(args) => {
76 let result = login::execute(args, &ctx.cli).await?;
77 render_result(&result, &ctx.cli);
78 Ok(())
79 },
80 SessionCommands::Logout(ref args) => {
81 let result = logout::execute(args, ctx.prompter(), &ctx.cli)?;
82 render_result(&result, &ctx.cli);
83 Ok(())
84 },
85 }
86}
87
88pub(super) fn load_or_reset_corrupt(sessions_dir: &Path) -> Result<SessionStore> {
92 match SessionStore::load(sessions_dir) {
93 Ok(store) => Ok(store.unwrap_or_else(SessionStore::new)),
94 Err(CloudError::SessionStoreCorrupted { path, .. }) => {
95 CliService::warning(&format!(
96 "Session store at {path} is corrupt; starting fresh"
97 ));
98 Ok(SessionStore::new())
99 },
100 Err(error) => Err(error.into()),
101 }
102}
103
104pub(super) fn load_for_display(sessions_dir: &Path) -> SessionStore {
105 match SessionStore::load(sessions_dir) {
106 Ok(store) => store.unwrap_or_else(SessionStore::new),
107 Err(error) => {
108 CliService::warning(&format!("Session store unreadable: {error}"));
109 SessionStore::new()
110 },
111 }
112}