Skip to main content

actr_cli/commands/
ps.rs

1use crate::commands::runtime_state::{RuntimeStateStore, RuntimeStatus, resolve_hyper_dir};
2use crate::core::{Command, CommandContext, CommandResult, ComponentType};
3use anyhow::Result;
4use async_trait::async_trait;
5use clap::Args;
6use comfy_table::{Attribute, Cell, Table};
7use std::path::PathBuf;
8
9#[derive(Args, Debug)]
10pub struct PsCommand {
11    /// Runtime configuration file
12    #[arg(short = 'c', long = "config", value_name = "FILE")]
13    pub config: Option<PathBuf>,
14
15    /// Hyper data directory
16    #[arg(long = "hyper-dir", value_name = "DIR")]
17    pub hyper_dir: Option<PathBuf>,
18
19    /// Show running, exited, and stale instances
20    #[arg(long = "all")]
21    pub all: bool,
22
23    /// Show log file path column
24    #[arg(long = "log")]
25    pub log: bool,
26}
27
28#[async_trait]
29impl Command for PsCommand {
30    async fn execute(&self, _ctx: &CommandContext) -> Result<CommandResult> {
31        let hyper_dir = resolve_hyper_dir(self.config.as_deref(), self.hyper_dir.as_deref())?;
32        let store = RuntimeStateStore::new(hyper_dir);
33        let mut entries = store.list_records().await?;
34
35        if !self.all {
36            entries.retain(|entry| entry.status == RuntimeStatus::Running);
37        }
38
39        if entries.is_empty() {
40            println!("No detached runtimes found.");
41            return Ok(CommandResult::Success(String::new()));
42        }
43
44        let mut table = Table::new();
45        let mut header = vec![
46            Cell::new("WID").add_attribute(Attribute::Bold),
47            Cell::new("ACTR_ID").add_attribute(Attribute::Bold),
48            Cell::new("PID").add_attribute(Attribute::Bold),
49            Cell::new("STATUS").add_attribute(Attribute::Bold),
50            Cell::new("STARTED_AT").add_attribute(Attribute::Bold),
51        ];
52        if self.log {
53            header.push(Cell::new("LOG").add_attribute(Attribute::Bold));
54        }
55        table.set_header(header);
56
57        for entry in entries {
58            let started_at = entry.started_at_display();
59            let log_path = entry.record.log_path.display().to_string();
60            let mut row = vec![
61                Cell::new(entry.wid_short()),
62                Cell::new(&entry.record.actr_id),
63                Cell::new(entry.record.pid),
64                Cell::new(entry.status.as_str()),
65                Cell::new(started_at),
66            ];
67            if self.log {
68                row.push(Cell::new(log_path));
69            }
70            table.add_row(row);
71        }
72
73        println!("{table}");
74        Ok(CommandResult::Success(String::new()))
75    }
76
77    fn required_components(&self) -> Vec<ComponentType> {
78        vec![]
79    }
80
81    fn name(&self) -> &str {
82        "ps"
83    }
84
85    fn description(&self) -> &str {
86        "List detached runtime instances"
87    }
88}