systemprompt-cli 0.2.1

Unified CLI for systemprompt.io AI governance: agent orchestration, MCP governance, analytics, profiles, cloud deploy, and self-hosted operations.
Documentation
use anyhow::{Result, anyhow};
use clap::Args;
use systemprompt_database::DbPool;
use systemprompt_runtime::AppContext;
use systemprompt_users::{UserAdminService, UserService};

use super::types::{SessionSummary, UserActivityOutput, UserDetailOutput};
use crate::CliConfig;
use crate::shared::CommandResult;

#[derive(Debug, Args)]
pub struct ShowArgs {
    pub identifier: String,

    #[arg(long)]
    pub sessions: bool,

    #[arg(long)]
    pub activity: bool,
}

pub async fn execute(
    args: ShowArgs,
    config: &CliConfig,
) -> Result<CommandResult<UserDetailOutput>> {
    let ctx = AppContext::new().await?;
    execute_with_pool(args, ctx.db_pool(), config).await
}

pub async fn execute_with_pool(
    args: ShowArgs,
    pool: &DbPool,
    _config: &CliConfig,
) -> Result<CommandResult<UserDetailOutput>> {
    let user_service = UserService::new(pool)?;
    let admin_service = UserAdminService::new(user_service.clone());

    let user = admin_service.find_user(&args.identifier).await?;

    let Some(user) = user else {
        return Err(anyhow!("User not found: {}", args.identifier));
    };

    let sessions = if args.sessions {
        let user_sessions = user_service.list_sessions(&user.id).await?;
        Some(
            user_sessions
                .into_iter()
                .map(|s| SessionSummary {
                    session_id: s.session_id,
                    ip_address: s.ip_address,
                    user_agent: s.user_agent,
                    device_type: s.device_type,
                    started_at: s.started_at,
                    last_activity_at: s.last_activity_at,
                    is_active: s.ended_at.is_none(),
                })
                .collect(),
        )
    } else {
        None
    };

    let activity = if args.activity {
        let user_activity = user_service.get_activity(&user.id).await?;
        Some(UserActivityOutput {
            user_id: user_activity.user_id,
            last_active: user_activity.last_active,
            session_count: user_activity.session_count,
            task_count: user_activity.task_count,
            message_count: user_activity.message_count,
        })
    } else {
        None
    };

    let output = UserDetailOutput {
        id: user.id.clone(),
        name: user.name.clone(),
        email: user.email.clone(),
        full_name: user.full_name.clone(),
        display_name: user.display_name.clone(),
        status: user.status.clone(),
        email_verified: user.email_verified,
        roles: user.roles.clone(),
        is_bot: user.is_bot,
        is_scanner: user.is_scanner,
        created_at: user.created_at,
        updated_at: user.updated_at,
        sessions,
        activity,
    };

    Ok(CommandResult::card(output).with_title(format!("User: {}", user.name)))
}