import React, { useState, useCallback } from 'react'; import { useApi } from '../hooks/useApi'; import { getMeshAgents, registerMeshAgent, unregisterMeshAgent, type MeshAgent } from '../api/discovery'; export default function CapabilityRegistry() { const [showForm, setShowForm] = useState(false); const agentsQuery = useApi(() => getMeshAgents(), []); const agents = agentsQuery.data ?? []; const handleUnregister = useCallback(async (name: string) => { if (!confirm(`Unregister agent "${name}"?`)) return; await unregisterMeshAgent(name); agentsQuery.refetch(); }, [agentsQuery]); const handleRegister = useCallback(async (data: { name: string; description: string; capabilities: string[]; endpoint: string }) => { await registerMeshAgent(data); setShowForm(false); agentsQuery.refetch(); }, [agentsQuery]); return (

🤖 Agent Registry

{showForm && setShowForm(false)} />} {agentsQuery.loading &&

Loading...

} {agentsQuery.error &&

Error: {agentsQuery.error}

} {!agentsQuery.loading && agents.length === 0 && (

No agents registered yet.

)} {agents.map((agent) => (
{agent.name}

{agent.description}

{agent.capabilities.map((cap) => ( {cap} ))}
Endpoint: {agent.endpoint} Protocol: {agent.protocol} Last seen: {new Date(agent.last_seen).toLocaleString()}
))}
); } function RegisterForm({ onSubmit, onCancel }: { onSubmit: (data: { name: string; description: string; capabilities: string[]; endpoint: string }) => void; onCancel: () => void; }) { const [name, setName] = useState(''); const [description, setDescription] = useState(''); const [capabilities, setCapabilities] = useState(''); const [endpoint, setEndpoint] = useState(''); const handleSubmit = (e: React.FormEvent) => { e.preventDefault(); onSubmit({ name, description, capabilities: capabilities.split(',').map(s => s.trim()).filter(Boolean), endpoint, }); }; return (

Register New Agent

); } const cardStyle: React.CSSProperties = { padding: '16px', border: '1px solid #e2e8f0', borderRadius: '8px', marginBottom: '12px', }; const btnStyle: React.CSSProperties = { padding: '8px 16px', background: '#3b82f6', color: 'white', border: 'none', borderRadius: '6px', cursor: 'pointer', fontSize: '14px', }; const smallBtnStyle: React.CSSProperties = { padding: '4px 10px', background: 'transparent', border: '1px solid #d1d5db', borderRadius: '4px', cursor: 'pointer', fontSize: '13px', }; const dangerBtnStyle: React.CSSProperties = { padding: '4px 10px', background: 'transparent', border: '1px solid #fca5a5', color: '#dc2626', borderRadius: '4px', cursor: 'pointer', fontSize: '13px', }; const tagStyle: React.CSSProperties = { padding: '2px 8px', background: '#e0f2fe', color: '#0369a1', borderRadius: '12px', fontSize: '12px', fontWeight: 500, }; const inputStyle: React.CSSProperties = { width: '100%', padding: '6px 10px', border: '1px solid #d1d5db', borderRadius: '4px', fontSize: '14px', marginTop: '4px', };