15f6a6c713
Add operator health checks (make doctor) wrapping platform CLIs, and the fixtures-only daily board skill library with unit tests (make verify).
102 lines
2.8 KiB
Python
102 lines
2.8 KiB
Python
#!/usr/bin/env python3
|
|
"""Build a daily board from scheduling fixtures.
|
|
|
|
Usage:
|
|
python build_board.py [--fixtures PATH] [--date YYYY-MM-DD] [--salon NAME] [--format text|json]
|
|
|
|
All data is labeled as fixture/offline — never silent fake live data.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import argparse
|
|
import json
|
|
import pathlib
|
|
import sys
|
|
|
|
# Ensure the _lib package is importable regardless of cwd.
|
|
_REPO_ROOT = pathlib.Path(__file__).resolve().parents[3]
|
|
sys.path.insert(0, str(_REPO_ROOT / "skills" / "_lib"))
|
|
|
|
from lumina_skills.providers.scheduling.fixture_provider import (
|
|
load_fixtures,
|
|
load_fixture_metadata,
|
|
)
|
|
from lumina_skills.board_builder import build_board, format_board_text
|
|
|
|
# Default fixture: Claire Bennett sample day.
|
|
_DEFAULT_FIXTURE = _REPO_ROOT / "data" / "fixtures" / "scheduling" / "claire_bennett_2026-07-28.json"
|
|
|
|
|
|
def main() -> int:
|
|
parser = argparse.ArgumentParser(
|
|
description="Build a daily salon board from fixture data.",
|
|
)
|
|
parser.add_argument(
|
|
"--fixtures",
|
|
type=pathlib.Path,
|
|
default=_DEFAULT_FIXTURE,
|
|
help="Path to fixture JSON file (default: Claire Bennett sample day).",
|
|
)
|
|
parser.add_argument(
|
|
"--date",
|
|
type=str,
|
|
default=None,
|
|
help="Override board date (YYYY-MM-DD). Defaults to fixture date.",
|
|
)
|
|
parser.add_argument(
|
|
"--salon",
|
|
type=str,
|
|
default=None,
|
|
help="Override salon name. Defaults to fixture salon_name.",
|
|
)
|
|
parser.add_argument(
|
|
"--format",
|
|
choices=["text", "json"],
|
|
default="text",
|
|
help="Output format (default: text).",
|
|
)
|
|
args = parser.parse_args()
|
|
|
|
# Load fixture data.
|
|
try:
|
|
appointments = load_fixtures(args.fixtures)
|
|
except FileNotFoundError as exc:
|
|
print(f"Error: {exc}", file=sys.stderr)
|
|
return 1
|
|
except (json.JSONDecodeError, KeyError, ValueError) as exc:
|
|
print(f"Error parsing fixture: {exc}", file=sys.stderr)
|
|
return 1
|
|
|
|
# Load metadata for defaults.
|
|
try:
|
|
meta = load_fixture_metadata(args.fixtures)
|
|
except (json.JSONDecodeError, KeyError, TypeError, ValueError) as exc:
|
|
print(f"Warning: could not parse fixture metadata: {exc}", file=sys.stderr)
|
|
meta = {}
|
|
|
|
date = args.date or meta.get("date", "unknown")
|
|
salon_name = args.salon or meta.get("salon_name", "Unknown Salon")
|
|
business_hours = meta.get("business_hours")
|
|
|
|
# Build the board.
|
|
board = build_board(
|
|
appointments=appointments,
|
|
date=date,
|
|
salon_name=salon_name,
|
|
source="fixtures",
|
|
business_hours=business_hours,
|
|
)
|
|
|
|
# Output.
|
|
if args.format == "json":
|
|
print(json.dumps(board.to_dict(), indent=2))
|
|
else:
|
|
print(format_board_text(board))
|
|
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
raise SystemExit(main())
|