claude-configs/skills/major-domo/cli_admin.py
Cal Corum 43d32e9b9d Update major-domo skill CLI refactor and plugin/config updates
- Refactor major-domo skill: api_client.py, cli.py, and CLI modules (admin, common, injuries, results, schedule, transactions) with significant simplification (-275 lines net)
- Update CLI_REFERENCE.md and SKILL.md docs for major-domo
- Update create-scheduled-task SKILL.md
- Update plugins blocklist.json and known_marketplaces.json
- Add patterns/ directory to repo
- Update CLAUDE.md

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-09 02:00:41 -05:00

249 lines
7.6 KiB
Python

#!/usr/bin/env python3
"""
Major Domo CLI - Admin Operations
Privileged operations: standings recalculation, stats refresh.
Each command performs the write operation then fetches fresh data to confirm.
"""
from typing import Annotated, Optional
import typer
from cli_common import (
console,
state,
output_json,
output_table,
handle_error,
get_season,
safe_nested,
)
from cli_stats import _format_rate_stat, _outs_to_ip
admin_app = typer.Typer(help="Admin operations (standings recalculate, stats refresh)")
def _show_standings(season: int):
"""Fetch and display standings after recalculation"""
standings_data = state.api.get_standings(season=season)
if not standings_data:
console.print(f"[yellow]No standings found for season {season}[/yellow]")
return
rows = []
for s in standings_data:
abbrev = safe_nested(s, "team", "abbrev")
name = safe_nested(s, "team", "lname")
wins = s.get("wins", 0)
losses = s.get("losses", 0)
total = wins + losses
pct = f".{int(wins / total * 1000):03d}" if total > 0 else ".000"
rd = s.get("run_diff", 0)
rd_str = f"+{rd}" if rd > 0 else str(rd)
rows.append([abbrev, name, wins, losses, pct, rd_str])
output_table(
f"Standings - Season {season} (Recalculated)",
["Team", "Name", "W", "L", "PCT", "RD"],
rows,
)
def _show_batting_preview(season: int, count: int):
"""Fetch and display top 5 batting leaders after refresh"""
stats = state.api.get_season_batting_stats(
season=season, sort_by="woba", sort_order="desc", limit=5, min_pa=50
)
if not stats:
return
rows = []
for rank, s in enumerate(stats, 1):
rows.append(
[
rank,
s.get("name", "N/A"),
s.get("player_team_abbrev", "N/A"),
s.get("pa", 0),
_format_rate_stat(s.get("avg")),
_format_rate_stat(s.get("obp")),
_format_rate_stat(s.get("slg")),
_format_rate_stat(s.get("woba")),
]
)
console.print()
output_table(
f"Top 5 by wOBA (min 50 PA) - {count} players refreshed",
["#", "Name", "Team", "PA", "AVG", "OBP", "SLG", "wOBA"],
rows,
)
def _show_pitching_preview(season: int, count: int):
"""Fetch and display top 5 pitching leaders after refresh"""
stats = state.api.get_season_pitching_stats(
season=season, sort_by="era", sort_order="asc", limit=5, min_outs=50
)
if not stats:
return
rows = []
for rank, s in enumerate(stats, 1):
rows.append(
[
rank,
s.get("name", "N/A"),
s.get("player_team_abbrev", "N/A"),
_outs_to_ip(s.get("outs", 0)),
_format_rate_stat(s.get("era"), decimals=2),
_format_rate_stat(s.get("whip"), decimals=2),
s.get("so", 0),
]
)
console.print()
output_table(
f"Top 5 by ERA (min 50 outs) - {count} players refreshed",
["#", "Name", "Team", "IP", "ERA", "WHIP", "SO"],
rows,
)
@admin_app.command("recalculate-standings")
def recalculate_standings(
season: Annotated[
Optional[int], typer.Option("--season", "-s", help="Season number")
] = None,
):
"""Recalculate standings from game results for a season"""
try:
season = get_season(season)
console.print(
f"[yellow]Recalculating standings for season {season}...[/yellow]"
)
result = state.api.recalculate_standings(season)
console.print(f"[green]Done:[/green] {result}")
if state.json_output:
standings_data = state.api.get_standings(season=season)
output_json(
{"message": result, "season": season, "standings": standings_data}
)
return
_show_standings(season)
except Exception as e:
handle_error(e)
@admin_app.command("refresh-batting")
def refresh_batting(
season: Annotated[
Optional[int], typer.Option("--season", "-s", help="Season number")
] = None,
):
"""Refresh season batting stats materialized view"""
try:
season = get_season(season)
console.print(
f"[yellow]Refreshing batting stats for season {season}...[/yellow]"
)
result = state.api.refresh_batting_stats(season)
players = result.get("players_updated", 0)
console.print(
f"[green]Done:[/green] {result.get('message', 'Batting stats refreshed')} "
f"({players} players updated)"
)
if state.json_output:
top_stats = state.api.get_season_batting_stats(
season=season, sort_by="woba", sort_order="desc", limit=5, min_pa=50
)
result["top_5_woba"] = top_stats
output_json(result)
return
_show_batting_preview(season, players)
except Exception as e:
handle_error(e)
@admin_app.command("refresh-pitching")
def refresh_pitching(
season: Annotated[
Optional[int], typer.Option("--season", "-s", help="Season number")
] = None,
):
"""Refresh season pitching stats materialized view"""
try:
season = get_season(season)
console.print(
f"[yellow]Refreshing pitching stats for season {season}...[/yellow]"
)
result = state.api.refresh_pitching_stats(season)
players = result.get("players_updated", 0)
console.print(
f"[green]Done:[/green] {result.get('message', 'Pitching stats refreshed')} "
f"({players} players updated)"
)
if state.json_output:
top_stats = state.api.get_season_pitching_stats(
season=season, sort_by="era", sort_order="asc", limit=5, min_outs=50
)
result["top_5_era"] = top_stats
output_json(result)
return
_show_pitching_preview(season, players)
except Exception as e:
handle_error(e)
@admin_app.command("refresh-stats")
def refresh_stats(
season: Annotated[
Optional[int], typer.Option("--season", "-s", help="Season number")
] = None,
):
"""Refresh both batting and pitching stats materialized views"""
try:
season = get_season(season)
console.print(f"[yellow]Refreshing all stats for season {season}...[/yellow]")
batting_result = state.api.refresh_batting_stats(season)
bat_count = batting_result.get("players_updated", 0)
console.print(f" Batting: {bat_count} players refreshed")
pitching_result = state.api.refresh_pitching_stats(season)
pit_count = pitching_result.get("players_updated", 0)
console.print(f" Pitching: {pit_count} players refreshed")
console.print(f"[green]Done![/green]")
if state.json_output:
top_batting = state.api.get_season_batting_stats(
season=season, sort_by="woba", sort_order="desc", limit=5, min_pa=50
)
top_pitching = state.api.get_season_pitching_stats(
season=season, sort_by="era", sort_order="asc", limit=5, min_outs=50
)
output_json(
{
"batting": {**batting_result, "top_5_woba": top_batting},
"pitching": {**pitching_result, "top_5_era": top_pitching},
}
)
return
_show_batting_preview(season, bat_count)
_show_pitching_preview(season, pit_count)
except Exception as e:
handle_error(e)