From 5cf896a70e210b1a1a0e93f7a1cb5053e1db6707 Mon Sep 17 00:00:00 2001 From: 7000pctAUTO Date: Thu, 29 Jan 2026 12:43:40 +0000 Subject: [PATCH] Add shellgen UI and safety modules --- app/shellgen/ui/console.py | 163 +++++++++++++++++++++++++++++++++++++ 1 file changed, 163 insertions(+) create mode 100644 app/shellgen/ui/console.py diff --git a/app/shellgen/ui/console.py b/app/shellgen/ui/console.py new file mode 100644 index 0000000..6eeb6b8 --- /dev/null +++ b/app/shellgen/ui/console.py @@ -0,0 +1,163 @@ +"""Console UI using Rich library.""" + +import subprocess +import sys +from typing import List, Optional + +from rich.console import Console +from rich.panel import Panel +from rich.text import Text +from rich.syntax import Syntax +from rich.prompt import Prompt, Confirm +from rich.table import Table +from rich import box + + +class ConsoleUI: + """Rich-based console interface for ShellGen.""" + + def __init__(self): + """Initialize console with Rich.""" + self.console = Console() + + def print_header(self) -> None: + """Print the application header.""" + header = Text() + header.append("ShellGen", style="bold magenta") + header.append(" - ", style="dim") + header.append("Natural Language to Shell Command", style="italic") + + self.console.print(Panel(header, expand=False)) + + def display_generated_command( + self, command: str, explanation: str, language: str = "bash" + ) -> None: + """Display the generated command with explanation. + + Args: + command: The generated shell command. + explanation: Brief explanation of the command. + language: Syntax highlighting language. + """ + self.console.print("\n[bold green]Generated Command:[/bold green]") + + syntax = Syntax(command, language, theme="monokai", line_numbers=False) + self.console.print(Panel(syntax, expand=False, border_style="green")) + + self.console.print(f"\n[bold]Explanation:[/bold] {explanation}\n") + + def display_history(self, entries: List[dict]) -> None: + """Display command history. + + Args: + entries: List of history entry dictionaries. + """ + if not entries: + self.console.print("[yellow]No command history found.[/yellow]") + return + + table = Table( + title="Command History", + show_header=True, + header_style="bold magenta", + box=box.ROUNDED, + ) + + table.add_column("ID", width=5, justify="right") + table.add_column("Prompt", width=40) + table.add_column("Command", width=40) + table.add_column("Shell", width=10) + table.add_column("Executed", width=10) + + for entry in entries: + executed = "✓" if entry.get("executed") else "✗" + style = "green" if entry.get("executed") else "red" + + table.add_row( + str(entry.get("id", 0)), + entry.get("prompt", "")[:37] + "..." if len(entry.get("prompt", "")) > 40 else entry.get("prompt", ""), + entry.get("command", "")[:37] + "..." if len(entry.get("command", "")) > 40 else entry.get("command", ""), + entry.get("shell", ""), + f"[{style}]{executed}[/{style}]", + ) + + self.console.print(table) + + def confirm_execution(self) -> bool: + """Prompt user for execution confirmation. + + Returns: + True if user confirmed, False otherwise. + """ + return Confirm.ask("Execute this command?") + + def print_safety_warning(self, warning: str) -> None: + """Print a safety warning. + + Args: + warning: The warning message. + """ + self.console.print( + Panel( + Text(warning, style="bold red"), + title="⚠️ Safety Warning", + border_style="red", + ) + ) + + def print_cancelled(self) -> None: + """Print cancelled message.""" + self.console.print("[yellow]Command execution cancelled.[/yellow]") + + def print_error(self, message: str) -> None: + """Print an error message. + + Args: + message: Error message to display. + """ + self.console.print( + Panel( + Text(message, style="bold red"), + title="Error", + border_style="red", + ) + ) + + def execute_command(self, command: str) -> None: + """Execute a command and show output. + + Args: + command: Command to execute. + """ + self.console.print( + f"\n[bold]Executing:[/bold] [cyan]{command}[/cyan]\n" + ) + + try: + result = subprocess.run( + command, + shell=True, + capture_output=True, + text=True, + timeout=30, + ) + + if result.stdout: + self.console.print(result.stdout) + if result.stderr: + self.console.print(f"[red]{result.stderr}[/red]", highlight=False) + + self.console.print( + f"\n[dim]Exit code: {result.returncode}[/dim]\n" + ) + + except subprocess.TimeoutExpired: + self.console.print("[yellow]Command timed out after 30 seconds[/yellow]") + except Exception as e: + self.console.print(f"[red]Execution error: {e}[/red]") + + def print_feedback_submitted(self) -> None: + """Print feedback submission confirmation.""" + self.console.print( + "[green]✓[/green] Feedback submitted successfully" + )