import { useCallback, useEffect, useState } from 'react'; import { api } from '../api'; import { fmtId } from '../util'; import type { Cost, EventsSnapshot, McpDiscovery, MissionsResponse } from '../types'; type Filter = 'all' | 'mission' | 'task' | 'approval' | 'session' | 'inventory'; export function Telemetry({ refreshTick = 0 }: { refreshTick?: number }) { const [events, setEvents] = useState(null); const [missions, setMissions] = useState(null); const [cost, setCost] = useState(null); const [mcp, setMcp] = useState(null); const [filter, setFilter] = useState('all'); const [err, setErr] = useState(''); const load = useCallback(() => { Promise.all([ api('/api/events/snapshot'), api('/api/missions').catch(() => null), api('/api/cost').catch(() => null), api('/api/mcp/discovery').catch(() => null), ]).then(([eventData, missionData, costData, mcpData]) => { setEvents(eventData); setMissions(missionData); setCost(costData); setMcp(mcpData); setErr(''); }).catch((e) => setErr((e as Error).message)); }, []); useEffect(() => { load(); }, [load, refreshTick]); if (err) return

Could not load telemetry: {err}

; if (!events) return

Loading...

; const visible = filter === 'all' ? events.events : events.events.filter((e) => e.type.startsWith(filter)); const missionTotals = summarizeMissions(missions); const tokenTotal = cost ? cost.total.input_tokens + cost.total.output_tokens : 0; return ( <>

Live Cockpit telemetry from the unified event model. This replaces the legacy dashboard feed with Bridge-backed inventory, session, task, approval, Mission, and cost posture.

Events{events.count}{events.source}
Active Missions{missionTotals.active}{missionTotals.terminal} terminal
Approvals{missionTotals.awaiting}awaiting operator input
Spend{cost ? `$${cost.total.usd.toFixed(2)}` : '-'}{tokenTotal ? `${tokenTotal.toLocaleString()} tokens` : 'cost route unavailable'}
MCP{mcp?.status ?? '-'}{mcp ? `${mcp.tools.length} tools · ${mcp.auth.scopes.length} scopes` : 'discovery unavailable'}
{mcp && (

MCP Management

{mcp.endpoint.path} · {mcp.endpoint.transport} · {mcp.endpoint.stateless ? 'stateless' : 'stateful'} · session id {mcp.endpoint.mcp_session_id ? 'expected' : 'not expected'}

{mcp.auth.principals.length} principal(s): {mcp.auth.principals.map((principal) => principal.client_id).join(', ') || '-'}

Tools: {mcp.tools.map((tool) => tool.name).join(', ') || '-'}

Resources: {[...mcp.resources.map((resource) => resource.uri), ...mcp.resource_templates.map((template) => template.uriTemplate)].join(', ') || '-'}

{mcp.reason_code &&

{mcp.reason_code}

}
)}
{(['all', 'mission', 'task', 'approval', 'session', 'inventory'] as const).map((f) => ( ))}
{!visible.length ?

No events match this filter.

: ( {visible.map((e) => ( ))}
{visible.length} event(s), fetched {new Date(events.fetched_at).toLocaleTimeString()}
TimeTypeSubjectStateSource
{e.type} {fmtId(e.subject)} {e.state ? : '-'} {e.source}
)} ); } function summarizeMissions(data: MissionsResponse | null) { const summary = { active: 0, terminal: 0, awaiting: 0 }; for (const mission of data?.missions ?? []) { if (mission.status === 'awaiting-approval' || mission.status === 'input-required') summary.awaiting += 1; if (mission.terminal) summary.terminal += 1; else summary.active += 1; } return summary; }