{ "timestamp": "2026-04-07T11:54:55.731Z", "code": "import { readFile } from 'node:fs/promises';\n\nasync function inspectChessUI() {\n const filesToRead = [\n 'panel/src/games/chess/ChessGame.tsx',\n 'panel/src/games/chess/pieces.tsx',\n 'bot/lib/embeds.ts'\n ];\n\n for (const file of filesToRead) {\n try {\n console.log(`\\n--- Reading ${file} ---`);\n const content = await readFile(file, 'utf8');\n console.log(content.substring(0, 3000) + \"\\n... [truncated]\");\n } catch (e) {\n console.error(`Could not read ${file}:`, e.message);\n }\n }\n}\n\ninspectChessUI();\n", "output": "\n--- Reading panel/src/games/chess/ChessGame.tsx ---\nimport { useState, useEffect, useCallback, useMemo, useRef } from \"react\";\nimport { Chessboard } from \"react-chessboard\";\nimport { Chess } from \"chess.js\";\nimport type { Square } from \"chess.js\";\nimport type { GameUIProps } from \"../registry\";\nimport { Flag, Handshake, X, Check, Clock } from \"lucide-react\";\nimport { chessPieces } from \"./pieces\";\n\n// ── Types matching server ChessPlayerView / ChessSpectatorView ──\n\ninterface ChessClockView {\n white: number;\n black: number;\n increment: number;\n activeColor: \"white\" | \"black\" | null;\n}\n\ninterface ChessViewBase {\n fen: string;\n pgn: string;\n turn: \"white\" | \"black\";\n clock: ChessClockView | null;\n drawOffer: \"white\" | \"black\" | null;\n result: \"white\" | \"black\" | \"draw\" | null;\n resultReason: string | null;\n moveHistory: { from: string; to: string; san: string; color: \"w\" | \"b\" }[];\n isCheck: boolean;\n}\n\ninterface PlayerView extends ChessViewBase {\n myColor: \"white\" | \"black\";\n legalMoves: { from: string; to: string; promotion?: string }[];\n}\n\ninterface SpectatorView extends ChessViewBase {\n players: { white: string; black: string };\n}\n\nfunction isPlayerView(state: unknown): state is PlayerView {\n return typeof state === \"object\" && state !== null && \"myColor\" in state;\n}\n\n// ── Clock Display ──\n\nfunction formatTime(ms: number): string {\n if (ms <= 0) return \"0:00\";\n const totalSeconds = Math.ceil(ms / 1000);\n const minutes = Math.floor(totalSeconds / 60);\n const seconds = totalSeconds % 60;\n if (minutes >= 60) {\n const hours = Math.floor(minutes / 60);\n const mins = minutes % 60;\n return `${hours}:${mins.toString().padStart(2, \"0\")}:${seconds.toString().padStart(2, \"0\")}`;\n }\n return `${minutes}:${seconds.toString().padStart(2, \"0\")}`;\n}\n\nfunction ChessClock({ time, isActive, isLow, label }: {\n time: number;\n isActive: boolean;\n isLow: boolean;\n label: string;\n}) {\n return (\n
\n \n {formatTime(time)}\n {label}\n
\n );\n}\n\n// ── Move History ──\n\nfunction MoveHistory({ moves, containerRef }: {\n moves: { san: string; color: \"w\" | \"b\" }[];\n containerRef: React.RefObject;\n}) {\n const pairs: { number: number; white?: string; black?: string }[] = [];\n for (let i = 0; i < moves.length; i++) {\n const moveNum = Math.floor(i / 2) + 1;\n if (i % 2 === 0) {\n pairs.push({ number: moveNum, white: moves[i]!.san });\n } else {\n const\n... [truncated]\n\n--- Reading panel/src/games/chess/pieces.tsx ---\n/**\n * Inline SVG chess pieces (cburnett set from Lichess, CC BY-SA).\n *\n * These are rendered as native JSX — not tags — so they live in\n * the same React/DOM tree as react-chessboard's Piece wrapper and don't\n * interfere with dnd-kit's pointer-event pipeline.\n */\n\nimport type { PieceRenderObject } from \"react-chessboard\";\n\ntype PieceProps = { svgStyle?: React.CSSProperties };\n\nfunction svg(children: React.ReactNode) {\n return (props?: PieceProps) => (\n \n {children}\n \n );\n}\n\nexport const chessPieces: PieceRenderObject = {\n // ── White ──\n\n wP: svg(\n \n ),\n\n wR: svg(\n \n \n \n \n \n \n \n ),\n\n wN: svg(\n \n \n \n \n \n ),\n\n wB: svg(\n \n \n \n \n \n \n \n \n ),\n\n wQ: svg(\n