"use client"; import { createFileRoute, useNavigate } from "@tanstack/react-router"; import { useState } from "react"; import { useForm, Controller } from "react-hook-form"; import { zodResolver } from "@hookform/resolvers/zod"; import { ArrowLeft, Check, CircleDashed, Loader2, Sparkles, X } from "lucide-react"; import { Link } from "@tanstack/react-router"; import { toast } from "sonner"; import { supabase } from "@/integrations/supabase/client"; import { skillFormSchema, AVAILABLE_TOOLS, type SkillFormValues } from "@/lib/skill-schema"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Textarea } from "@/components/ui/textarea"; import { Label } from "@/components/ui/label"; import { Badge } from "@/components/ui/badge"; import { cn } from "@/lib/utils"; export const Route = createFileRoute("/painel/skills/nova")({ component: NovaSkillPage, }); const FIELDS_META: { key: keyof SkillFormValues; label: string; required: boolean }[] = [ { key: "name", label: "Nome", required: true }, { key: "description", label: "Descrição", required: true }, { key: "trigger_keywords", label: "Gatilhos", required: true }, { key: "expected_inputs", label: "Inputs esperados", required: false }, { key: "steps", label: "Passo a passo", required: true }, { key: "required_tools", label: "Ferramentas", required: true }, { key: "success_criteria", label: "Critério de sucesso", required: true }, { key: "example_use_case", label: "Exemplo de uso", required: false }, ]; function NovaSkillPage() { const navigate = useNavigate(); const [generating, setGenerating] = useState(false); const form = useForm({ resolver: zodResolver(skillFormSchema), defaultValues: { name: "", description: "", trigger_keywords: "", expected_inputs: "", steps: "", required_tools: [], success_criteria: "", example_use_case: "", }, mode: "onChange", }); const values = form.watch(); const { isValid } = form.formState; const fieldFilled = (key: keyof SkillFormValues): boolean => { const v = values[key]; if (key === "required_tools") return Array.isArray(v) && v.length > 0; return typeof v === "string" && v.trim().length > 0; }; const handleGenerate = async () => { const valid = await form.trigger(); if (!valid) return; setGenerating(true); try { const formValues = form.getValues(); const formInputs = { name: formValues.name, description: formValues.description, trigger_keywords: formValues.trigger_keywords, expected_inputs: formValues.expected_inputs || null, steps: formValues.steps, required_tools: formValues.required_tools, success_criteria: formValues.success_criteria, example_use_case: formValues.example_use_case || null, }; const { data, error } = await supabase.functions.invoke("generate-skill-markdown", { body: { form_inputs: formInputs }, }); if (error) { const msg = error.message || "Falha ao gerar skill"; if (msg.includes("429") || msg.includes("Muitas")) { toast.error("Muitas requisições. Aguarde 1 minuto e tente novamente."); } else { toast.error(msg); } return; } // Navigate to preview with state navigate({ to: "/painel/skills/preview", search: {}, state: { markdown_content: data.markdown_content, form_inputs: formInputs, } as Record, }); } catch (e) { toast.error("Erro inesperado ao gerar skill. Tente novamente."); } finally { setGenerating(false); } }; return (

Nova skill

Preencha os campos e gere o conteúdo com IA

{/* Form column */}