use crate::{Context, World, error::SkillError};
use serde::{Deserialize, Serialize};
use std::borrow::Cow;
use std::collections::BTreeMap;
use std::path::PathBuf;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SkillManifest {
pub name: String,
pub description: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub license: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub compatibility: Option<String>,
#[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
pub metadata: BTreeMap<String, serde_json::Value>,
#[serde(default, skip_serializing_if = "Option::is_none", rename = "allowed-tools")]
pub allowed_tools: Option<String>,
}
impl SkillManifest {
pub fn harness_ext(&self) -> Option<HarnessExt> {
let v = self.metadata.get("harness")?;
serde_json::from_value::<HarnessExt>(v.clone()).ok()
}
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct HarnessExt {
#[serde(default)]
pub kind: Option<crate::Execution>,
#[serde(default)]
pub risk: Option<crate::ToolRisk>,
#[serde(default)]
pub entrypoint: Option<String>,
#[serde(default)]
pub schema_version: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Resource {
pub kind: ResourceKind,
pub path: PathBuf,
pub summary: Option<String>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
#[non_exhaustive]
pub enum ResourceKind {
Script,
Reference,
Asset,
}
pub type SkillHandler = std::sync::Arc<
dyn for<'a> Fn(
&'a mut Context,
&'a mut World,
) -> futures::future::BoxFuture<'a, Result<(), SkillError>>
+ Send
+ Sync,
>;
pub trait Skill: Send + Sync + 'static {
fn manifest(&self) -> &SkillManifest;
fn body(&self) -> Cow<'_, str>;
fn resources(&self) -> &[Resource] { &[] }
fn handler(&self) -> Option<SkillHandler> { None }
}
pub struct SkillEntry {
pub factory: fn() -> std::sync::Arc<dyn Skill>,
}
inventory::collect!(SkillEntry);
pub fn iter_macro_skills() -> impl Iterator<Item = std::sync::Arc<dyn Skill>> {
inventory::iter::<SkillEntry>().map(|e| (e.factory)())
}