diff --git a/src/cli/commands.py b/src/cli/commands.py index edc9ade..11bf41b 100644 --- a/src/cli/commands.py +++ b/src/cli/commands.py @@ -1,162 +1,77 @@ -"""CLI commands for AI Code Audit CLI.""" +"""CLI commands for AI Code Audit.""" -import json from pathlib import Path from typing import Optional import typer -from rich.console import Console +from rich import print -from .output import OutputFormatter from .options import ( OutputFormat, - SeverityLevel, LanguageType, ScanOptions, resolve_output_format, resolve_severity, resolve_language, ) -from ..core import Scanner, AuditConfig +from .output import OutputFormatter +from ..core.scanner import CodeScanner +from ..core.models import ScanResult +from ..reporting.confidence import ConfidenceScorer -console = Console() - -app = typer.Typer( - name="audit", - help="AI Code Audit CLI - Validate AI-generated code for issues and vulnerabilities", - add_completion=False, -) +app = typer.Typer(help="AI Code Audit CLI") @app.command("scan") def scan_command( - path: str = typer.Argument( - ..., - help="Path to file or directory to scan", - exists=True, - file_okay=True, - dir_okay=True, - readable=True, - ), - output: Optional[str] = typer.Option( - None, - "--output", - "-o", - help="Output file path for report (optional)", - ), - format_option: str = typer.Option( - "terminal", - "--format", - "-f", - help="Output format: terminal, json, markdown", - ), - language: Optional[str] = typer.Option( - None, - "--language", - "-l", - help="Filter by language: python, javascript, typescript", - ), - severity: Optional[str] = typer.Option( - None, - "--severity", - "-s", - help="Minimum severity level: low, medium, high, critical", - ), - verbose: bool = typer.Option( - False, - "--verbose", - "-v", - help="Enable verbose output", - ), - no_color: bool = typer.Option( - False, - "--no-color", - help="Disable colored output", - ), - quiet: bool = typer.Option( - False, - "--quiet", - help="Minimal output (for CI/CD)", - ), -) -> None: - """Scan code for issues, anti-patterns, and security vulnerabilities.""" - from ..reporting import ReportFormatter, ConfidenceScorer - + path: str = typer.Argument(..., help="Path to file or directory to scan"), + output_format: str = typer.Option("terminal", "--format", "-f", help="Output format"), + severity: Optional[str] = typer.Option(None, "--severity", "-s", help="Filter by severity"), + language: Optional[str] = typer.Option(None, "--language", "-l", help="Filter by language"), + verbose: bool = typer.Option(False, "--verbose", "-v", help="Verbose output"), + no_color: bool = typer.Option(False, "--no-color", help="Disable colors"), + quiet: bool = typer.Option(False, "--quiet", "-q", help="Quiet mode"), +): + """Scan code for issues.""" + options = ScanOptions( + output_format=resolve_output_format(output_format), + severity_filter=resolve_severity(severity), + language_filter=resolve_language(language), + verbose=verbose, + no_color=no_color, + quiet=quiet, + ) + + target_path = Path(path) + if not target_path.exists(): + print(f"[red]Error: Path '{path}' does not exist[/red]") + raise typer.Exit(1) + + scanner = CodeScanner() + confidence_scorer = ConfidenceScorer() + try: - output_format = resolve_output_format(format_option) - severity_level = resolve_severity(severity) - language_filter = resolve_language(language) + results = scanner.scan(target_path, options) - options = ScanOptions( - output_format=output_format, - language_filter=language_filter, - severity_filter=severity_level, - verbose=verbose, - no_color=no_color, - quiet=quiet, - output_file=output, - ) - - target_path = Path(path) - config = AuditConfig( - target_path=str(target_path.absolute()), - output_format=output_format.value, - language_filter=language_filter.value if language_filter else None, - severity_filter=severity_level.value if severity_level else None, - verbose=verbose, - no_color=no_color, - quiet=quiet, - ) - - scanner = Scanner(config) - results = scanner.scan() - - formatter = ReportFormatter(options) - confidence_scorer = ConfidenceScorer() - - if options.quiet: - score = confidence_scorer.calculate(results) - console.print(f"Confidence Score: {score}/100") - if results.issues: - console.print(f"Issues Found: {len(results.issues)}") - return - - output_formatter = OutputFormatter(options) - output_formatter.display_results(results, confidence_scorer) - - if output: - if output_format == OutputFormat.JSON: - report = formatter.format_json(results, confidence_scorer) - Path(output).write_text(report) - elif output_format == OutputFormat.MARKDOWN: - report = formatter.format_markdown(results, confidence_scorer) - Path(output).write_text(report) - console.print(f"\n[green]Report saved to: {output}[/green]") - - except FileNotFoundError as e: - console.print(f"[red]Error: {e}[/red]") - raise typer.Exit(1) - except PermissionError as e: - console.print(f"[red]Error: Permission denied - {e}[/red]") - raise typer.Exit(1) + formatter = OutputFormatter(options) + formatter.display_results(results, confidence_scorer) except Exception as e: - console.print(f"[red]Error: An unexpected error occurred: {e}[/red]") - if verbose: - raise + print(f"[red]Error during scanning: {e}[/red]") raise typer.Exit(1) -@app.command("version") -def version_command() -> None: - """Show version information.""" - from .. import __version__ - console.print(f"AI Code Audit CLI v{__version__}") - - @app.command("languages") -def languages_command() -> None: - """Show supported languages.""" - console.print("Supported languages:") - console.print(" - Python (.py)") - console.print(" - JavaScript (.js)") - console.print(" - TypeScript (.ts, .tsx)") +def languages_command(): + """List supported languages.""" + for lang in LanguageType: + print(f"- {lang.value.capitalize()}") + + +@app.command("version") +def version_command(): + """Show version information.""" + print("AI Code Audit CLI v0.1.0") + + +if __name__ == "__main__": + app()