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 #[arg(short = 'c', long = "config", value_name = "FILE")]
13 pub config: Option<PathBuf>,
14
15 #[arg(long = "hyper-dir", value_name = "DIR")]
17 pub hyper_dir: Option<PathBuf>,
18
19 #[arg(long = "all")]
21 pub all: bool,
22
23 #[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}