use crate::Result;
use serde_json::Value;
use std::path::PathBuf;
#[allow(clippy::exhaustive_structs)] pub struct Context {
pub dry_run: bool,
pub job_id: String,
pub working_dir: PathBuf,
}
impl Context {
#[must_use]
pub fn new(dry_run: bool, job_id: String) -> Self {
Self {
dry_run,
job_id,
working_dir: std::env::current_dir().unwrap_or_else(|_| PathBuf::from("/")),
}
}
#[must_use]
pub fn with_working_dir(dry_run: bool, job_id: String, working_dir: PathBuf) -> Self {
Self {
dry_run,
job_id,
working_dir,
}
}
}
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
#[allow(clippy::exhaustive_structs)] pub struct Output {
pub success: bool,
pub data: Value,
pub message: Option<String>,
}
pub trait Capability: Send + Sync {
fn name(&self) -> &'static str;
fn description(&self) -> &'static str;
fn schema(&self) -> Value;
fn validate(&self, args: &Value) -> Result<()>;
fn execute(&self, args: &Value, ctx: &Context) -> Result<Output>;
}
pub struct CapabilityRegistry {
capabilities: std::collections::HashMap<String, Box<dyn Capability>>,
}
impl CapabilityRegistry {
#[must_use]
pub fn new() -> Self {
Self {
capabilities: std::collections::HashMap::new(),
}
}
pub fn register<C: Capability + 'static>(&mut self, capability: C) {
let name = capability.name().to_string();
self.capabilities.insert(name, Box::new(capability));
}
#[must_use]
pub fn get(&self, name: &str) -> Option<&dyn Capability> {
self.capabilities.get(name).map(|c| c.as_ref())
}
#[must_use]
pub fn list(&self) -> Vec<&str> {
self.capabilities.keys().map(|s| s.as_str()).collect()
}
}
impl Default for CapabilityRegistry {
fn default() -> Self {
Self::new()
}
}