'use client'; import { useEffect, useMemo, useState } from 'react'; import Link from 'next/link'; import { ArrowRight, BadgeCheck, BellRing, Bot, CheckCircle2, Clock3, LayoutDashboard, OctagonAlert, Rocket, ShieldAlert, Sparkles, TriangleAlert } from 'lucide-react'; import { Badge, Button } from '@/components/ui/Primitives'; import { HermesShell, MetricCard, SectionCard } from '@/components/hermes-shell'; import { HermesInstanceBadge } from '@/components/hermes-instance-switcher'; import { HermesOpsPanel } from '@/components/hermes-ops-panel'; import { useHermesInstance } from '@/lib/hermes-instance-context'; import { getHermesAgents, getHermesOverview, getHermesProducts, getHermesTasks, hermesProducts, hermesTasks, HERMES_INSTANCES, type HermesProduct, type HermesTask, } from '@/lib/hermes'; import { collectBackupEntries, collectCronEntries, collectWatchdogAlerts, emptyTelemetryState, loadAllHermesTelemetry, telemetryForFilter, type HermesTelemetryState, } from '@/lib/hermes-telemetry-client'; const fmtDate = new Intl.DateTimeFormat('en', { month: 'short', day: 'numeric', hour: 'numeric', minute: '2-digit', }); const statusTone: Record = { running: 'info', idle: 'neutral', degraded: 'warning', error: 'error', queued: 'neutral', blocked: 'warning', failed: 'error', completed: 'success', }; function taskStatusLabel(task: HermesTask) { return task.status.replace('-', ' '); } function getTaskTone(task: HermesTask) { return statusTone[task.status] ?? 'neutral'; } function ProductMiniCard({ product }: { product: HermesProduct }) { const healthColor = product.healthScore >= 85 ? 'bg-[var(--bl-success)]' : product.healthScore >= 70 ? 'bg-[var(--bl-warning)]' : 'bg-[var(--bl-danger)]'; return (

{product.name}

{product.category} · {product.priority}

{product.needsAttention ? 'Attention' : 'Healthy'}
Health {product.healthScore}/100
{product.tags.slice(0, 3).map((tag) => ( {tag} ))}
); } export default function HermesMissionControlPage() { const { selectedInstance } = useHermesInstance(); const [telemetry, setTelemetry] = useState(emptyTelemetryState); const [telemetryError, setTelemetryError] = useState(null); const overview = useMemo(() => getHermesOverview(selectedInstance), [selectedInstance]); // Per-instance roll-up cards always show both Vijay and Bheem regardless of // the active filter — they're the "comparison" view that sits next to the // filtered overview metrics. This satisfies the roadmap's "per-instance // cards AND a combined roll-up" requirement. const perInstance = useMemo( () => HERMES_INSTANCES.map((inst) => ({ ...inst, overview: getHermesOverview(inst.id) })), [], ); const activeTasks = useMemo( () => getHermesTasks({ status: 'running', instance: selectedInstance }) .concat(getHermesTasks({ status: 'blocked', instance: selectedInstance })) .concat(getHermesTasks({ status: 'queued', instance: selectedInstance })) .slice(0, 8), [selectedInstance], ); const attentionTasks = useMemo( () => getHermesTasks({ status: 'blocked', instance: selectedInstance }) .concat(getHermesTasks({ status: 'failed', instance: selectedInstance })) .slice(0, 8), [selectedInstance], ); const filteredProducts = useMemo( () => (selectedInstance === 'all' ? hermesProducts : hermesProducts.filter((p) => p.instanceId === selectedInstance)), [selectedInstance], ); const filteredTasks = useMemo( () => (selectedInstance === 'all' ? hermesTasks : hermesTasks.filter((t) => t.instanceId === selectedInstance)), [selectedInstance], ); const recentProducts = filteredProducts .filter((product) => product.lastHermesActivityAt) .sort((a, b) => new Date(b.lastHermesActivityAt!).getTime() - new Date(a.lastHermesActivityAt!).getTime()) .slice(0, 8); const completedToday = filteredTasks.filter((task) => task.completedAt && new Date(task.completedAt).getTime() > Date.now() - 86_400_000); const completedThisWeek = filteredTasks.filter((task) => task.completedAt && new Date(task.completedAt).getTime() > Date.now() - 7 * 86_400_000); const failedTasks = filteredTasks.filter((task) => task.status === 'failed'); const repeatedFailures = useMemo( () => getHermesProducts('repeated-failures', selectedInstance).slice(0, 5), [selectedInstance], ); const actionableProducts = filteredProducts.filter((product) => product.needsAttention).slice(0, 6); const agentStatuses = useMemo(() => getHermesAgents(selectedInstance), [selectedInstance]); const liveSnapshots = useMemo(() => telemetryForFilter(telemetry, selectedInstance), [telemetry, selectedInstance]); const liveAlerts = useMemo(() => collectWatchdogAlerts(telemetry, selectedInstance).slice(0, 8), [telemetry, selectedInstance]); const liveBackups = useMemo(() => collectBackupEntries(telemetry, selectedInstance).slice(0, 6), [telemetry, selectedInstance]); const liveCron = useMemo(() => collectCronEntries(telemetry, selectedInstance).slice(0, 6), [telemetry, selectedInstance]); useEffect(() => { let active = true; const load = async () => { try { const next = await loadAllHermesTelemetry(); if (!active) return; setTelemetry(next); setTelemetryError(null); } catch (err) { if (!active) return; setTelemetryError(err instanceof Error ? err.message : String(err)); } }; void load(); const timer = window.setInterval(load, 60_000); return () => { active = false; window.clearInterval(timer); }; }, []); const autoActions = [ 'Continue the queued execution lane for high-priority product updates.', 'Publish a weekly digest from completed and failed work.', 'Refresh the product health snapshot and attach evidence links.', ]; const founderActions = [ overview.nextRecommendedAction, 'Approve the blocked P0 work item before the release window closes.', 'Rotate the stale notification token so background alerts can resume.', ]; return ( )} >
} helpText={overview.lastAction} /> } helpText={`${overview.upcomingJobs} queued jobs waiting to run`} /> } helpText={`${overview.completedThisWeek} completed this week`} /> } helpText={overview.nextRecommendedAction} /> } helpText="Failure clusters are being tracked in the task ledger" /> } helpText="These items need a human decision or credential fix" /> } helpText="Average across completed tasks" /> } helpText={`${overview.productsTouchedRecently} products touched in the last 14 days`} />
Always cross-instance} >
{perInstance.map(({ id, label, description, overview: ov }) => (

{label}

{description}

{ov.status}
Active
{ov.activeTasks}
Blocked
{ov.blockedTasks}
Failed
{ov.failedTasks}
Success %
{ov.successRate}%
))}
{telemetryError ? 'Telemetry unavailable' : 'Live telemetry'}} > {telemetryError ? (

Could not load telemetry: {telemetryError}

) : (
{liveAlerts.length > 0 ? liveAlerts.map((alert) => (
{alert.severity} {fmtDate.format(new Date(alert.timestamp))}

{alert.message}

)) : (
No watchdog alerts were returned for the selected instance filter.
)}

Sessions

{liveSnapshots.map((snapshot) => (
{snapshot.sessions.totalSessions} sessions · {snapshot.sessions.totalMessages} messages
))}

Upcoming Hermes cron

{liveCron.length > 0 ? liveCron.map((entry) => (
{entry.name}
)) :

No cron entries returned.

}

Recent backup commits

{liveBackups.length > 0 ? liveBackups.map((entry) => (
{entry.subject}
)) :

No backup commits returned.

}
)}
View all tasks }>
{activeTasks.map((task) => { const product = hermesProducts.find((item) => item.id === task.productId); return (
{task.title} {taskStatusLabel(task)} {task.priority}

{product?.name ?? 'Unknown product'} · {task.assignedAgent} · {task.type}

Started {fmtDate.format(new Date(task.startedAt ?? task.createdAt))}

{task.currentStep ?? task.nextAction}

Progress {task.progressPercent}%
); })}
Needs decision}>
{attentionTasks.slice(0, 5).map((task) => (
{task.title}

{task.blockerReason ?? task.error ?? task.nextAction}

{task.status}
))} {actionableProducts.slice(0, 2).map((product) => (

{product.name}

{product.description}

Product attention
))}
Evidence-backed}>

Today

{completedToday.length}

Tasks completed or closed today.

This week

{completedThisWeek.length}

Shipped, repaired, or documented this week.

Last 30 days

{hermesTasks.length}

Tracked execution events across the portfolio.

{[ 'Fixed bugs and failure loops', 'Created PRs and commit-ready changes', 'Deployed services and validated health', 'Updated docs and audit summaries', ].map((item) => (
{item}
))}
Prioritized}>

Hermes can do automatically

{autoActions.map((item) => (
{item}
))}

Needs Saravana's decision

{founderActions.map((item) => (
{item}
))}
Open portfolio }>
{recentProducts.map((product) => ( ))}
Telemetry placeholder}>
{agentStatuses.map((agent) => (

{agent.name}

{agent.type} · {agent.callsToday} calls today

{agent.configIssue ?

{agent.configIssue}

: null}
{agent.status}
))}

Shipped this week

{completedThisWeek.length}

Failed this week

{failedTasks.filter((task) => task.completedAt ? new Date(task.completedAt).getTime() > Date.now() - 7 * 86_400_000 : true).length}

Repeated failure products

{repeatedFailures.length}

); }