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>
62 lines
1.9 KiB
Rust
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)))
|
|
}
|