Created comprehensive terminal testing tool with two modes: 1. Interactive REPL (recommended) - Persistent in-memory state 2. Standalone CLI commands - Config file persistence Features: - Interactive REPL using Python cmd module - Persistent event loop prevents DB connection issues - 11 commands for full game control (new_game, defensive, offensive, resolve, etc.) - Beautiful Rich formatting with colors and panels - Auto-generated test lineups for rapid testing - Direct GameEngine access (no WebSocket overhead) - Config file (~/.terminal_client_config.json) for state persistence Files added: - terminal_client/repl.py (525 lines) - Interactive REPL - terminal_client/main.py (516 lines) - Click standalone commands - terminal_client/display.py (218 lines) - Rich formatting - terminal_client/config.py (89 lines) - Persistent config - terminal_client/__main__.py - Dual mode entry point - terminal_client/CLAUDE.md (725 lines) - Full documentation Updated: - backend/CLAUDE.md - Added terminal client to testing section - requirements.txt - Added rich==13.9.4 Perfect for rapid iteration on game engine without building frontend! 🚀 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
96 lines
2.6 KiB
Python
96 lines
2.6 KiB
Python
"""
|
|
Configuration management for terminal client.
|
|
|
|
Handles persistent state across command invocations using a config file.
|
|
|
|
Author: Claude
|
|
Date: 2025-10-26
|
|
"""
|
|
import logging
|
|
import json
|
|
from pathlib import Path
|
|
from uuid import UUID
|
|
from typing import Optional
|
|
|
|
logger = logging.getLogger(f'{__name__}.config')
|
|
|
|
# Config file location in user's home directory
|
|
CONFIG_FILE = Path.home() / '.terminal_client_config.json'
|
|
|
|
|
|
class Config:
|
|
"""Persistent configuration manager for terminal client."""
|
|
|
|
@staticmethod
|
|
def _ensure_config_exists() -> None:
|
|
"""Create config file if it doesn't exist."""
|
|
if not CONFIG_FILE.exists():
|
|
CONFIG_FILE.write_text('{}')
|
|
logger.debug(f"Created config file: {CONFIG_FILE}")
|
|
|
|
@staticmethod
|
|
def get_current_game() -> Optional[UUID]:
|
|
"""
|
|
Get the current game ID from config file.
|
|
|
|
Returns:
|
|
UUID of current game, or None if not set
|
|
"""
|
|
Config._ensure_config_exists()
|
|
|
|
try:
|
|
data = json.loads(CONFIG_FILE.read_text())
|
|
game_id_str = data.get('current_game_id')
|
|
|
|
if game_id_str:
|
|
return UUID(game_id_str)
|
|
return None
|
|
|
|
except (json.JSONDecodeError, ValueError) as e:
|
|
logger.warning(f"Failed to read config: {e}")
|
|
return None
|
|
|
|
@staticmethod
|
|
def set_current_game(game_id: UUID) -> None:
|
|
"""
|
|
Set the current game ID in config file.
|
|
|
|
Args:
|
|
game_id: UUID of game to set as current
|
|
"""
|
|
Config._ensure_config_exists()
|
|
|
|
try:
|
|
# Read existing config
|
|
data = json.loads(CONFIG_FILE.read_text())
|
|
|
|
# Update current game
|
|
data['current_game_id'] = str(game_id)
|
|
|
|
# Write back
|
|
CONFIG_FILE.write_text(json.dumps(data, indent=2))
|
|
logger.debug(f"Set current game to: {game_id}")
|
|
|
|
except (json.JSONDecodeError, IOError) as e:
|
|
logger.error(f"Failed to write config: {e}")
|
|
raise
|
|
|
|
@staticmethod
|
|
def clear_current_game() -> None:
|
|
"""Clear the current game ID from config file."""
|
|
Config._ensure_config_exists()
|
|
|
|
try:
|
|
data = json.loads(CONFIG_FILE.read_text())
|
|
data.pop('current_game_id', None)
|
|
CONFIG_FILE.write_text(json.dumps(data, indent=2))
|
|
logger.debug("Cleared current game")
|
|
|
|
except (json.JSONDecodeError, IOError) as e:
|
|
logger.warning(f"Failed to clear config: {e}")
|
|
|
|
@staticmethod
|
|
def get_config_path() -> Path:
|
|
"""Get the path to the config file."""
|
|
return CONFIG_FILE
|