systemprompt-cli 0.2.0

systemprompt.io OS - CLI for agent orchestration, AI operations, and system management
Documentation
use anyhow::Result;
use clap::Args;
use std::sync::Arc;
use systemprompt_runtime::AppContext;
use systemprompt_scheduler::ScheduledJob;

use super::types::{JobHistoryEntry, JobHistoryOutput};
use crate::shared::{CommandResult, RenderingHints};

#[derive(Debug, Args)]
pub struct HistoryArgs {
    #[arg(long, help = "Filter by job name")]
    pub job: Option<String>,

    #[arg(
        long,
        short = 'n',
        default_value = "20",
        help = "Number of entries to show"
    )]
    pub limit: i64,

    #[arg(long, help = "Filter by status (success, failed, running)")]
    pub status: Option<String>,
}

pub async fn execute(args: HistoryArgs) -> Result<CommandResult<JobHistoryOutput>> {
    let ctx = Arc::new(AppContext::new().await?);
    let pool = ctx.db_pool().pool_arc()?;

    let entries: Vec<JobHistoryEntry> = if let Some(ref job_name) = args.job {
        let job = sqlx::query_as!(
            ScheduledJob,
            r#"
            SELECT id, job_name, schedule, enabled, last_run, next_run,
                   last_status, last_error, run_count, created_at, updated_at
            FROM scheduled_jobs
            WHERE job_name = $1
            "#,
            job_name
        )
        .fetch_optional(&*pool)
        .await?;

        if let Some(j) = job {
            if let Some(last_run) = j.last_run {
                vec![JobHistoryEntry {
                    job_name: j.job_name,
                    status: j.last_status.unwrap_or_else(|| "unknown".to_string()),
                    run_at: last_run,
                    error: j.last_error,
                }]
            } else {
                vec![]
            }
        } else {
            vec![]
        }
    } else {
        let jobs = sqlx::query_as!(
            ScheduledJob,
            r#"
            SELECT id, job_name, schedule, enabled, last_run, next_run,
                   last_status, last_error, run_count, created_at, updated_at
            FROM scheduled_jobs
            WHERE last_run IS NOT NULL
            ORDER BY last_run DESC
            LIMIT $1
            "#,
            args.limit
        )
        .fetch_all(&*pool)
        .await?;

        jobs.into_iter()
            .filter_map(|j| {
                j.last_run.map(|last_run| JobHistoryEntry {
                    job_name: j.job_name,
                    status: j.last_status.unwrap_or_else(|| "unknown".to_string()),
                    run_at: last_run,
                    error: j.last_error,
                })
            })
            .filter(|e| {
                args.status
                    .as_ref()
                    .is_none_or(|s| e.status.eq_ignore_ascii_case(s))
            })
            .collect()
    };

    let total = entries.len();
    let output = JobHistoryOutput { entries, total };

    Ok(CommandResult::table(output)
        .with_title("Job Execution History")
        .with_hints(RenderingHints {
            columns: Some(vec![
                "job_name".to_string(),
                "status".to_string(),
                "run_at".to_string(),
                "error".to_string(),
            ]),
            ..Default::default()
        }))
}