actor trait improvements and ui implementation
This commit is contained in:
117
core/supervisor/cmd/README.md
Normal file
117
core/supervisor/cmd/README.md
Normal file
@@ -0,0 +1,117 @@
|
||||
# Supervisor CLI
|
||||
|
||||
Interactive command-line interface for the Hero Supervisor that allows you to dispatch jobs to actors and manage the job lifecycle.
|
||||
|
||||
## Features
|
||||
|
||||
- **Interactive Menu**: Easy-to-use menu system for all supervisor operations
|
||||
- **Job Management**: Create, run, monitor, and manage jobs
|
||||
- **OSIS Actor Integration**: Dispatch Rhai scripts to the OSIS actor
|
||||
- **Real-time Results**: Get immediate feedback from job execution
|
||||
- **Colorized Output**: Clear visual feedback with colored status indicators
|
||||
|
||||
## Usage
|
||||
|
||||
### 1. Build the OSIS Actor
|
||||
|
||||
First, ensure the OSIS actor is built:
|
||||
|
||||
```bash
|
||||
cd /Users/timurgordon/code/git.ourworld.tf/herocode/actor_osis
|
||||
cargo build
|
||||
```
|
||||
|
||||
### 2. Configure the Supervisor
|
||||
|
||||
Create or use the example configuration file at `examples/cli_config.toml`:
|
||||
|
||||
```toml
|
||||
[global]
|
||||
redis_url = "redis://127.0.0.1/"
|
||||
|
||||
[actors]
|
||||
osis_actor = "/Users/timurgordon/code/git.ourworld.tf/herocode/actor_osis/target/debug/actor_osis"
|
||||
```
|
||||
|
||||
### 3. Run the CLI
|
||||
|
||||
```bash
|
||||
cd /Users/timurgordon/code/git.ourworld.tf/herocode/baobab/core/supervisor
|
||||
cargo run --bin supervisor-cli -- --config examples/cli_config.toml
|
||||
```
|
||||
|
||||
Or with verbose logging:
|
||||
|
||||
```bash
|
||||
cargo run --bin supervisor-cli -- --config examples/cli_config.toml --verbose
|
||||
```
|
||||
|
||||
## Available Commands
|
||||
|
||||
1. **list_jobs** - List all jobs in the system
|
||||
2. **run_job** - Create and run a new job interactively
|
||||
3. **get_job_status** - Get status of a specific job
|
||||
4. **get_job_output** - Get output of a completed job
|
||||
5. **get_job_logs** - Get logs for a specific job
|
||||
6. **stop_job** - Stop a running job
|
||||
7. **delete_job** - Delete a specific job
|
||||
8. **clear_all_jobs** - Clear all jobs from the system
|
||||
9. **quit** - Exit the CLI
|
||||
|
||||
## Example Workflow
|
||||
|
||||
1. Start the CLI with your configuration
|
||||
2. Select option `2` (run_job)
|
||||
3. Enter job details:
|
||||
- **Caller**: Your name or identifier
|
||||
- **Context**: Description of what the job does
|
||||
- **Script**: Rhai script to execute (end with empty line)
|
||||
4. The job is automatically dispatched to the OSIS actor
|
||||
5. View the real-time result
|
||||
|
||||
### Example Rhai Script
|
||||
|
||||
```rhai
|
||||
// Simple calculation
|
||||
let result = 10 + 20 * 3;
|
||||
print("Calculation result: " + result);
|
||||
result
|
||||
```
|
||||
|
||||
```rhai
|
||||
// Working with strings
|
||||
let message = "Hello from OSIS Actor!";
|
||||
print(message);
|
||||
message.to_upper()
|
||||
```
|
||||
|
||||
## Job Status Colors
|
||||
|
||||
- **Created** - Cyan
|
||||
- **Dispatched** - Blue
|
||||
- **Started** - Yellow
|
||||
- **Finished** - Green
|
||||
- **Error** - Red
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Redis server running on localhost:6379 (or configured URL)
|
||||
- OSIS actor binary built and accessible
|
||||
- Proper permissions to start/stop processes via Zinit
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Actor Not Starting
|
||||
- Verify the OSIS actor binary path in the TOML config
|
||||
- Check that the binary exists and is executable
|
||||
- Ensure Redis is running and accessible
|
||||
|
||||
### Connection Issues
|
||||
- Verify Redis URL in configuration
|
||||
- Check network connectivity to Redis server
|
||||
- Ensure no firewall blocking connections
|
||||
|
||||
### Job Execution Failures
|
||||
- Check job logs using `get_job_logs` command
|
||||
- Verify Rhai script syntax
|
||||
- Check actor logs for detailed error information
|
178
core/supervisor/cmd/TUI_README.md
Normal file
178
core/supervisor/cmd/TUI_README.md
Normal file
@@ -0,0 +1,178 @@
|
||||
# Supervisor Terminal UI (TUI)
|
||||
|
||||
A modern, interactive Terminal User Interface for the Hero Supervisor that provides intuitive job management with real-time updates and visual navigation.
|
||||
|
||||
## Features
|
||||
|
||||
### 🎯 **Intuitive Interface**
|
||||
- **Split-pane Layout**: Job list on the left, details on the right
|
||||
- **Real-time Updates**: Auto-refreshes every 2 seconds
|
||||
- **Color-coded Status**: Visual job status indicators
|
||||
- **Keyboard Navigation**: Vim-style and arrow key support
|
||||
|
||||
### 📋 **Job Management**
|
||||
- **Create Jobs**: Interactive form with tab navigation
|
||||
- **Monitor Jobs**: Real-time status updates with color coding
|
||||
- **View Details**: Detailed job information and output
|
||||
- **View Logs**: Access job execution logs
|
||||
- **Stop/Delete**: Job lifecycle management
|
||||
- **Bulk Operations**: Clear all jobs with confirmation
|
||||
|
||||
### 🎨 **Visual Design**
|
||||
- **Status Colors**:
|
||||
- 🔵 **Blue**: Dispatched
|
||||
- 🟡 **Yellow**: Started
|
||||
- 🟢 **Green**: Finished
|
||||
- 🔴 **Red**: Error
|
||||
- 🟣 **Magenta**: Waiting for Prerequisites
|
||||
- **Highlighted Selection**: Clear visual feedback
|
||||
- **Popup Messages**: Status and error notifications
|
||||
- **Confirmation Dialogs**: Safe bulk operations
|
||||
|
||||
## Usage
|
||||
|
||||
### 1. Start the TUI
|
||||
|
||||
```bash
|
||||
cd /Users/timurgordon/code/git.ourworld.tf/herocode/baobab/core/supervisor
|
||||
cargo run --bin supervisor-tui -- --config examples/cli_config.toml
|
||||
```
|
||||
|
||||
### 2. Navigation
|
||||
|
||||
#### Main View
|
||||
- **↑/↓ or j/k**: Navigate job list
|
||||
- **Enter/Space**: View job details
|
||||
- **n/c**: Create new job
|
||||
- **r**: Manual refresh
|
||||
- **d**: Delete selected job (with confirmation)
|
||||
- **s**: Stop selected job
|
||||
- **C**: Clear all jobs (with confirmation)
|
||||
- **q**: Quit application
|
||||
|
||||
#### Job Creation Form
|
||||
- **Tab**: Next field
|
||||
- **Shift+Tab**: Previous field
|
||||
- **Enter**: Next field (or newline in script field)
|
||||
- **F5**: Submit job
|
||||
- **Esc**: Cancel and return to main view
|
||||
|
||||
#### Job Details/Logs View
|
||||
- **Esc/q**: Return to main view
|
||||
- **l**: Switch to logs view
|
||||
- **d**: Switch to details view
|
||||
|
||||
## Interface Layout
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ Hero Supervisor TUI - Job Management │
|
||||
├─────────────────────┬───────────────────────────────────────┤
|
||||
│ Jobs │ Job Details │
|
||||
│ │ │
|
||||
│ >> 1a2b3c4d - ✅ Fi │ Job ID: 1a2b3c4d5e6f7g8h │
|
||||
│ 2b3c4d5e - 🟡 St │ Status: Finished │
|
||||
│ 3c4d5e6f - 🔴 Er │ │
|
||||
│ 4d5e6f7g - 🔵 Di │ Output: │
|
||||
│ │ Calculation result: 70 │
|
||||
│ │ 70 │
|
||||
├─────────────────────┴───────────────────────────────────────┤
|
||||
│ q: Quit | n: New Job | ↑↓: Navigate | Enter: Details │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
## Job Creation Workflow
|
||||
|
||||
1. **Press 'n'** to create a new job
|
||||
2. **Fill in the form**:
|
||||
- **Caller**: Your name or identifier
|
||||
- **Context**: Job description
|
||||
- **Script**: Rhai script (supports multi-line)
|
||||
3. **Press F5** to submit
|
||||
4. **Watch real-time execution** in the main view
|
||||
|
||||
### Example Rhai Scripts
|
||||
|
||||
```rhai
|
||||
// Simple calculation
|
||||
let result = 10 + 20 * 3;
|
||||
print("Calculation result: " + result);
|
||||
result
|
||||
```
|
||||
|
||||
```rhai
|
||||
// String manipulation
|
||||
let message = "Hello from OSIS Actor!";
|
||||
print(message);
|
||||
message.to_upper()
|
||||
```
|
||||
|
||||
```rhai
|
||||
// Loop example
|
||||
let sum = 0;
|
||||
for i in 1..=10 {
|
||||
sum += i;
|
||||
}
|
||||
print("Sum of 1-10: " + sum);
|
||||
sum
|
||||
```
|
||||
|
||||
## Key Improvements over CLI
|
||||
|
||||
### ✅ **Better UX**
|
||||
- **Visual Navigation**: No need to remember numbers
|
||||
- **Real-time Updates**: See job progress immediately
|
||||
- **Split-pane Design**: View list and details simultaneously
|
||||
- **Form Validation**: Clear error messages
|
||||
|
||||
### ✅ **Enhanced Productivity**
|
||||
- **Auto-refresh**: Always up-to-date information
|
||||
- **Keyboard Shortcuts**: Fast navigation and actions
|
||||
- **Confirmation Dialogs**: Prevent accidental operations
|
||||
- **Multi-line Script Input**: Better script editing
|
||||
|
||||
### ✅ **Professional Interface**
|
||||
- **Color-coded Status**: Quick visual assessment
|
||||
- **Consistent Layout**: Predictable interface elements
|
||||
- **Popup Notifications**: Non-intrusive feedback
|
||||
- **Graceful Error Handling**: User-friendly error messages
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Redis server running (default: localhost:6379)
|
||||
- OSIS actor binary built and configured
|
||||
- Terminal with color support
|
||||
- Minimum terminal size: 80x24
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Display Issues
|
||||
- Ensure terminal supports colors and Unicode
|
||||
- Resize terminal if layout appears broken
|
||||
- Use a modern terminal emulator (iTerm2, Alacritty, etc.)
|
||||
|
||||
### Performance
|
||||
- TUI auto-refreshes every 2 seconds
|
||||
- Large job lists may impact performance
|
||||
- Use 'r' for manual refresh if needed
|
||||
|
||||
### Navigation Issues
|
||||
- Use arrow keys if vim keys (j/k) don't work
|
||||
- Ensure terminal is in focus
|
||||
- Try Esc to reset state if stuck
|
||||
|
||||
## Advanced Features
|
||||
|
||||
### Bulk Operations
|
||||
- **Clear All Jobs**: Press 'C' with confirmation
|
||||
- **Safe Deletion**: Confirmation required for destructive operations
|
||||
|
||||
### Real-time Monitoring
|
||||
- **Auto-refresh**: Updates every 2 seconds
|
||||
- **Status Tracking**: Watch job progression
|
||||
- **Immediate Feedback**: See results as they complete
|
||||
|
||||
### Multi-line Scripts
|
||||
- **Rich Text Input**: Full script editing in TUI
|
||||
- **Syntax Awareness**: Better than single-line CLI input
|
||||
- **Preview**: See script before submission
|
398
core/supervisor/cmd/supervisor_cli.rs
Normal file
398
core/supervisor/cmd/supervisor_cli.rs
Normal file
@@ -0,0 +1,398 @@
|
||||
use clap::Parser;
|
||||
use colored::*;
|
||||
use hero_supervisor::{Supervisor, SupervisorBuilder, SupervisorError, Job, JobStatus, ScriptType};
|
||||
use log::{error, info};
|
||||
use std::io::{self, Write};
|
||||
use std::path::PathBuf;
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
use tokio::time::sleep;
|
||||
|
||||
#[derive(Parser)]
|
||||
#[command(name = "supervisor-cli")]
|
||||
#[command(about = "Interactive CLI for Hero Supervisor - Dispatch jobs to actors")]
|
||||
struct Args {
|
||||
/// Path to TOML configuration file
|
||||
#[arg(short, long)]
|
||||
config: PathBuf,
|
||||
|
||||
/// Enable verbose logging
|
||||
#[arg(short, long)]
|
||||
verbose: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
enum CliCommand {
|
||||
ListJobs,
|
||||
RunJob,
|
||||
GetJobStatus,
|
||||
GetJobOutput,
|
||||
GetJobLogs,
|
||||
StopJob,
|
||||
DeleteJob,
|
||||
ClearAllJobs,
|
||||
Quit,
|
||||
}
|
||||
|
||||
impl CliCommand {
|
||||
fn all_commands() -> Vec<(CliCommand, &'static str, &'static str)> {
|
||||
vec![
|
||||
(CliCommand::ListJobs, "list_jobs", "List all jobs in the system"),
|
||||
(CliCommand::RunJob, "run_job", "Create and run a new job"),
|
||||
(CliCommand::GetJobStatus, "get_job_status", "Get status of a specific job"),
|
||||
(CliCommand::GetJobOutput, "get_job_output", "Get output of a completed job"),
|
||||
(CliCommand::GetJobLogs, "get_job_logs", "Get logs for a specific job"),
|
||||
(CliCommand::StopJob, "stop_job", "Stop a running job"),
|
||||
(CliCommand::DeleteJob, "delete_job", "Delete a specific job"),
|
||||
(CliCommand::ClearAllJobs, "clear_all_jobs", "Clear all jobs from the system"),
|
||||
(CliCommand::Quit, "quit", "Exit the CLI"),
|
||||
]
|
||||
}
|
||||
|
||||
fn from_index(index: usize) -> Option<CliCommand> {
|
||||
Self::all_commands().get(index).map(|(cmd, _, _)| cmd.clone())
|
||||
}
|
||||
}
|
||||
|
||||
struct SupervisorCli {
|
||||
supervisor: Arc<Supervisor>,
|
||||
}
|
||||
|
||||
impl SupervisorCli {
|
||||
fn new(supervisor: Arc<Supervisor>) -> Self {
|
||||
Self { supervisor }
|
||||
}
|
||||
|
||||
async fn run(&self) -> Result<(), SupervisorError> {
|
||||
println!("{}", "=== Hero Supervisor CLI ===".bright_blue().bold());
|
||||
println!("{}", "Interactive job management interface".cyan());
|
||||
println!();
|
||||
|
||||
loop {
|
||||
self.display_menu();
|
||||
|
||||
match self.get_user_choice().await {
|
||||
Some(command) => {
|
||||
match command {
|
||||
CliCommand::Quit => {
|
||||
println!("{}", "Goodbye!".bright_green());
|
||||
break;
|
||||
}
|
||||
_ => {
|
||||
if let Err(e) = self.execute_command(command).await {
|
||||
eprintln!("{} {}", "Error:".bright_red(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
None => {
|
||||
println!("{}", "Invalid selection. Please try again.".yellow());
|
||||
}
|
||||
}
|
||||
|
||||
println!();
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn display_menu(&self) {
|
||||
println!("{}", "Available Commands:".bright_yellow().bold());
|
||||
for (index, (_, name, description)) in CliCommand::all_commands().iter().enumerate() {
|
||||
println!(" {}. {} - {}",
|
||||
(index + 1).to_string().bright_white().bold(),
|
||||
name.bright_cyan(),
|
||||
description
|
||||
);
|
||||
}
|
||||
print!("\n{} ", "Select a command (1-9):".bright_white());
|
||||
io::stdout().flush().unwrap();
|
||||
}
|
||||
|
||||
async fn get_user_choice(&self) -> Option<CliCommand> {
|
||||
let mut input = String::new();
|
||||
if io::stdin().read_line(&mut input).is_ok() {
|
||||
if let Ok(choice) = input.trim().parse::<usize>() {
|
||||
if choice > 0 {
|
||||
return CliCommand::from_index(choice - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
async fn execute_command(&self, command: CliCommand) -> Result<(), SupervisorError> {
|
||||
match command {
|
||||
CliCommand::ListJobs => self.list_jobs().await,
|
||||
CliCommand::RunJob => self.run_job().await,
|
||||
CliCommand::GetJobStatus => self.get_job_status().await,
|
||||
CliCommand::GetJobOutput => self.get_job_output().await,
|
||||
CliCommand::GetJobLogs => self.get_job_logs().await,
|
||||
CliCommand::StopJob => self.stop_job().await,
|
||||
CliCommand::DeleteJob => self.delete_job().await,
|
||||
CliCommand::ClearAllJobs => self.clear_all_jobs().await,
|
||||
CliCommand::Quit => Ok(()),
|
||||
}
|
||||
}
|
||||
|
||||
async fn list_jobs(&self) -> Result<(), SupervisorError> {
|
||||
println!("{}", "Listing all jobs...".bright_blue());
|
||||
|
||||
let jobs = self.supervisor.list_jobs().await?;
|
||||
|
||||
if jobs.is_empty() {
|
||||
println!("{}", "No jobs found.".yellow());
|
||||
} else {
|
||||
println!("{} jobs found:", jobs.len().to_string().bright_white().bold());
|
||||
for job_id in jobs {
|
||||
let status = self.supervisor.get_job_status(&job_id).await?;
|
||||
let status_color = match status {
|
||||
JobStatus::Dispatched => "blue",
|
||||
JobStatus::Started => "yellow",
|
||||
JobStatus::Finished => "green",
|
||||
JobStatus::Error => "red",
|
||||
JobStatus::WaitingForPrerequisites => "magenta",
|
||||
};
|
||||
|
||||
println!(" {} - {}",
|
||||
job_id.bright_white(),
|
||||
format!("{:?}", status).color(status_color)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn run_job(&self) -> Result<(), SupervisorError> {
|
||||
println!("{}", "Creating a new job...".bright_blue());
|
||||
|
||||
// Get caller
|
||||
print!("Enter caller name: ");
|
||||
io::stdout().flush().unwrap();
|
||||
let mut caller = String::new();
|
||||
io::stdin().read_line(&mut caller).unwrap();
|
||||
let caller = caller.trim().to_string();
|
||||
|
||||
// Get context
|
||||
print!("Enter job context: ");
|
||||
io::stdout().flush().unwrap();
|
||||
let mut context = String::new();
|
||||
io::stdin().read_line(&mut context).unwrap();
|
||||
let context = context.trim().to_string();
|
||||
|
||||
// Get script
|
||||
println!("Enter Rhai script (end with empty line):");
|
||||
let mut script_lines = Vec::new();
|
||||
loop {
|
||||
let mut line = String::new();
|
||||
io::stdin().read_line(&mut line).unwrap();
|
||||
let line = line.trim_end_matches('\n');
|
||||
if line.is_empty() {
|
||||
break;
|
||||
}
|
||||
script_lines.push(line.to_string());
|
||||
}
|
||||
let script = script_lines.join("\n");
|
||||
|
||||
if script.is_empty() {
|
||||
println!("{}", "Script cannot be empty!".bright_red());
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
// For now, default to OSIS actor (ScriptType::OSIS)
|
||||
let script_type = ScriptType::OSIS;
|
||||
|
||||
// Create the job
|
||||
let job = Job::new(caller, context, script, script_type);
|
||||
|
||||
println!("{} Job ID: {}",
|
||||
"Created job with".bright_green(),
|
||||
job.id.bright_white().bold()
|
||||
);
|
||||
|
||||
// Run the job and await result
|
||||
println!("{}", "Dispatching job and waiting for result...".bright_blue());
|
||||
|
||||
match self.supervisor.run_job_and_await_result(&job).await {
|
||||
Ok(result) => {
|
||||
println!("{}", "Job completed successfully!".bright_green().bold());
|
||||
println!("{} {}", "Result:".bright_yellow(), result.bright_white());
|
||||
}
|
||||
Err(e) => {
|
||||
println!("{} {}", "Job failed:".bright_red().bold(), e);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn get_job_status(&self) -> Result<(), SupervisorError> {
|
||||
let job_id = self.prompt_for_job_id("Enter job ID to check status: ")?;
|
||||
|
||||
let status = self.supervisor.get_job_status(&job_id).await?;
|
||||
let status_color = match status {
|
||||
JobStatus::Dispatched => "blue",
|
||||
JobStatus::Started => "yellow",
|
||||
JobStatus::Finished => "green",
|
||||
JobStatus::Error => "red",
|
||||
JobStatus::WaitingForPrerequisites => "magenta",
|
||||
};
|
||||
|
||||
println!("{} {} - {}",
|
||||
"Job".bright_white(),
|
||||
job_id.bright_white().bold(),
|
||||
format!("{:?}", status).color(status_color).bold()
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn get_job_output(&self) -> Result<(), SupervisorError> {
|
||||
let job_id = self.prompt_for_job_id("Enter job ID to get output: ")?;
|
||||
|
||||
match self.supervisor.get_job_output(&job_id).await? {
|
||||
Some(output) => {
|
||||
println!("{}", "Job Output:".bright_yellow().bold());
|
||||
println!("{}", output.bright_white());
|
||||
}
|
||||
None => {
|
||||
println!("{}", "No output available for this job.".yellow());
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn get_job_logs(&self) -> Result<(), SupervisorError> {
|
||||
let job_id = self.prompt_for_job_id("Enter job ID to get logs: ")?;
|
||||
|
||||
match self.supervisor.get_job_logs(&job_id).await? {
|
||||
Some(logs) => {
|
||||
println!("{}", "Job Logs:".bright_yellow().bold());
|
||||
println!("{}", logs.bright_white());
|
||||
}
|
||||
None => {
|
||||
println!("{}", "No logs available for this job.".yellow());
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn stop_job(&self) -> Result<(), SupervisorError> {
|
||||
let job_id = self.prompt_for_job_id("Enter job ID to stop: ")?;
|
||||
|
||||
self.supervisor.stop_job(&job_id).await?;
|
||||
println!("{} {}",
|
||||
"Stop signal sent for job".bright_green(),
|
||||
job_id.bright_white().bold()
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn delete_job(&self) -> Result<(), SupervisorError> {
|
||||
let job_id = self.prompt_for_job_id("Enter job ID to delete: ")?;
|
||||
|
||||
self.supervisor.delete_job(&job_id).await?;
|
||||
println!("{} {}",
|
||||
"Deleted job".bright_green(),
|
||||
job_id.bright_white().bold()
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn clear_all_jobs(&self) -> Result<(), SupervisorError> {
|
||||
print!("Are you sure you want to clear ALL jobs? (y/N): ");
|
||||
io::stdout().flush().unwrap();
|
||||
|
||||
let mut confirmation = String::new();
|
||||
io::stdin().read_line(&mut confirmation).unwrap();
|
||||
|
||||
if confirmation.trim().to_lowercase() == "y" {
|
||||
let count = self.supervisor.clear_all_jobs().await?;
|
||||
println!("{} {} jobs",
|
||||
"Cleared".bright_green().bold(),
|
||||
count.to_string().bright_white().bold()
|
||||
);
|
||||
} else {
|
||||
println!("{}", "Operation cancelled.".yellow());
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn prompt_for_job_id(&self, prompt: &str) -> Result<String, SupervisorError> {
|
||||
print!("{}", prompt);
|
||||
io::stdout().flush().unwrap();
|
||||
|
||||
let mut job_id = String::new();
|
||||
io::stdin().read_line(&mut job_id).unwrap();
|
||||
let job_id = job_id.trim().to_string();
|
||||
|
||||
if job_id.is_empty() {
|
||||
return Err(SupervisorError::ConfigError("Job ID cannot be empty".to_string()));
|
||||
}
|
||||
|
||||
Ok(job_id)
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let args = Args::parse();
|
||||
|
||||
// Setup logging
|
||||
if args.verbose {
|
||||
env_logger::Builder::from_default_env()
|
||||
.filter_level(log::LevelFilter::Debug)
|
||||
.init();
|
||||
} else {
|
||||
env_logger::Builder::from_default_env()
|
||||
.filter_level(log::LevelFilter::Info)
|
||||
.init();
|
||||
}
|
||||
|
||||
info!("Starting Supervisor CLI with config: {:?}", args.config);
|
||||
|
||||
// Build supervisor from TOML config
|
||||
let supervisor = Arc::new(
|
||||
SupervisorBuilder::from_toml(&args.config)?
|
||||
.build().await?
|
||||
);
|
||||
|
||||
println!("{}", "Starting actors...".bright_blue());
|
||||
|
||||
// Start the actors
|
||||
supervisor.start_actors().await?;
|
||||
|
||||
// Give actors time to start up
|
||||
sleep(Duration::from_secs(2)).await;
|
||||
|
||||
println!("{}", "Actors started successfully!".bright_green());
|
||||
println!();
|
||||
|
||||
// Create and run the CLI
|
||||
let cli = SupervisorCli::new(supervisor.clone());
|
||||
|
||||
// Setup cleanup on exit
|
||||
let supervisor_cleanup = supervisor.clone();
|
||||
tokio::spawn(async move {
|
||||
tokio::signal::ctrl_c().await.expect("Failed to listen for ctrl+c");
|
||||
println!("\n{}", "Shutting down...".bright_yellow());
|
||||
if let Err(e) = supervisor_cleanup.cleanup_and_shutdown().await {
|
||||
eprintln!("Error during cleanup: {}", e);
|
||||
}
|
||||
std::process::exit(0);
|
||||
});
|
||||
|
||||
// Run the interactive CLI
|
||||
cli.run().await?;
|
||||
|
||||
// Cleanup on normal exit
|
||||
supervisor.cleanup_and_shutdown().await?;
|
||||
|
||||
Ok(())
|
||||
}
|
1052
core/supervisor/cmd/supervisor_tui.rs
Normal file
1052
core/supervisor/cmd/supervisor_tui.rs
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user