import { useState } from "react" import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query" import { Bot, Play, Loader2, CheckCircle2, AlertTriangle } from "lucide-react" import { cn } from "@/lib/utils" import { api } from "@/lib/api" import { qk } from "@/lib/queries" import { JobsBar } from "@/components/models/JobsBar" interface Skill { name: string description: string running?: boolean } interface SkillsResp { skills: Skill[] } export function SkillsView() { const queryClient = useQueryClient() const { data, isLoading, isError } = useQuery({ queryKey: ["skills-list"], queryFn: () => api("/api/skills"), refetchInterval: 5000, }) const [runningSkill, setRunningSkill] = useState(null) const [lastResult, setLastResult] = useState<{name: string, ok: boolean, msg: string} | null>(null) const mutation = useMutation({ mutationFn: (skillName: string) => api<{ok: boolean, msg?: string, err?: string}>("/api/skills/run", { method: "POST", body: JSON.stringify({ skill_name: skillName }) }), onMutate: (skillName) => { setRunningSkill(skillName) setLastResult(null) }, onSuccess: (res, skillName) => { setRunningSkill(null) setLastResult({ name: skillName, ok: res.ok, msg: res.msg || res.err || "Unbekannter Fehler" }) // Jobs neu laden, damit der gestartete Skill direkt in der JobsBar auftaucht queryClient.invalidateQueries({ queryKey: qk.jobs }) queryClient.invalidateQueries({ queryKey: ["skills-list"] }) }, onError: (err, skillName) => { setRunningSkill(null) setLastResult({ name: skillName, ok: false, msg: String(err) }) } }) return (

Skills & Jobs

Löst autonome Agent-Skills manuell auf der Box aus. Die Ausführung erfolgt im Hintergrund durch Hermes.

{lastResult && (
{lastResult.ok ? : }
{lastResult.name}
{lastResult.msg}
)} {isLoading && (
)} {isError && (
Fehler beim Laden der Skills. Ist das Backend erreichbar?
)} {data?.skills && (
{data.skills.map(skill => (
{skill.name}
{skill.description}
))} {data.skills.length === 0 && (
Keine Skills im Ordner deploy/skills gefunden.
)}
)}
) }