import { useState } from "react"; import { useQuery } from "@tanstack/react-query"; import { Card, CardContent, CardHeader, CardTitle, CardDescription } from "@/components/ui/card"; import { Badge } from "@/components/ui/badge"; import { Button } from "@/components/ui/button"; import { ScrollArea } from "@/components/ui/scroll-area"; import { CheckCircle, XCircle, Clock, Loader2, ChevronDown, ChevronRight, FileText, Code, Brain, Wrench, Shield, Rocket, TrendingUp, AlertCircle, RefreshCw, Filter, BarChart3, GitBranch, Eye, Layers, Play, } from "lucide-react"; interface TimelineEntry { id: number; agent: string; action: string; thought: string; observation?: string; createdAt: string; } interface SubtaskEntry { id: number; title: string; status: string; assignedAgent: string; startedAt?: string; completedAt?: string; } interface ArtifactEntry { id: number; type: string; name: string; createdBy: string; createdAt: string; } interface HistoryTask { id: number; type: string; title: string; description: string; status: string; priority: number; assignedAgent?: string; userId?: string; result?: any; errorMessage?: string; createdAt: string; updatedAt?: string; startedAt?: string; completedAt?: string; subtaskCount: number; artifactCount: number; logCount: number; subtasks: SubtaskEntry[]; artifacts: ArtifactEntry[]; timeline: TimelineEntry[]; } const AGENT_CONFIG: Record = { architect: { label: "Arquiteto", color: "bg-blue-100 text-blue-700 border-blue-200", icon: Brain }, generator: { label: "Gerador", color: "bg-purple-100 text-purple-700 border-purple-200", icon: Code }, validator: { label: "Validador", color: "bg-amber-100 text-amber-700 border-amber-200", icon: Shield }, executor: { label: "Executor", color: "bg-green-100 text-green-700 border-green-200", icon: Rocket }, evolution: { label: "Evolução", color: "bg-cyan-100 text-cyan-700 border-cyan-200", icon: TrendingUp }, dispatcher: { label: "Dispatcher", color: "bg-slate-100 text-slate-700 border-slate-200", icon: Layers }, }; const STATUS_CONFIG: Record = { pending: { label: "Pendente", color: "bg-slate-100 text-slate-600", icon: Clock }, in_progress: { label: "Em Progresso", color: "bg-blue-100 text-blue-600", icon: Loader2 }, completed: { label: "Concluída", color: "bg-green-100 text-green-600", icon: CheckCircle }, failed: { label: "Falhou", color: "bg-red-100 text-red-600", icon: XCircle }, blocked: { label: "Bloqueada", color: "bg-orange-100 text-orange-600", icon: AlertCircle }, }; const ARTIFACT_ICONS: Record = { spec: FileText, code: Code, test: Shield, doc: FileText, config: Wrench, analysis: BarChart3, }; function formatDate(dateStr?: string) { if (!dateStr) return "—"; const d = new Date(dateStr); return d.toLocaleDateString("pt-BR", { day: "2-digit", month: "2-digit", year: "2-digit" }) + " " + d.toLocaleTimeString("pt-BR", { hour: "2-digit", minute: "2-digit" }); } function formatDuration(start?: string, end?: string) { if (!start || !end) return null; const ms = new Date(end).getTime() - new Date(start).getTime(); if (ms < 1000) return `${ms}ms`; if (ms < 60000) return `${Math.round(ms / 1000)}s`; return `${Math.round(ms / 60000)}min`; } function TaskCard({ task, onContinueTask }: { task: HistoryTask; onContinueTask?: (title: string) => void }) { const [expanded, setExpanded] = useState(false); const [activeSection, setActiveSection] = useState<"timeline" | "subtasks" | "artifacts">("timeline"); const statusCfg = STATUS_CONFIG[task.status] || STATUS_CONFIG.pending; const StatusIcon = statusCfg.icon; const duration = formatDuration(task.startedAt || task.createdAt, task.completedAt); return (
setExpanded(!expanded)} >
{expanded ? : }
{task.title} #{task.id}

{task.description}

{duration && ( {duration} )} {task.subtaskCount} {task.artifactCount} {formatDate(task.createdAt)} {onContinueTask && ( )}
{expanded && (
{task.errorMessage && (
Erro: {task.errorMessage}
)}
{[ { key: "timeline" as const, label: "Timeline", count: task.logCount }, { key: "subtasks" as const, label: "Subtarefas", count: task.subtaskCount }, { key: "artifacts" as const, label: "Artefatos", count: task.artifactCount }, ].map(tab => ( ))}
{activeSection === "timeline" && (
{task.timeline.length === 0 ? (

Nenhum registro na timeline

) : (
{task.timeline.map((entry, idx) => { const agentCfg = AGENT_CONFIG[entry.agent] || AGENT_CONFIG.dispatcher; const AgentIcon = agentCfg.icon; return (
{agentCfg.label} {entry.action}
{formatDate(entry.createdAt)}

{entry.thought}

{entry.observation && (

{entry.observation.length > 200 ? entry.observation.slice(0, 200) + "…" : entry.observation}

)}
); })}
)}
)} {activeSection === "subtasks" && (
{task.subtasks.length === 0 ? (

Nenhuma subtarefa

) : ( task.subtasks.map(sub => { const subStatus = STATUS_CONFIG[sub.status] || STATUS_CONFIG.pending; const SubIcon = subStatus.icon; const agentCfg = AGENT_CONFIG[sub.assignedAgent] || AGENT_CONFIG.dispatcher; const AgentIcon = agentCfg.icon; const subDuration = formatDuration(sub.startedAt, sub.completedAt); return (

{sub.title}

{agentCfg.label} {subDuration && ( {subDuration} )}
{subStatus.label}
); }) )}
)} {activeSection === "artifacts" && (
{task.artifacts.length === 0 ? (

Nenhum artefato gerado

) : ( task.artifacts.map(art => { const ArtIcon = ARTIFACT_ICONS[art.type] || FileText; const agentCfg = AGENT_CONFIG[art.createdBy] || AGENT_CONFIG.dispatcher; return (

{art.name}

{art.type} {agentCfg.label} {formatDate(art.createdAt)}
); }) )}
)}
)} ); } interface DevHistoryProps { embedded?: boolean; onContinueTask?: (taskTitle: string) => void; } export default function DevHistory({ embedded, onContinueTask }: DevHistoryProps) { const [statusFilter, setStatusFilter] = useState("all"); const [page, setPage] = useState(0); const pageSize = 20; const { data: historyData, isLoading, refetch } = useQuery({ queryKey: ["/api/blackboard/history", statusFilter, page], queryFn: async () => { const params = new URLSearchParams(); params.set("limit", pageSize.toString()); params.set("offset", (page * pageSize).toString()); if (statusFilter !== "all") params.set("status", statusFilter); const res = await fetch(`/api/blackboard/history?${params}`, { credentials: "include" }); if (!res.ok) throw new Error("Falha ao carregar histórico"); return res.json(); }, refetchInterval: 15000, }); const { data: statsData } = useQuery({ queryKey: ["/api/blackboard/stats"], queryFn: async () => { const res = await fetch("/api/blackboard/stats", { credentials: "include" }); if (!res.ok) throw new Error("Falha ao carregar stats"); return res.json(); }, refetchInterval: 15000, }); const tasks: HistoryTask[] = historyData?.tasks || []; const stats = statsData?.stats; const agents = statsData?.agents || []; return (
{/* Stats Cards */}
{[ { label: "Total", value: stats?.totalTasks || 0, color: "text-foreground", bgColor: "bg-muted/50" }, { label: "Pendentes", value: stats?.pendingTasks || 0, color: "text-amber-600", bgColor: "bg-amber-50" }, { label: "Concluídas", value: stats?.completedTasks || 0, color: "text-green-600", bgColor: "bg-green-50" }, { label: "Falhas", value: stats?.failedTasks || 0, color: "text-red-600", bgColor: "bg-red-50" }, { label: "Artefatos", value: stats?.artifactsCount || 0, color: "text-blue-600", bgColor: "bg-blue-50" }, ].map(stat => (

{stat.value}

{stat.label}

))}
{/* Agentes Status */} {agents.length > 0 && (
Agentes: {agents.map((agent: any) => { const cfg = AGENT_CONFIG[agent.name] || AGENT_CONFIG.dispatcher; return (
{cfg.label} {agent.tasksProcessed > 0 && ` (${agent.tasksProcessed})`} ); })}
)} {/* Filtros e ações */}
{[ { key: "all", label: "Todas" }, { key: "completed", label: "Concluídas" }, { key: "failed", label: "Falhas" }, { key: "in_progress", label: "Em Progresso" }, { key: "pending", label: "Pendentes" }, ].map(f => ( ))}
{/* Lista de Tarefas */} {isLoading ? (
Carregando histórico...
) : tasks.length === 0 ? (

Nenhuma tarefa encontrada

As tarefas executadas pelos agentes autônomos aparecerão aqui com todos os detalhes.

) : (
{tasks.map(task => ( ))}
)}
{/* Pagination */} {(historyData?.total || 0) > pageSize && (
{page * pageSize + 1}–{Math.min((page + 1) * pageSize, historyData?.total || 0)} de {historyData?.total || 0}
)}
); }