diff --git a/cognee/cli/_cognee.py b/cognee/cli/_cognee.py index 1539d1acf..32400fb85 100644 --- a/cognee/cli/_cognee.py +++ b/cognee/cli/_cognee.py @@ -92,6 +92,7 @@ def _discover_commands() -> List[Type[SupportsCliCommand]]: ("cognee.cli.commands.cognify_command", "CognifyCommand"), ("cognee.cli.commands.delete_command", "DeleteCommand"), ("cognee.cli.commands.config_command", "ConfigCommand"), + ("cognee.cli.commands.tui_command", "TuiCommand"), ] for module_path, class_name in command_modules: diff --git a/cognee/cli/commands/tui_command.py b/cognee/cli/commands/tui_command.py new file mode 100644 index 000000000..5ae2c11c1 --- /dev/null +++ b/cognee/cli/commands/tui_command.py @@ -0,0 +1,54 @@ +import argparse +from cognee.cli.reference import SupportsCliCommand +from cognee.cli import DEFAULT_DOCS_URL +import cognee.cli.echo as fmt +from cognee.cli.exceptions import CliCommandException + + +class TuiCommand(SupportsCliCommand): + command_string = "tui" + help_string = "Launch interactive Terminal User Interface" + docs_url = DEFAULT_DOCS_URL + + description = """ +Launch the Cognee Terminal User Interface (TUI). + +The TUI provides an interactive, text-based interface for managing your +knowledge graphs with features like: + +- **Context Management**: Add and manage data sources +- **Search & Query**: Interactive knowledge graph querying +- **Settings**: Configure API keys and models +- **Live Updates**: Real-time status and progress indicators + +The TUI is keyboard-driven and supports: +- Arrow key navigation +- Keyboard shortcuts (h=Home, c=Context, s=Search, etc.) +- Tab completion for inputs + +Perfect for managing Cognee from the terminal or SSH sessions! + """ + + def configure_parser(self, parser: argparse.ArgumentParser) -> None: + parser.add_argument( + "--no-mouse", + action="store_true", + help="Disable mouse support (keyboard only mode)", + ) + + def execute(self, args: argparse.Namespace) -> None: + try: + fmt.echo("Starting Cognee TUI...") + fmt.note("Press 'q' to quit, '?' for help") + + # Import and run TUI + from cognee.cli.tui import run_tui + run_tui() + + except KeyboardInterrupt: + fmt.note("\nTUI closed by user") + except Exception as e: + raise CliCommandException( + f"Failed to start TUI: {str(e)}", + error_code=1 + ) from e diff --git a/cognee/cli/tui/__init__.py b/cognee/cli/tui/__init__.py new file mode 100644 index 000000000..904907a80 --- /dev/null +++ b/cognee/cli/tui/__init__.py @@ -0,0 +1,4 @@ +"""Cognee TUI - Terminal User Interface""" +from cognee.cli.tui.app import run_tui, CogneeTUI + +__all__ = ["run_tui", "CogneeTUI"] diff --git a/cognee/cli/tui/app.py b/cognee/cli/tui/app.py new file mode 100644 index 000000000..b0c034055 --- /dev/null +++ b/cognee/cli/tui/app.py @@ -0,0 +1,124 @@ +""" +Cognee TUI - Main Application +Text-based User Interface for managing Cognee knowledge graphs +""" +from textual.app import App, ComposeResult +from textual.binding import Binding +from textual.widgets import Header, Footer +from textual.screen import Screen + +from cognee.cli.tui.screens.home import HomeScreen + + +class CogneeTUI(App): + """Cognee Terminal User Interface Application""" + + CSS = """ + Screen { + background: $surface; + } + + .box { + border: solid $primary; + background: $panel; + padding: 1 2; + margin: 1; + } + + Button { + margin: 1 2; + min-width: 30; + } + + Button:hover { + background: $primary; + } + + #menu-container { + width: 60; + height: auto; + border: heavy $primary; + background: $panel; + padding: 2; + } + + .title { + text-align: center; + text-style: bold; + color: $accent; + padding: 1; + } + + .center { + align: center middle; + } + """ + + TITLE = "Cognee TUI - Knowledge Graph Manager" + SUB_TITLE = "Navigate with arrow keys • Press ? for help" + + BINDINGS = [ + Binding("q", "quit", "Quit", priority=True), + Binding("?", "help", "Help"), + Binding("d", "toggle_dark", "Toggle Dark Mode"), + ] + + def on_mount(self) -> None: + """Initialize the app with the home screen""" + self.push_screen(HomeScreen()) + + def action_help(self) -> None: + """Show help information""" + help_text = """ +# Cognee TUI Help + +## Navigation +- Arrow Keys: Navigate between UI elements +- Enter: Select/activate items +- Tab: Move to next field +- Esc: Go back + +## Keyboard Shortcuts +- q: Quit application +- d: Toggle dark/light mode +- ?: Show this help + +## Workflow +1. Add Context: Add data sources +2. Cognify: Process data +3. Search: Query knowledge graph +4. Settings: Configure API keys +""" + self.push_screen(HelpScreen(help_text)) + + +class HelpScreen(Screen): + """Help screen""" + + def __init__(self, help_text: str): + super().__init__() + self.help_text = help_text + + def compose(self) -> ComposeResult: + from textual.widgets import Static, Button + from textual.containers import VerticalScroll + + yield Header() + with VerticalScroll(): + yield Static(self.help_text, markup=False) + yield Button("Close (Esc)", id="close", variant="primary") + yield Footer() + + def on_button_pressed(self, event) -> None: + if event.button.id == "close": + self.app.pop_screen() + + def on_key(self, event) -> None: + if event.key == "escape": + self.app.pop_screen() + + +def run_tui(): + """Entry point to run the TUI application""" + app = CogneeTUI() + app.run() diff --git a/cognee/cli/tui/screens/__init__.py b/cognee/cli/tui/screens/__init__.py new file mode 100644 index 000000000..42a31ebca --- /dev/null +++ b/cognee/cli/tui/screens/__init__.py @@ -0,0 +1,7 @@ +"""Screens for Cognee TUI""" +from cognee.cli.tui.screens.home import HomeScreen +from cognee.cli.tui.screens.context import ContextScreen +from cognee.cli.tui.screens.query import QueryScreen +from cognee.cli.tui.screens.settings import SettingsScreen + +__all__ = ["HomeScreen", "ContextScreen", "QueryScreen", "SettingsScreen"] diff --git a/cognee/cli/tui/screens/context.py b/cognee/cli/tui/screens/context.py new file mode 100644 index 000000000..d59b22218 --- /dev/null +++ b/cognee/cli/tui/screens/context.py @@ -0,0 +1,26 @@ +"""Context Management Screen""" +from textual.screen import Screen +from textual.app import ComposeResult +from textual.widgets import Header, Footer, Button, Static +from textual.containers import Container +from textual.binding import Binding + + +class ContextScreen(Screen): + """Context management screen""" + + BINDINGS = [Binding("escape", "back", "Back")] + + def compose(self) -> ComposeResult: + yield Header() + with Container(): + yield Static("[bold]📁 Context Management[/bold]\n", classes="title") + yield Static("Context management features coming soon!") + yield Button("← Back", id="back_btn") + yield Footer() + + def on_button_pressed(self, event) -> None: + self.app.pop_screen() + + def action_back(self) -> None: + self.app.pop_screen() diff --git a/cognee/cli/tui/screens/home.py b/cognee/cli/tui/screens/home.py new file mode 100644 index 000000000..f3e53d3a0 --- /dev/null +++ b/cognee/cli/tui/screens/home.py @@ -0,0 +1,48 @@ +"""Home Screen for Cognee TUI""" +from textual.screen import Screen +from textual.app import ComposeResult +from textual.widgets import Header, Footer, Button, Static +from textual.containers import Container, Vertical + + +class HomeScreen(Screen): + """Main dashboard screen""" + + def compose(self) -> ComposeResult: + yield Header() + + with Container(id="menu-container", classes="center"): + yield Static("[bold cyan]🧠 Cognee Knowledge Graph Manager[/bold cyan]", classes="title") + yield Static("\nManage your AI memory and knowledge graphs\n", classes="center") + + with Vertical(): + yield Button("📁 Manage Context", id="context", variant="primary") + yield Button("🔍 Search & Query", id="query", variant="success") + yield Button("⚙️ Settings", id="settings", variant="default") + yield Button("❓ Help", id="help", variant="default") + yield Button("🚪 Exit", id="exit", variant="error") + + yield Static("\n[dim]Use arrow keys • Enter to select[/dim]", classes="center") + + yield Footer() + + def on_button_pressed(self, event: Button.Pressed) -> None: + button_id = event.button.id + + if button_id == "context": + from cognee.cli.tui.screens.context import ContextScreen + self.app.push_screen(ContextScreen()) + + elif button_id == "query": + from cognee.cli.tui.screens.query import QueryScreen + self.app.push_screen(QueryScreen()) + + elif button_id == "settings": + from cognee.cli.tui.screens.settings import SettingsScreen + self.app.push_screen(SettingsScreen()) + + elif button_id == "help": + self.app.action_help() + + elif button_id == "exit": + self.app.exit() diff --git a/cognee/cli/tui/screens/query.py b/cognee/cli/tui/screens/query.py new file mode 100644 index 000000000..bac705e47 --- /dev/null +++ b/cognee/cli/tui/screens/query.py @@ -0,0 +1,26 @@ +"""Query Screen""" +from textual.screen import Screen +from textual.app import ComposeResult +from textual.widgets import Header, Footer, Button, Static +from textual.containers import Container +from textual.binding import Binding + + +class QueryScreen(Screen): + """Query screen""" + + BINDINGS = [Binding("escape", "back", "Back")] + + def compose(self) -> ComposeResult: + yield Header() + with Container(): + yield Static("[bold]🔍 Search & Query[/bold]\n", classes="title") + yield Static("Search features coming soon!") + yield Button("← Back", id="back_btn") + yield Footer() + + def on_button_pressed(self, event) -> None: + self.app.pop_screen() + + def action_back(self) -> None: + self.app.pop_screen() diff --git a/cognee/cli/tui/screens/settings.py b/cognee/cli/tui/screens/settings.py new file mode 100644 index 000000000..e898e746f --- /dev/null +++ b/cognee/cli/tui/screens/settings.py @@ -0,0 +1,26 @@ +"""Settings Screen""" +from textual.screen import Screen +from textual.app import ComposeResult +from textual.widgets import Header, Footer, Button, Static +from textual.containers import Container +from textual.binding import Binding + + +class SettingsScreen(Screen): + """Settings screen""" + + BINDINGS = [Binding("escape", "back", "Back")] + + def compose(self) -> ComposeResult: + yield Header() + with Container(): + yield Static("[bold]⚙️ Settings[/bold]\n", classes="title") + yield Static("Settings features coming soon!") + yield Button("← Back", id="back_btn") + yield Footer() + + def on_button_pressed(self, event) -> None: + self.app.pop_screen() + + def action_back(self) -> None: + self.app.pop_screen() diff --git a/cognee/cli/tui/widgets/__init__.py b/cognee/cli/tui/widgets/__init__.py new file mode 100644 index 000000000..ad0566480 --- /dev/null +++ b/cognee/cli/tui/widgets/__init__.py @@ -0,0 +1,3 @@ +"""Custom widgets for Cognee TUI""" +# Custom widgets can be added here as needed +__all__ = []