"use client"; import React, { useState } from 'react'; import { Loader2, AlertCircle, Bot, Zap } from 'lucide-react'; import type { BeadIssue } from '../../lib/types'; import type { AgentArchetype } from '../../lib/types-swarm'; import { WorkflowGraph } from '../shared/workflow-graph'; interface TelemetryGridProps { epicId: string; issues: BeadIssue[]; archetypes: AgentArchetype[]; } export function TelemetryGrid({ epicId, issues, archetypes }: TelemetryGridProps) { const [selectedBeadId, setSelectedBeadId] = useState(null); const [isPrepping, setIsPrepping] = useState(false); const [prepSuccess, setPrepSuccess] = useState(false); const [selectedArchetypeForPrep, setSelectedArchetypeForPrep] = useState(''); // 1. Filter beads for this epic const beads = issues.filter(issue => { if (issue.issue_type === 'epic') return false; // don't include epic itself in DAG const parent = issue.dependencies.find(d => d.type === 'parent'); return parent?.target === epicId; }); // 2. Compute "Attention Feed" (Blocked beads) const blockedBeads = beads.filter(b => b.status === 'blocked'); // 3. Compute "Active Roster" (Unique assignees working on in_progress beads) const activeAssignees = new Set(); const rosterEntries: { assignee: string, currentTask: string, archetype?: AgentArchetype }[] = []; beads.forEach(b => { if (b.status === 'in_progress' && b.assignee && !activeAssignees.has(b.assignee)) { activeAssignees.add(b.assignee); const assigneeStr = b.assignee.toLowerCase(); const matchedArchetype = archetypes.find(a => assigneeStr.includes(a.id.toLowerCase()) || assigneeStr.includes(a.name.toLowerCase()) ); rosterEntries.push({ assignee: b.assignee, currentTask: b.title, archetype: matchedArchetype }); } }); const selectedBead = selectedBeadId ? beads.find(b => b.id === selectedBeadId) : null; const handlePrepTask = async () => { if (!selectedBead || !selectedArchetypeForPrep) return; setIsPrepping(true); setPrepSuccess(false); try { const res = await fetch('/api/swarm/prep', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ beadId: selectedBead.id, archetypeId: selectedArchetypeForPrep }) }); if (!res.ok) throw new Error('Prep failed'); setPrepSuccess(true); setTimeout(() => setPrepSuccess(false), 3000); // Note: The shell's useIssues typically polls or relies on SWR to update. // In a real app we'd call mutate() here. } catch (e) { console.error(e); } finally { setIsPrepping(false); } }; return (
{/* Left/Top: Specialized DAG */}
Agent Flow
{/* Right/Bottom: Feeds */}
{/* Task Assignment Panel (Shows if a node is selected) */} {selectedBead && (

Task Assignment

{selectedBead.id}
{selectedBead.title}
Status: {selectedBead.status}
{(selectedBead.status === 'open' || selectedBead.status === 'blocked') ? (
) : (
Task is {selectedBead.status.replace('_', ' ')}. Only open or blocked tasks can be prepped.
)}
)} {/* Priority Attention */}

Priority Attention

{blockedBeads.length} Blocked
{blockedBeads.length === 0 ? (
All clear. No blocked tasks.
) : ( blockedBeads.map(b => (
{b.id}
{b.title}
)) )}
{/* Active Roster */}

Active Roster

{rosterEntries.length} Deployed
{rosterEntries.length === 0 ? (
No agents currently active.
) : ( rosterEntries.map((r, i) => (
{r.assignee.charAt(0).toUpperCase()}
{r.assignee}
{r.currentTask}
)) )}
); }