"""Checklist service for retrieving and listing checklists.
Provides business logic for checklist operations.
"""
from __future__ import annotations
from typing import TYPE_CHECKING, Any
from sso_mcp_server import get_logger
from sso_mcp_server.checklists.discovery import discover_checklists
from sso_mcp_server.checklists.parser import parse_checklist_file
if TYPE_CHECKING:
from pathlib import Path
_logger = get_logger("checklist_service")
class ChecklistService:
"""Service for managing checklist operations.
Provides methods to get and list checklists from the configured directory.
"""
def __init__(self, checklist_dir: Path) -> None:
"""Initialize the checklist service.
Args:
checklist_dir: Directory containing checklist markdown files.
"""
self._checklist_dir = checklist_dir
_logger.debug("checklist_service_initialized", directory=str(checklist_dir))
def get_checklist(self, name: str) -> dict[str, Any] | None:
"""Get a checklist by name.
Performs case-insensitive matching against checklist names
(from frontmatter) and filenames (without extension).
Args:
name: Name of the checklist to retrieve.
Returns:
Dictionary with name, description, content, and path.
Returns None if checklist not found.
"""
_logger.debug("getting_checklist", name=name)
name_lower = name.lower()
for file_path in discover_checklists(self._checklist_dir):
parsed = parse_checklist_file(file_path)
if parsed is None:
continue
# Match by name from frontmatter
if parsed["name"].lower() == name_lower:
_logger.info("checklist_found", name=parsed["name"], path=str(file_path))
return parsed
# Match by filename (without extension)
if file_path.stem.lower() == name_lower:
_logger.info(
"checklist_found_by_filename",
name=parsed["name"],
path=str(file_path),
)
return parsed
_logger.debug("checklist_not_found", name=name)
return None
def list_checklists(self) -> list[dict[str, Any]]:
"""List all available checklists.
Returns metadata (name, description) for all checklists.
Does NOT include full content.
Returns:
List of dictionaries with name and description for each checklist.
"""
_logger.debug("listing_checklists")
checklists = []
for file_path in discover_checklists(self._checklist_dir):
parsed = parse_checklist_file(file_path)
if parsed is None:
continue
# Return metadata only, not content
checklists.append(
{
"name": parsed["name"],
"description": parsed.get("description", ""),
}
)
_logger.info("checklists_listed", count=len(checklists))
return checklists
def get_available_names(self) -> list[str]:
"""Get list of available checklist names.
Useful for error messages when a checklist is not found.
Returns:
List of checklist names.
"""
checklists = self.list_checklists()
return [c["name"] for c in checklists]