use actix_web::{web, HttpResponse};
use crate::app_state::AppState;
use crate::error::AppError;
use super::sources::{list_mcp_tools_as_commands, list_workflows_as_commands, skill_to_command};
use super::types::CommandListResponse;
pub async fn list_commands(app_state: web::Data<AppState>) -> Result<HttpResponse, AppError> {
let mut commands = Vec::new();
match list_workflows_as_commands(&app_state.app_data_dir).await {
Ok(workflows) => commands.extend(workflows),
Err(error) => {
tracing::warn!("Failed to load workflows: {error}");
}
}
let skills = app_state
.skill_manager
.store()
.list_skills(None, false)
.await;
let skill_commands = skills.into_iter().map(|skill| skill_to_command(&skill));
commands.extend(skill_commands);
match list_mcp_tools_as_commands(app_state.get_ref()).await {
Ok(mcp_tools) => commands.extend(mcp_tools),
Err(error) => {
tracing::warn!("Failed to load MCP tools: {error}");
}
}
commands.sort_by(|left, right| left.name.cmp(&right.name));
Ok(HttpResponse::Ok().json(CommandListResponse {
total: commands.len(),
commands,
}))
}
pub async fn get_command(
app_state: web::Data<AppState>,
path: web::Path<(String, String)>,
) -> Result<HttpResponse, AppError> {
let (command_type, id) = path.into_inner();
match command_type.as_str() {
"workflow" => {
let workflows_dir = app_state.app_data_dir.join("workflows");
let filename = format!("{id}.md");
let filepath = workflows_dir.join(&filename);
if !filepath.exists() {
return Err(AppError::NotFound(format!("Workflow {id} not found")));
}
let content = tokio::fs::read_to_string(&filepath)
.await
.map_err(|error| {
AppError::InternalError(anyhow::anyhow!("Failed to read workflow: {error}"))
})?;
Ok(HttpResponse::Ok().json(serde_json::json!({
"id": format!("workflow-{id}"),
"name": id,
"content": content,
"type": "workflow"
})))
}
"skill" => match app_state.skill_manager.store().get_skill(&id).await {
Ok(skill) => Ok(HttpResponse::Ok().json(skill)),
Err(error) => Err(AppError::NotFound(format!("Skill {id} not found: {error}"))),
},
"mcp" => Err(AppError::NotFound(
"MCP tools do not support content retrieval".to_string(),
)),
_ => Err(AppError::NotFound(format!(
"Unknown command type: {command_type}"
))),
}
}
pub fn config(cfg: &mut web::ServiceConfig) {
cfg.route("/commands", web::get().to(list_commands))
.route("/commands/{command_type}/{id}", web::get().to(get_command));
}