vault-os/crates/vault-api/src/routes/skills.rs
Harald Hoyer f820a72b04 Initial implementation of vault-os
Complete implementation across all 13 phases:

- vault-core: types, YAML frontmatter parsing, entity classification,
  filesystem ops, config, prompt composition, validation, search
- vault-watch: filesystem watcher with daemon write filtering, event
  classification
- vault-scheduler: cron engine, process executor, task runner with
  retry logic and concurrency limiting
- vault-api: Axum REST API (15 route modules), WebSocket with broadcast,
  AI assistant proxy, validation, templates
- Dashboard: React + TypeScript + Tailwind v4 with kanban, CodeMirror
  editor, dynamic view system, AI chat sidebar
- Nix flake with dev shell and NixOS module
- Graceful shutdown, inotify overflow recovery, tracing instrumentation

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 01:21:17 +01:00

62 lines
1.9 KiB
Rust

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<Arc<AppState>> {
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<Arc<AppState>>) -> Result<Json<Value>, ApiError> {
let skills = state.skills.read().unwrap();
let list: Vec<Value> = 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<Arc<AppState>>,
Path(name): Path<String>,
) -> Result<Json<Value>, 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<Arc<AppState>>,
Path(name): Path<String>,
) -> Result<Json<Value>, ApiError> {
let agents = state.agents.read().unwrap();
let users: Vec<String> = agents
.values()
.filter(|a| a.frontmatter.skills.contains(&name))
.map(|a| a.frontmatter.name.clone())
.collect();
Ok(Json(json!(users)))
}