"""
Modular CLI commands for Continuity.
Routes commands to specialized modules for better organization.
"""
import sys
from typing import Any, List, Optional
[docs]
class UserError(Exception):
"""User-friendly error with helpful suggestions."""
def __init__(self, message: str, suggestion: Optional[str] = None):
self.message = message
self.suggestion = suggestion
super().__init__(message)
[docs]
def parse_message_refs(ref: str, max_messages: int = 10) -> List[int]:
"""Parse message references supporting ranges, lists, and 'all'."""
refs: List[int] = []
if ref.lower() == "all":
return list(range(1, max_messages + 1))
# Split by commas for list notation
parts = [part.strip() for part in ref.split(",")]
for part in parts:
if "-" in part:
# Range notation like "1-4"
try:
start_str, end_str = part.split("-", 1)
start = int(start_str.strip())
end = int(end_str.strip())
if start < 1 or end > max_messages or start > end:
raise UserError(
f"Invalid range '{part}' (messages 1-{max_messages} available)",
"Use ranges like '1-3' or lists like '1,3,5'",
)
refs.extend(range(start, end + 1))
except ValueError as e:
raise UserError(
f"Invalid range format '{part}'",
"Use ranges like '1-3' or single numbers like '2'",
) from e
else:
# Single number
try:
num = int(part)
if 1 <= num <= max_messages:
refs.append(num)
else:
raise UserError(
f"Message {num} not found (only messages 1-{max_messages} available)",
"Use 'continuity check' to see available messages",
)
except ValueError as e:
raise UserError(
f"'{part}' is not a valid message number",
"Message numbers are like 1, 2, 3... Use 'continuity check' to see messages",
) from e
return sorted(set(refs)) # Remove duplicates and sort
[docs]
def validate_message_ref(ref: str, max_messages: int = 10) -> int:
"""Validate and normalize message reference to number (legacy single reference)."""
refs = parse_message_refs(ref, max_messages)
if len(refs) != 1:
raise UserError(
f"Expected single message reference, got {len(refs)} messages",
"Use a single number like '2' for this command",
)
return refs[0]
[docs]
def handle_user_error(func):
"""Decorator to handle UserError exceptions gracefully."""
import functools
from rich.console import Console
console = Console()
@functools.wraps(func)
def wrapper(*args, **kwargs):
try:
return func(*args, **kwargs)
except UserError as e:
console.print(f"[red]Error:[/red] {e.message}")
if e.suggestion:
console.print(f"[yellow]Tip:[/yellow] {e.suggestion}")
sys.exit(1)
except Exception as e:
console.print(f"[red]Unexpected error:[/red] {e}")
console.print("[dim]Use --help for usage information[/dim]")
sys.exit(1)
return wrapper
[docs]
def register_commands(cli_group: Any) -> None:
"""Register all CLI commands by importing and calling modular registration functions."""
# Import and register message commands
from .command_modules.message import register_message_commands
register_message_commands(cli_group)
# Import and register inbox commands
from .command_modules.inbox import register_inbox_commands
register_inbox_commands(cli_group)
# Import and register project management commands
from .command_modules.project import register_project_commands
register_project_commands(cli_group)
# Import and register user detection commands
from .command_modules.user import register_user_commands
register_user_commands(cli_group)