use crate::error::ApiError; use crate::state::AppState; use axum::extract::{Path, State}; use axum::routing::get; use axum::{Json, Router}; use serde_json::{json, Value}; use std::sync::Arc; pub fn routes() -> Router> { Router::new() .route("/skills", get(list_skills)) .route("/skills/{name}", get(get_skill)) .route("/skills/{name}/used-by", get(skill_used_by)) } async fn list_skills(State(state): State>) -> Result, ApiError> { let skills = state.skills.read().unwrap(); let list: Vec = skills .values() .map(|s| { json!({ "name": s.frontmatter.name, "description": s.frontmatter.description, "version": s.frontmatter.version, }) }) .collect(); Ok(Json(json!(list))) } async fn get_skill( State(state): State>, Path(name): Path, ) -> Result, ApiError> { let skills = state.skills.read().unwrap(); let skill = skills .get(&name) .ok_or_else(|| ApiError::NotFound(format!("Skill '{}' not found", name)))?; Ok(Json(json!({ "name": skill.frontmatter.name, "description": skill.frontmatter.description, "version": skill.frontmatter.version, "requires_mcp": skill.frontmatter.requires_mcp, "inputs": skill.frontmatter.inputs, "outputs": skill.frontmatter.outputs, "body": skill.body, }))) } async fn skill_used_by( State(state): State>, Path(name): Path, ) -> Result, ApiError> { let agents = state.agents.read().unwrap(); let users: Vec = agents .values() .filter(|a| a.frontmatter.skills.contains(&name)) .map(|a| a.frontmatter.name.clone()) .collect(); Ok(Json(json!(users))) }