- 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>
219 lines
6.0 KiB
Python
219 lines
6.0 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
Major Domo CLI - Schedule Operations
|
|
|
|
Commands for listing and filtering game schedules.
|
|
"""
|
|
|
|
from typing import Annotated, Optional
|
|
|
|
import typer
|
|
from cli_common import (
|
|
state,
|
|
console,
|
|
output_json,
|
|
output_table,
|
|
handle_error,
|
|
get_season,
|
|
safe_nested,
|
|
)
|
|
|
|
schedule_app = typer.Typer(
|
|
help="Schedule operations",
|
|
invoke_without_command=True,
|
|
no_args_is_help=False,
|
|
)
|
|
|
|
|
|
@schedule_app.callback()
|
|
def schedule_callback(
|
|
ctx: typer.Context,
|
|
team: Annotated[
|
|
Optional[str], typer.Option("--team", "-t", help="Filter by team abbreviation")
|
|
] = None,
|
|
week: Annotated[
|
|
Optional[int], typer.Option("--week", "-w", help="Filter by specific week")
|
|
] = None,
|
|
week_start: Annotated[
|
|
Optional[int], typer.Option("--week-start", help="Start week for range")
|
|
] = None,
|
|
week_end: Annotated[
|
|
Optional[int], typer.Option("--week-end", help="End week for range")
|
|
] = None,
|
|
season: Annotated[
|
|
Optional[int], typer.Option("--season", "-s", help="Season number")
|
|
] = None,
|
|
limit: Annotated[
|
|
int, typer.Option("--limit", "-n", help="Max results to display")
|
|
] = 50,
|
|
):
|
|
"""
|
|
List game schedules with optional filters.
|
|
|
|
By default, shows recent schedules for the current season.
|
|
Use filters to narrow down results.
|
|
|
|
Examples:
|
|
majordomo schedule --team CAR
|
|
majordomo schedule --week 5
|
|
majordomo schedule --week-start 1 --week-end 4
|
|
"""
|
|
# Only invoke if no subcommand was called
|
|
if ctx.invoked_subcommand is not None:
|
|
return
|
|
|
|
try:
|
|
season = get_season(season)
|
|
|
|
# Handle week vs week_start/week_end
|
|
if week is not None:
|
|
week_start = week
|
|
week_end = week
|
|
|
|
# Get schedules from API using low-level get method
|
|
result = state.api.get(
|
|
"schedules",
|
|
season=season,
|
|
team_abbrev=team,
|
|
week_start=week_start,
|
|
week_end=week_end,
|
|
short_output=False,
|
|
)
|
|
schedules = result.get("schedules", [])
|
|
|
|
# Limit results
|
|
schedules = schedules[:limit]
|
|
|
|
if state.json_output:
|
|
output_json(schedules)
|
|
return
|
|
|
|
if not schedules:
|
|
console.print(
|
|
f"[yellow]No schedules found for the given filters (Season {season})[/yellow]"
|
|
)
|
|
return
|
|
|
|
# Build table rows
|
|
rows = []
|
|
for s in schedules:
|
|
away_abbrev = safe_nested(s, "away_team", "abbrev")
|
|
home_abbrev = safe_nested(s, "home_team", "abbrev")
|
|
|
|
rows.append(
|
|
[
|
|
s.get("week", ""),
|
|
s.get("game_num", ""),
|
|
away_abbrev,
|
|
"@",
|
|
home_abbrev,
|
|
]
|
|
)
|
|
|
|
# Build title with filters
|
|
title_parts = [f"Schedule (Season {season})"]
|
|
if team:
|
|
title_parts.append(f"Team: {team}")
|
|
if week:
|
|
title_parts.append(f"Week {week}")
|
|
elif week_start and week_end:
|
|
title_parts.append(f"Weeks {week_start}-{week_end}")
|
|
|
|
title = " | ".join(title_parts)
|
|
|
|
output_table(title, ["Week", "Gm", "Away", "@", "Home"], rows)
|
|
|
|
except Exception as e:
|
|
handle_error(e)
|
|
|
|
|
|
@schedule_app.command("list")
|
|
def schedule_list(
|
|
team: Annotated[
|
|
Optional[str], typer.Option("--team", "-t", help="Filter by team abbreviation")
|
|
] = None,
|
|
week: Annotated[
|
|
Optional[int], typer.Option("--week", "-w", help="Filter by specific week")
|
|
] = None,
|
|
week_start: Annotated[
|
|
Optional[int], typer.Option("--week-start", help="Start week for range")
|
|
] = None,
|
|
week_end: Annotated[
|
|
Optional[int], typer.Option("--week-end", help="End week for range")
|
|
] = None,
|
|
season: Annotated[
|
|
Optional[int], typer.Option("--season", "-s", help="Season number")
|
|
] = None,
|
|
limit: Annotated[
|
|
int, typer.Option("--limit", "-n", help="Max results to display")
|
|
] = 50,
|
|
):
|
|
"""
|
|
List game schedules with optional filters (explicit command).
|
|
|
|
This is the same as calling 'majordomo schedule' without a subcommand.
|
|
"""
|
|
try:
|
|
season = get_season(season)
|
|
|
|
# Handle week vs week_start/week_end
|
|
if week is not None:
|
|
week_start = week
|
|
week_end = week
|
|
|
|
# Get schedules from API using low-level get method
|
|
result = state.api.get(
|
|
"schedules",
|
|
season=season,
|
|
team_abbrev=team,
|
|
week_start=week_start,
|
|
week_end=week_end,
|
|
short_output=False,
|
|
)
|
|
schedules = result.get("schedules", [])
|
|
|
|
# Limit results
|
|
schedules = schedules[:limit]
|
|
|
|
if state.json_output:
|
|
output_json(schedules)
|
|
return
|
|
|
|
if not schedules:
|
|
console.print(
|
|
f"[yellow]No schedules found for the given filters (Season {season})[/yellow]"
|
|
)
|
|
return
|
|
|
|
# Build table rows
|
|
rows = []
|
|
for s in schedules:
|
|
away_abbrev = safe_nested(s, "away_team", "abbrev")
|
|
home_abbrev = safe_nested(s, "home_team", "abbrev")
|
|
|
|
rows.append(
|
|
[
|
|
s.get("week", ""),
|
|
s.get("game_num", ""),
|
|
away_abbrev,
|
|
"@",
|
|
home_abbrev,
|
|
]
|
|
)
|
|
|
|
# Build title with filters
|
|
title_parts = [f"Schedule (Season {season})"]
|
|
if team:
|
|
title_parts.append(f"Team: {team}")
|
|
if week:
|
|
title_parts.append(f"Week {week}")
|
|
elif week_start and week_end:
|
|
title_parts.append(f"Weeks {week_start}-{week_end}")
|
|
|
|
title = " | ".join(title_parts)
|
|
|
|
output_table(title, ["Week", "Gm", "Away", "@", "Home"], rows)
|
|
|
|
except Exception as e:
|
|
handle_error(e)
|