""" Main CLI Entry Point Universal Issue Tracking System CLI """ import click import sys from pathlib import Path from .commands import issue_group from .backend_commands import backend_group from .sync_commands import sync_group @click.group() @click.version_option() @click.option('--config', type=click.Path(), help='Configuration file path') @click.option('--backend', help='Backend to use (local, gitea)') @click.option('--verbose', '-v', is_flag=True, help='Verbose output') @click.pass_context def cli(ctx, config, backend, verbose): """ Universal Issue Tracking System A backend-agnostic issue tracking tool that works with local SQLite, Gitea, GitHub, and other issue tracking systems. Examples: issue list # List all issues issue create "Bug in parser" # Create new issue issue show 42 # Show issue #42 issue close 42 # Close issue #42 backend add local ~/.issues # Add local backend backend add gitea myrepo # Add Gitea backend sync pull gitea # Sync from Gitea sync push gitea # Sync to Gitea """ # Ensure the object exists ctx.ensure_object(dict) # Store global options in context ctx.obj['config_path'] = config ctx.obj['backend'] = backend ctx.obj['verbose'] = verbose # Register command groups cli.add_command(issue_group, name='issue') cli.add_command(backend_group, name='backend') cli.add_command(sync_group, name='sync') # Convenience aliases - direct issue commands @cli.command('list') @click.pass_context def list_issues(ctx): """List all issues (alias for 'issue list').""" ctx.invoke(issue_group.get_command(ctx, 'list')) @cli.command('show') @click.argument('issue_number', type=int) @click.pass_context def show_issue(ctx, issue_number): """Show issue details (alias for 'issue show').""" ctx.invoke(issue_group.get_command(ctx, 'show'), issue_number=issue_number) @cli.command('create') @click.argument('title') @click.option('--description', '-d', help='Issue description') @click.option('--label', '-l', multiple=True, help='Labels to add') @click.option('--assignee', '-a', help='Assign to user') @click.option('--milestone', '-m', help='Milestone') @click.pass_context def create_issue(ctx, title, description, label, assignee, milestone): """Create new issue (alias for 'issue create').""" ctx.invoke( issue_group.get_command(ctx, 'create'), title=title, description=description, label=label, assignee=assignee, milestone=milestone ) @cli.command('close') @click.argument('issue_number', type=int) @click.option('--comment', '-c', help='Closing comment') @click.pass_context def close_issue(ctx, issue_number, comment): """Close issue (alias for 'issue close').""" ctx.invoke( issue_group.get_command(ctx, 'close'), issue_number=issue_number, comment=comment ) def main(): """Main entry point for the CLI.""" try: cli(obj={}) except KeyboardInterrupt: click.echo("\nAborted by user", err=True) sys.exit(1) except Exception as e: click.echo(f"Error: {e}", err=True) sys.exit(1) if __name__ == '__main__': main()