Files
aurorabot/.pico/history/2026-04-07T11-58-45-141Z-e47ac1e4.json
syntaxbullet 8369d10bab
Some checks failed
Deploy to Production / test (push) Failing after 33s
Add auth checks for user routes and dashboard state
- tighten route authorization and schema handling
- update user route tests and server coverage
- refresh player dashboard behavior
2026-04-09 20:42:32 +02:00

7 lines
6.2 KiB
JSON

{
"timestamp": "2026-04-07T11:58:45.141Z",
"code": "import { readFile } from 'node:fs/promises';\n\nasync function analyzeLayout() {\n const filePath = 'panel/src/games/chess/ChessGame.tsx';\n try {\n const content = await readFile(filePath, 'utf8');\n \n // We want to look at the return statement of the main component \n // and how it uses Tailwind classes for layout.\n const returnMatch = content.match(/return\\s*\\(([\\s\\S]*?)\\);/);\n \n if (returnMatch) {\n console.log(\"--- Found Layout JSX ---\");\n // We'll print a slightly larger chunk around the return to see the container structure\n const startIdx = returnMatch.index!;\n const endIdx = startIdx + 5000; // Look at next 5000 chars\n console.log(content.substring(startIdx, endIdx));\n } else {\n console.log(\"Could not find the return statement in JSX.\");\n // Fallback to printing the whole thing if regex fails\n console.log(content);\n }\n\n } catch (e) {\n console.error(\"Error analyzing layout:\", e);\n }\n}\n\nanalyzeLayout();\n",
"output": "--- Found Layout JSX ---\nreturn (\n <div className={`flex items-center gap-2 px-3 py-2 rounded-lg font-mono text-lg transition-colors ${\n isActive\n ? isLow\n ? \"bg-destructive/15 text-destructive\"\n : \"bg-primary/15 text-primary\"\n : \"bg-card text-text-tertiary\"\n }`}>\n <Clock className=\"w-4 h-4 opacity-60\" />\n <span className=\"font-semibold tabular-nums\">{formatTime(time)}</span>\n <span className=\"text-xs opacity-50 font-label\">{label}</span>\n </div>\n );\n}\n\n// ── Move History ──\n\nfunction MoveHistory({ moves, containerRef }: {\n moves: { san: string; color: \"w\" | \"b\" }[];\n containerRef: React.RefObject<HTMLDivElement | null>;\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 pair = pairs[pairs.length - 1];\n if (pair) pair.black = moves[i]!.san;\n }\n }\n\n useEffect(() => {\n if (containerRef.current) {\n containerRef.current.scrollTop = containerRef.current.scrollHeight;\n }\n }, [moves.length]);\n\n if (pairs.length === 0) {\n return (\n <div className=\"text-xs text-text-disabled text-center py-4\">\n No moves yet\n </div>\n );\n }\n\n return (\n <div className=\"grid grid-cols-[auto_1fr_1fr] gap-x-2 gap-y-0.5 text-sm\">\n {pairs.map(p => (\n <div key={p.number} className=\"contents\">\n <span className=\"text-text-disabled text-xs tabular-nums pr-1\">{p.number}.</span>\n <span className={`font-mono ${p.white ? \"text-foreground\" : \"\"}`}>{p.white ?? \"\"}</span>\n <span className={`font-mono ${p.black ? \"text-foreground\" : \"\"}`}>{p.black ?? \"\"}</span>\n </div>\n ))}\n </div>\n );\n}\n\n// ── Main Component ──\n\nexport function ChessGame({ state, myPlayerId, isSpectator, onAction, players }: GameUIProps) {\n const view = state as PlayerView | SpectatorView;\n const playerView = isPlayerView(state) ? state as PlayerView : null;\n const myColor = playerView?.myColor ?? \"white\";\n // Solo mode: both players are the same user — myColor flips each turn, so lock orientation to white\n const isSoloMode = !isSpectator && players.length === 2 && players[0]?.discordId === players[1]?.discordId;\n const boardOrientation = isSpectator || isSoloMode ? \"white\" : myColor;\n const isMyTurn = playerView ? view.turn === playerView.myColor : false;\n const isGameOver = view.result !== null;\n const moveHistoryRef = useRef<HTMLDivElement>(null);\n\n // Selected square for click-to-move\n const [selectedSquare, setSelectedSquare] = useState<Square | null>(null);\n const [promotionSquare, setPromotionSquare] = useState<{ from: Square; to: Square } | null>(null);\n\n // Live clock state (client-side countdown for smooth display)\n const [liveClock, setLiveClock] = useState(view.clock);\n const lastServerClock = useRef(view.clock);\n\n // Sync from server\n useEffect(() => {\n lastServerClock.current = view.clock;\n setLiveClock(view.clock);\n }, [view.clock?.white, view.clock?.black, view.clock?.activeColor]);\n\n // Client-side clock tick (100ms intervals for smooth countdown)\n useEffect(() => {\n if (!liveClock || !liveClock.activeColor || isGameOver) return;\n\n const interval = setInterval(() => {\n setLiveClock(prev => {\n if (!prev || !prev.activeColor) return prev;\n const active = prev.activeColor;\n const remaining = Math.max(0, prev[active] - 100);\n if (remaining <= 0 && !isSpectator && active !== myColor) {\n // Opponent ran out — claim timeout\n onAction({ type: \"claim_timeout\" });\n }\n return { ...prev, [active]: remaining };\n });\n }, 100);\n\n return () => clearInterval(interval);\n }, [liveClock?.activeColor, isGameOver, isSpectator, myColor, onAction]);\n\n // Compute legal move squares for highlighting\n const legalMovesForSquare = useMemo(() => {\n if (!playerView || !selectedSquare || isGameOver || !isMyTurn) return [];\n return playerView.legalMoves\n .filter(m => m.from === selectedSquare)\n .map(m => m.to);\n }, [playerView, selectedSquare, isGameOver, isMyTurn]);\n\n // Build custom square styles\n const customSquareStyles = useMemo(() => {\n const styles: Record<string, React.CSSProperties> = {};\n\n // Highlight selected square\n if (selectedSquare) {\n styles[selectedSquare] = {\n backgroundColor: \"rgba(233, 195, 73, 0.35)\",\n };\n }\n\n // \n",
"exitCode": 0,
"durationMs": 19
}