"use client"; import { useState } from "react"; import useSWR from "swr"; import AppShell from "@/components/AppShell"; import { PageHeader } from "@/components/ui"; import { api, fetcher } from "@/lib/api"; import { useAuth } from "@/lib/auth"; type SkillSummary = { id: string; name: string; description: string; priority: number; rule_ids: string[]; path_hint: string; }; type SkillsListResponse = { skills: SkillSummary[]; path_hint: string; }; type SkillDetail = SkillSummary & { markdown: string; match: Record; }; export default function SkillsPage() { const { user } = useAuth(); const isAdmin = user?.role === "admin"; const { data: listData } = useSWR("/api/skills", fetcher); const [selectedId, setSelectedId] = useState(null); const [markdown, setMarkdown] = useState(null); const [previewTitle, setPreviewTitle] = useState("VoIP issue"); const [previewIssue, setPreviewIssue] = useState("one-way audio on SIP calls from crew phones"); const [previewRuleId, setPreviewRuleId] = useState(""); const [preview, setPreview] = useState<{ matched: Record[] } | null>(null); const [saving, setSaving] = useState(false); const [msg, setMsg] = useState(null); const [msgKind, setMsgKind] = useState<"ok" | "err">("ok"); const skills = listData?.skills ?? []; const activeId = selectedId ?? skills[0]?.id ?? null; const { data: skillData, mutate } = useSWR( activeId ? `/api/skills/${activeId}` : null, fetcher, ); const content = markdown ?? skillData?.markdown ?? ""; const selectSkill = (id: string) => { setSelectedId(id); setMarkdown(null); setMsg(null); }; const save = async () => { if (!activeId) return; setSaving(true); setMsg(null); try { await api(`/api/skills/${activeId}`, { method: "PUT", body: JSON.stringify({ markdown: content }), }); setMsgKind("ok"); setMsg("Skill saved — next task run will use it."); setMarkdown(null); mutate(); } catch (err: unknown) { setMsgKind("err"); setMsg(err instanceof Error ? err.message : "Save failed"); } finally { setSaving(false); } }; const runPreview = async () => { setPreview(null); try { const body: Record = { title: previewTitle, issue: previewIssue, }; if (previewRuleId.trim()) body.matched_rule_id = previewRuleId.trim(); const res = await api<{ matched: Record[] }>("/api/skills/preview", { method: "POST", body: JSON.stringify(body), }); setPreview(res); } catch (err: unknown) { setMsgKind("err"); setMsg(err instanceof Error ? err.message : "Preview failed"); } }; return (

Skill preview

Test which skills match a task title + issue.

setPreviewTitle(e.target.value)} placeholder="Task title" />