#!/usr/bin/env python3 """ CLI interface for tddai library. This module now uses the separated architecture with services and presenters. Business logic is handled by services, presentation by CLI framework. """ import sys import argparse from pathlib import Path from typing import Optional, Any # Add current directory to path so we can import modules sys.path.insert(0, str(Path(__file__).parent)) from cli import CLIFramework # Lazy initialization of CLI framework _cli_framework: Optional[CLIFramework] = None def _get_cli() -> CLIFramework: """Get CLI framework instance (lazy initialization).""" global _cli_framework if _cli_framework is None: _cli_framework = CLIFramework() return _cli_framework def workspace_status() -> None: """Show current workspace status.""" _get_cli().workspace_status() def start_issue(issue_number: int) -> None: """Start working on an issue.""" _get_cli().start_issue(issue_number) def finish_issue() -> None: """Finish current issue workspace.""" _get_cli().finish_issue() def add_test_guidance() -> None: """Show guidance for adding tests.""" _get_cli().add_test_guidance() def list_issues() -> None: """List all issues.""" _get_cli().list_issues() def list_open_issues() -> None: """List only open issues.""" _get_cli().list_open_issues() def show_issue(issue_number: int) -> None: """Show detailed issue information.""" _get_cli().show_issue(issue_number) def create_issue(title: str, body: str, issue_type: str = "enhancement") -> None: """Create a new issue.""" _get_cli().create_issue(title, body, issue_type) def create_enhancement_issue(title: str, use_case: str, technical_requirements: str = "", acceptance_criteria: str = "", dependencies: str = "", priority: str = "Medium") -> None: """Create a structured enhancement issue.""" # Parse acceptance criteria if provided criteria_list = [] if acceptance_criteria: criteria_list = [line.strip() for line in acceptance_criteria.split('\n') if line.strip()] # Parse dependencies if provided deps_list = [] if dependencies: deps_list = [line.strip() for line in dependencies.split('\n') if line.strip()] _get_cli().create_enhancement_issue( title=title, use_case=use_case, technical_requirements=technical_requirements, acceptance_criteria=criteria_list, dependencies=deps_list, priority=priority ) def create_from_template(template_file: str, **kwargs: Any) -> None: """Create issue from template file.""" _get_cli().create_from_template(template_file, **kwargs) def close_issue(issue_number: int, comment: str = "") -> None: """Close an issue with optional comment.""" _get_cli().close_issue(issue_number, comment) def analyze_coverage(issue_number: int) -> None: """Analyze test coverage for a specific issue.""" _get_cli().analyze_coverage(issue_number) def setup_project_management() -> None: """Setup project management labels and milestones.""" _get_cli().setup_project_management() def move_issue_to_state(issue_number: int, state: str) -> None: """Move issue to a specific project state.""" _get_cli().move_issue_to_state(issue_number, state) def set_issue_priority(issue_number: int, priority: str) -> None: """Set issue priority.""" _get_cli().set_issue_priority(issue_number, priority) def create_milestone(title: str, description: str = "") -> None: """Create a new milestone (project).""" _get_cli().create_milestone(title, description) def list_milestones() -> None: """List all milestones.""" _get_cli().list_milestones() def assign_issue_to_milestone(issue_number: int, milestone_id: int) -> None: """Assign issue to a milestone.""" _get_cli().assign_issue_to_milestone(issue_number, milestone_id) def project_overview() -> None: """Show project management overview.""" _get_cli().project_overview() def issue_index(format_type: str = "tsv", sort_by: str = "number", filter_state: Optional[str] = None, filter_priority: Optional[str] = None, include_state: bool = False) -> None: """Output compact index of all issues for Unix processing.""" _get_cli().issue_index( format_type=format_type, sort_by=sort_by, filter_state=filter_state, filter_priority=filter_priority, include_state=include_state ) def show_config(show_sensitive: bool = False) -> None: """Display current configuration values.""" _get_cli().show_config(show_sensitive) def validate_config(verbose: bool = False) -> None: """Validate current configuration and show any issues.""" _get_cli().validate_config(verbose) def troubleshoot_config() -> None: """Run comprehensive configuration troubleshooting.""" _get_cli().troubleshoot_config() def check_config_files() -> None: """Check for configuration files and their status.""" _get_cli().check_config_files() def main() -> None: """Main CLI entry point.""" parser = argparse.ArgumentParser(description="tddai CLI tool") subparsers = parser.add_subparsers(dest='command', help='Available commands') # Workspace commands subparsers.add_parser('workspace-status', help='Show workspace status') start_parser = subparsers.add_parser('start-issue', help='Start working on issue') start_parser.add_argument('issue_number', type=int, help='Issue number') subparsers.add_parser('finish-issue', help='Finish current issue') subparsers.add_parser('add-test', help='Show guidance for adding tests') # Issue commands subparsers.add_parser('list-issues', help='List all issues') subparsers.add_parser('list-open-issues', help='List open issues') index_parser = subparsers.add_parser('issue-index', help='Output compact issue index for Unix processing') index_parser.add_argument('--format', choices=['tsv', 'csv', 'json', 'fields'], default='tsv', help='Output format (default: tsv)') index_parser.add_argument('--sort', choices=['number', 'title', 'priority', 'state', 'created', 'updated'], default='number', help='Sort by field (default: number)') index_parser.add_argument('--filter-state', choices=['open', 'closed'], help='Filter by issue state') index_parser.add_argument('--filter-priority', choices=['low', 'medium', 'high', 'critical', 'none'], help='Filter by priority level') index_parser.add_argument('--include-state', action='store_true', help='Include state column in output') show_parser = subparsers.add_parser('show-issue', help='Show issue details') show_parser.add_argument('issue_number', type=int, help='Issue number') coverage_parser = subparsers.add_parser('analyze-coverage', help='Analyze test coverage for issue') coverage_parser.add_argument('issue_number', type=int, help='Issue number') close_parser = subparsers.add_parser('close-issue', help='Close an issue') close_parser.add_argument('issue_number', type=int, help='Issue number') close_parser.add_argument('--comment', help='Optional closing comment', default='') # Issue creation commands create_parser = subparsers.add_parser('create-issue', help='Create a new issue') create_parser.add_argument('title', help='Issue title') create_parser.add_argument('body', help='Issue body/description') create_parser.add_argument('--type', choices=['enhancement', 'bug'], default='enhancement', help='Issue type') create_enh_parser = subparsers.add_parser('create-enhancement', help='Create a structured enhancement issue') create_enh_parser.add_argument('title', help='Issue title') create_enh_parser.add_argument('use_case', help='UseCase description') create_enh_parser.add_argument('--technical', help='Technical requirements', default='') create_enh_parser.add_argument('--criteria', help='Acceptance criteria (newline separated)', default='') create_enh_parser.add_argument('--dependencies', help='Dependencies (newline separated)', default='') create_enh_parser.add_argument('--priority', choices=['High', 'Medium', 'Low'], default='Medium', help='Priority level') template_parser = subparsers.add_parser('create-from-template', help='Create issue from template') template_parser.add_argument('template_file', help='Template file path') template_parser.add_argument('--vars', help='Template variables in key=value format', nargs='*', default=[]) # Project management commands subparsers.add_parser('setup-project-mgmt', help='Setup project management labels and milestones') subparsers.add_parser('project-overview', help='Show project management overview') state_parser = subparsers.add_parser('set-issue-state', help='Set issue project state') state_parser.add_argument('issue_number', type=int, help='Issue number') state_parser.add_argument('state', choices=['todo', 'active', 'review', 'done', 'blocked'], help='Project state') priority_parser = subparsers.add_parser('set-issue-priority', help='Set issue priority') priority_parser.add_argument('issue_number', type=int, help='Issue number') priority_parser.add_argument('priority', choices=['low', 'medium', 'high', 'critical'], help='Priority level') milestone_parser = subparsers.add_parser('create-milestone', help='Create a new milestone (project)') milestone_parser.add_argument('title', help='Milestone title') milestone_parser.add_argument('--description', help='Milestone description', default='') subparsers.add_parser('list-milestones', help='List all milestones') assign_parser = subparsers.add_parser('assign-to-milestone', help='Assign issue to milestone') assign_parser.add_argument('issue_number', type=int, help='Issue number') assign_parser.add_argument('milestone_id', type=int, help='Milestone ID') # Configuration management commands config_show_parser = subparsers.add_parser('config-show', help='Display current configuration values') config_show_parser.add_argument('--show-sensitive', action='store_true', help='Show sensitive information like masked tokens') config_validate_parser = subparsers.add_parser('config-validate', help='Validate current configuration') config_validate_parser.add_argument('--verbose', '-v', action='store_true', help='Show detailed validation results') subparsers.add_parser('config-troubleshoot', help='Run comprehensive configuration troubleshooting') subparsers.add_parser('config-files', help='Check configuration files status') args = parser.parse_args() if not args.command: parser.print_help() return try: if args.command == 'workspace-status': workspace_status() elif args.command == 'start-issue': start_issue(args.issue_number) elif args.command == 'finish-issue': finish_issue() elif args.command == 'add-test': add_test_guidance() elif args.command == 'list-issues': list_issues() elif args.command == 'list-open-issues': list_open_issues() elif args.command == 'issue-index': issue_index( format_type=args.format, sort_by=args.sort, filter_state=args.filter_state, filter_priority=args.filter_priority, include_state=args.include_state ) elif args.command == 'show-issue': show_issue(args.issue_number) elif args.command == 'analyze-coverage': analyze_coverage(args.issue_number) elif args.command == 'close-issue': close_issue(args.issue_number, args.comment) elif args.command == 'create-issue': create_issue(args.title, args.body, args.type) elif args.command == 'create-enhancement': create_enhancement_issue( args.title, args.use_case, args.technical, args.criteria, args.dependencies, args.priority ) elif args.command == 'create-from-template': # Parse template variables template_vars = {} for var in args.vars: if '=' in var: key, value = var.split('=', 1) template_vars[key] = value create_from_template(args.template_file, **template_vars) elif args.command == 'setup-project-mgmt': setup_project_management() elif args.command == 'project-overview': project_overview() elif args.command == 'set-issue-state': move_issue_to_state(args.issue_number, args.state) elif args.command == 'set-issue-priority': set_issue_priority(args.issue_number, args.priority) elif args.command == 'create-milestone': create_milestone(args.title, args.description) elif args.command == 'list-milestones': list_milestones() elif args.command == 'assign-to-milestone': assign_issue_to_milestone(args.issue_number, args.milestone_id) elif args.command == 'config-show': show_config(args.show_sensitive) elif args.command == 'config-validate': validate_config(args.verbose) elif args.command == 'config-troubleshoot': troubleshoot_config() elif args.command == 'config-files': check_config_files() except KeyboardInterrupt: print("\n⚠️ Operation cancelled") sys.exit(1) if __name__ == '__main__': main()