import { useSession } from '@/store/session' import { useNodeFeed } from '@/lib/useNodeFeed' import { useTelemetry } from '@/lib/useTelemetry' import { useMatrixMirror } from '@/lib/useMatrixMirror' import { useClawd, GRID_W } from '@/lib/clawSprite' import { useSharedAgentChat } from '@/lib/AgentChatContext' import { WaveformCanvas } from './WaveformCanvas' import { RailAgent } from './RailAgent' import { AgentArchitectureStrip } from './AgentArchitecture' import type { NodeActivityKind } from '@/types' import { cn } from '@/lib/utils' /** * The persistent instrument rail (right pane of the cockpit). A dark "device * screen" — intentionally dark in both themes. Six sections: node heartbeat, * agent activity log, and ADD progress are wired to real state; the LED matrix, * I2C bus, and live acceleration come from the telemetry seam (`useTelemetry`), * which is a **simulated** source today (marked SIM) until the ADXL355 stream * lands. See the plan's WS3. */ const LOG_COLOR: Record = { thinking: 'text-rail-dim2', tool: 'text-rail-text2', flash: 'text-rail-blue', error: 'text-rail-spike', response: 'text-rail-green', fallback: 'text-[#d9a441]', } function RailSection({ label, light, children }: { label: string; light?: boolean; children: React.ReactNode }) { return (
{label}
{children}
) } export function CockpitRail({ variant = 'full' }: { variant?: 'full' | 'agent' } = {}) { const teamId = useSession((s) => s.teamId) const team = useSession((s) => s.team) const connected = useSession((s) => s.device.connected) const feed = useNodeFeed(teamId, connected) const tel = useTelemetry(connected) const online = connected && feed.online // On the "agent" rail (Meet your agent) the matrix shows Clawd, the crab — // not a board mirror — driven by the live chat status, so we skip the mirror // poll and animate the sprite instead. const agentView = variant === 'agent' const chat = useSharedAgentChat() const claw = useClawd(chat.status) // Pixel-perfect mirror of the physical matrix (real board frame). Falls back // to the sim frame until the first real frame arrives. const mirror = useMatrixMirror(teamId, online && !agentView) const matrixDots = agentView ? claw.dots : mirror ?? tel.matrix const matrixLive = mirror != null const matrixCols = agentView ? GRID_W : 13 // Clawd flashes green on a reply; the board mirror stays ASCII-orange. const litColor = agentView && claw.color === 'green' ? 'oklch(0.82 0.17 152)' : 'oklch(0.7 0.2 34)' // Prefer the name the team gave their agent at registration. const nodeName = team.agentName?.trim() ? team.agentName.trim() : team.name ? team.name.toLowerCase().replace(/\s+/g, '-') : 'crimson-node' const log = feed.activity.slice(0, 6) // The agent rail is theme-aware (light in light mode); the instrument rail // stays a fixed-dark device screen. The LED matrix itself is a screen either way. const label = agentView ? 'text-ink-3' : 'text-rail-dim' return ( ) }