diff --git a/dylan/cli.py b/dylan/cli.py index 694ef80..86ccfa3 100644 --- a/dylan/cli.py +++ b/dylan/cli.py @@ -8,6 +8,7 @@ from rich.table import Table from .utility_library.dylan_dev.dylan_dev_cli import dev +from .utility_library.dylan_goodbye.dylan_goodbye_cli import goodbye from .utility_library.dylan_pr.dylan_pr_cli import pr from .utility_library.dylan_release.dylan_release_cli import release_app from .utility_library.dylan_review.dylan_review_cli import review @@ -28,6 +29,7 @@ app.command(name="review", help="Run AI-powered code reviews on git branches")(review) app.command(name="dev", help="Implement fixes from code reviews")(dev) app.command(name="pr", help="Create pull requests with AI-generated descriptions")(pr) +app.command(name="goodbye", help="Print a friendly farewell message")(goodbye) @app.callback(invoke_without_command=True) @@ -76,6 +78,11 @@ def _main(ctx: typer.Context) -> None: "Manage project releases", "dylan release --minor --tag" ) + table.add_row( + "goodbye", + "Say farewell", + "dylan goodbye" + ) console.print(table) help_text = f"\n[{COLORS['muted']}]Use[/] [{COLORS['primary']}]dylan --help[/]" diff --git a/dylan/utility_library/dylan_goodbye/README.md b/dylan/utility_library/dylan_goodbye/README.md new file mode 100644 index 0000000..60810ef --- /dev/null +++ b/dylan/utility_library/dylan_goodbye/README.md @@ -0,0 +1,47 @@ +# Dylan Goodbye Command + +A simple CLI command that prints a friendly farewell message when invoked. + +## Purpose + +The `goodbye` command provides users with a polite way to exit or conclude their Dylan CLI session. It complements the existing welcome message shown when Dylan is invoked without arguments, creating a complete and friendly user experience. + +## Usage + +```bash +# Print farewell message +dylan goodbye +``` + +## Command Output + +The command displays a stylized farewell message using Dylan's UI theme: +- Arrow and spark symbols for visual consistency +- Branded colors matching other Dylan commands +- Friendly farewell text + +## Implementation + +The goodbye command is implemented as a simple Typer command with no arguments or options. It uses the shared UI theme components (`ARROW`, `SPARK`, `COLORS`) to maintain visual consistency with other Dylan utilities. + +## Testing + +Run the unit tests: + +```bash +uv run pytest dylan/utility_library/dylan_goodbye/tests/ -v +``` + +## Architecture + +- **dylan_goodbye_cli.py**: Core CLI implementation using Typer and Rich +- **tests/test_goodbye_cli.py**: Unit tests for the goodbye command +- **__init__.py**: Package exports + +## Design Principles + +Following KISS (Keep It Simple, Stupid) and YAGNI (You Aren't Gonna Need It): +- Minimal functionality with no unnecessary features +- No external dependencies beyond project requirements +- Simple, self-contained implementation +- Consistent with existing command patterns diff --git a/dylan/utility_library/dylan_goodbye/__init__.py b/dylan/utility_library/dylan_goodbye/__init__.py new file mode 100644 index 0000000..23e37e0 --- /dev/null +++ b/dylan/utility_library/dylan_goodbye/__init__.py @@ -0,0 +1,5 @@ +"""Dylan goodbye command - prints a friendly farewell message.""" + +from .dylan_goodbye_cli import goodbye + +__all__ = ["goodbye"] diff --git a/dylan/utility_library/dylan_goodbye/dylan_goodbye_cli.py b/dylan/utility_library/dylan_goodbye/dylan_goodbye_cli.py new file mode 100644 index 0000000..ea380b3 --- /dev/null +++ b/dylan/utility_library/dylan_goodbye/dylan_goodbye_cli.py @@ -0,0 +1,21 @@ +#!/usr/bin/env python3 +"""CLI interface for the goodbye command.""" + +from rich.console import Console + +from ..shared.ui_theme import ARROW, COLORS, SPARK + +console = Console() + + +def goodbye() -> None: + """Print a friendly farewell message. + + Examples: + # Say goodbye + dylan goodbye + """ + console.print( + f"\n[{COLORS['primary']}]{ARROW}[/] [bold]Goodbye![/bold] [{COLORS['accent']}]{SPARK}[/]" + ) + console.print("[dim]Thanks for using Dylan. See you next time![/dim]\n") diff --git a/dylan/utility_library/dylan_goodbye/tests/__init__.py b/dylan/utility_library/dylan_goodbye/tests/__init__.py new file mode 100644 index 0000000..0e69a30 --- /dev/null +++ b/dylan/utility_library/dylan_goodbye/tests/__init__.py @@ -0,0 +1 @@ +"""Tests for dylan_goodbye module.""" diff --git a/dylan/utility_library/dylan_goodbye/tests/test_goodbye_cli.py b/dylan/utility_library/dylan_goodbye/tests/test_goodbye_cli.py new file mode 100644 index 0000000..7dcaad3 --- /dev/null +++ b/dylan/utility_library/dylan_goodbye/tests/test_goodbye_cli.py @@ -0,0 +1,50 @@ +"""Tests for the goodbye command CLI.""" + +from typer.testing import CliRunner + +from dylan.utility_library.dylan_goodbye.dylan_goodbye_cli import goodbye + +runner = CliRunner() + + +def test_goodbye_command_executes() -> None: + """Test that the goodbye command executes without errors.""" + # Create a Typer app with the goodbye command for testing + import typer + + app = typer.Typer() + app.command()(goodbye) + + result = runner.invoke(app) + + assert result.exit_code == 0 + + +def test_goodbye_output_content() -> None: + """Test that the goodbye command outputs expected content.""" + # Create a Typer app with the goodbye command for testing + import typer + + app = typer.Typer() + app.command()(goodbye) + + result = runner.invoke(app) + + # Check that output contains the key elements + assert "Goodbye!" in result.stdout + assert "Thanks for using Dylan" in result.stdout + assert "See you next time!" in result.stdout + + +def test_goodbye_accepts_no_arguments() -> None: + """Test that the goodbye command works with no arguments.""" + # Create a Typer app with the goodbye command for testing + import typer + + app = typer.Typer() + app.command()(goodbye) + + result = runner.invoke(app, []) + + assert result.exit_code == 0 + assert "Goodbye!" in result.stdout diff --git a/specs/issue-0-wo-6fae60c6-planner-goodbye-command.md b/specs/issue-0-wo-6fae60c6-planner-goodbye-command.md new file mode 100644 index 0000000..782e132 --- /dev/null +++ b/specs/issue-0-wo-6fae60c6-planner-goodbye-command.md @@ -0,0 +1,181 @@ +# Feature: Goodbye Command + +## Feature Description + +A simple CLI command that prints a friendly farewell message when invoked. This command provides users with a polite way to exit or conclude their Dylan CLI session, complementing the existing welcome message shown when Dylan is invoked without arguments. + +## User Story + +As a Dylan CLI user +I want to run a goodbye command +So that I can receive a friendly farewell message when ending my CLI session + +## Problem Statement + +The Dylan CLI currently provides a welcoming experience when users start their session (via the main help screen), but lacks a corresponding farewell mechanism. Users may want a friendly way to close their interaction with the tool, especially when working in long terminal sessions where a polite goodbye can improve the overall user experience. + +## Solution Statement + +Implement a simple `dylan goodbye` command that prints a stylized farewell message using Dylan's existing UI theme. The command will be lightweight, self-contained, and follow the KISS principle by providing only the essential functionality without unnecessary complexity. The implementation will use the existing UI theme components (colors, symbols, formatting) to maintain visual consistency with other Dylan commands. + +## Relevant Files + +- **dylan/cli.py** - Main CLI entry point where the new goodbye command will be registered +- **dylan/utility_library/shared/ui_theme.py** - Contains shared UI components (COLORS, ARROW, SPARK, create_header) that the goodbye command will use for consistent styling + +### New Files + +- **dylan/utility_library/dylan_goodbye/__init__.py** - Package initialization file +- **dylan/utility_library/dylan_goodbye/dylan_goodbye_cli.py** - CLI implementation for the goodbye command +- **dylan/utility_library/dylan_goodbye/tests/__init__.py** - Test package initialization +- **dylan/utility_library/dylan_goodbye/tests/test_goodbye_cli.py** - Unit tests for the goodbye command +- **dylan/utility_library/dylan_goodbye/README.md** - Documentation for the goodbye command + +## Implementation Plan + +### Phase 1: Foundation + +Create the directory structure and package files for the new goodbye command utility. This includes creating the `dylan_goodbye` directory under `utility_library` with proper Python package initialization files. + +### Phase 2: Core Implementation + +Implement the goodbye command CLI function using Typer. The function will: +- Accept no required arguments +- Use Rich console for output +- Leverage existing ui_theme components for consistent styling +- Print a farewell message with Dylan's signature visual elements (arrow, spark, colors) + +### Phase 3: Integration + +Register the goodbye command in the main Dylan CLI (`dylan/cli.py`) and update the help table to include the new command. Ensure the command follows the same patterns as existing commands like `review`, `dev`, and `pr`. + +## Step by Step Tasks + +### Step 1: Create Directory Structure + +- Create directory `dylan/utility_library/dylan_goodbye/` +- Create directory `dylan/utility_library/dylan_goodbye/tests/` + +### Step 2: Create Package Initialization Files + +- Create `dylan/utility_library/dylan_goodbye/__init__.py` with proper exports +- Create `dylan/utility_library/dylan_goodbye/tests/__init__.py` + +### Step 3: Implement the Goodbye CLI + +- Create `dylan/utility_library/dylan_goodbye/dylan_goodbye_cli.py` +- Implement the `goodbye()` function using Typer +- Use Rich console for styled output +- Import and use ui_theme components (COLORS, ARROW, SPARK, create_header) +- Create a farewell message with proper styling +- Add proper type hints for all function parameters and return types +- Include docstring with usage examples + +### Step 4: Write Unit Tests + +- Create `dylan/utility_library/dylan_goodbye/tests/test_goodbye_cli.py` +- Write test for successful command execution +- Test that the function prints expected output +- Use pytest fixtures as needed +- Ensure tests follow the project's testing conventions + +### Step 5: Create Documentation + +- Create `dylan/utility_library/dylan_goodbye/README.md` +- Document command purpose and usage +- Include examples of command invocation +- Follow documentation patterns from other utility READMEs + +### Step 6: Register Command in Main CLI + +- Edit `dylan/cli.py` to import the goodbye command +- Add the goodbye command using `app.command()` +- Update the help table in the `_main()` callback to include the goodbye command +- Ensure the command follows the naming and help text patterns of existing commands + +### Step 7: Run Validation Commands + +- Execute all validation commands listed below +- Fix any issues that arise +- Ensure zero regressions in existing functionality + +## Testing Strategy + +### Unit Tests + +- **test_goodbye_command_executes**: Verify the goodbye function executes without errors +- **test_goodbye_output_format**: Test that output includes expected styling elements (colors, symbols) +- **test_goodbye_console_output**: Verify Rich console is used for output + +### Integration Tests + +- **Manual CLI test**: Run `dylan goodbye` from command line to verify end-to-end functionality +- **Help text test**: Verify `dylan --help` displays the goodbye command +- **Command registration test**: Verify the command is properly registered in the Typer app + +### Edge Cases + +- Running goodbye command with no arguments (expected behavior) +- Running goodbye command multiple times in succession (should work each time) +- Verifying goodbye doesn't interfere with other commands + +## Acceptance Criteria + +- [ ] `dylan goodbye` command executes successfully and prints a farewell message +- [ ] The farewell message uses Dylan's UI theme (colors, arrow, spark symbols) +- [ ] Command appears in `dylan --help` output with appropriate description +- [ ] All unit tests pass with 100% coverage of the goodbye module +- [ ] Code follows project conventions: type hints, docstrings, KISS/YAGNI principles +- [ ] No regressions in existing commands or functionality +- [ ] Documentation clearly explains command purpose and usage +- [ ] Code passes all linters (ruff, black, mypy) + +## Validation Commands + +Execute every command to validate the feature works correctly with zero regressions. + +```bash +# Create and activate virtual environment +uv venv +source .venv/bin/activate + +# Install dependencies +uv sync + +# Run the goodbye command +uv run dylan goodbye + +# Verify command appears in help +uv run dylan --help + +# Run all tests +uv run pytest dylan/utility_library/dylan_goodbye/tests/ -v + +# Run type checking +uv run mypy dylan/utility_library/dylan_goodbye/ + +# Run linting +uv run ruff check dylan/utility_library/dylan_goodbye/ + +# Format code +uv run black dylan/utility_library/dylan_goodbye/ + +# Run all project tests to ensure no regressions +uv run pytest -v + +# Test installation and command availability +uv pip install -e . +dylan goodbye +dylan --help +``` + +## Notes + +- This is a simple utility command following KISS/YAGNI principles +- No external dependencies are required beyond what's already in the project +- The command is intentionally minimal and self-contained +- Future enhancements could include: + - Optional custom farewell messages via command arguments + - Random selection from multiple farewell messages + - Integration with session statistics (if tracked in the future) +- These enhancements should only be added if user demand justifies the complexity diff --git a/uv.lock b/uv.lock index 28c25dd..14a569b 100644 --- a/uv.lock +++ b/uv.lock @@ -212,7 +212,7 @@ wheels = [ [[package]] name = "dylan" -version = "0.6.10" +version = "0.6.11" source = { editable = "." } dependencies = [ { name = "filelock" },