Skip to content

Conversation

@mikejmorgan-ai
Copy link
Member

@mikejmorgan-ai mikejmorgan-ai commented Jan 15, 2026

Summary

  • Adds output_formatter.py with comprehensive Rich formatting utilities
  • Enhances branding.py with status boxes, tables, dividers, and colored status messages
  • Implements the investor-ready display format specified in issue requirements

Changes

  • Format boxes: format_box(), format_status_box() for framed content
  • Tables: format_table(), format_package_table() for tabular display
  • Progress: ProgressTracker, MultiStepProgress classes with spinners and bars
  • Status messages: cx_success/error/warning/info() with color-coded icons
  • 56 unit tests covering all new functionality

Example Output

┌─────────────────────────────────────────┐
│  CORTEX ML SCHEDULER                    │
├─────────────────────────────────────────┤
│  Status:    Active                      │
│  Uptime:    0.5 seconds                 │
└─────────────────────────────────────────┘

Test plan

  • All 56 tests pass
  • Demo script shows formatted output
  • Works in standard terminals

Fixes #242

🤖 Generated with Claude Code

Summary by CodeRabbit

Release Notes

  • New Features

    • Enhanced terminal UI with styled panels, status boxes, and formatted tables for improved visual feedback.
    • Added color-coded status messages (success, error, warning, info) for clearer communication.
    • Introduced progress tracking capabilities and dependency tree visualization for enhanced CLI experience.
  • Tests

    • Added comprehensive test suite for output formatting functionality.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 15, 2026

📝 Walkthrough

Walkthrough

This pull request introduces a comprehensive rich-based terminal UI framework across two modules: cortex/branding.py gains styled helper functions (boxes, status displays, tables, spinners), while the new cortex/output_formatter.py module provides core formatting utilities including enums, dataclasses, progress tracking, and output helpers. A test suite validates the new functionality.

Changes

Cohort / File(s) Summary
Rich UI Utilities
cortex/branding.py
Added 10+ styled output helpers: cx_box, cx_status_box, cx_table, cx_package_table, cx_divider, cx_success, cx_error, cx_warning, cx_info, cx_spinner_message. Added 4 new color constants (CORTEX_SUCCESS, CORTEX_WARNING, CORTEX_ERROR, CORTEX_INFO). Enhanced demo flow to showcase new rich-based rendering (+248 lines).
Core Formatting Module
cortex/output_formatter.py
New comprehensive module with: OutputStyle enum, TableColumn and StatusInfo dataclasses, box/panel/table/tree formatting functions (format_box, format_status_box, format_table, format_package_table, format_dependency_tree), progress tracking classes (ProgressTracker, MultiStepProgress), convenience print helpers, utility formatters (format_bytes, format_duration), and spinner context manager (+619 lines).
Test Coverage
tests/test_output_formatting.py
New test suite validating: branding constants, styled output helpers, status messages, OutputFormatter internals, progress tracking, and utility formatters. Tests use stdout capture to verify content presence across rendering scenarios (+539 lines).

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • PR #285: Contains overlapping implementations for progress/spinner utilities and multi-step progress tracking that align with the new ProgressTracker and MultiStepProgress classes.

Suggested labels

enhancement

Poem

🐰 Boxes now gleam with emerald and gold,
Progress spins bright where stories unfold,
Tables and panels, with colors so true,
Rich terminal magic—polished and new!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The PR title clearly and concisely summarizes the main changes: introducing Rich-based output formatting with colors, boxes, and spinners, which is the primary objective of this changeset.
Description check ✅ Passed The description covers the main changes, provides example output, includes a test plan, and references issue #242. However, it does not explicitly fill out the required PR description template sections (Related Issue formatted as required, AI Disclosure section, and full Checklist).
Linked Issues check ✅ Passed The PR successfully implements all core requirements from issue #242: color-coded status messages (green/yellow/red), progress spinners and bars via ProgressTracker/MultiStepProgress, boxed/framed output via format_box and format_status_box, consistent formatting across utilities, standard terminal support, and 56 unit tests included.
Out of Scope Changes check ✅ Passed All changes are directly aligned with issue #242 requirements: output_formatter.py provides the Rich formatting utilities, branding.py adds UI helpers (boxes, tables, dividers, status messages), and tests cover new functionality. No extraneous changes detected outside the stated objectives.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello @mikejmorgan-ai, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly upgrades the CLI's visual output by integrating the Rich library. It introduces a dedicated module for advanced formatting, including styled boxes, dynamic progress indicators, and color-coded messages, and refactors the existing branding module to utilize these new features. The overall goal is to provide a more user-friendly and professional terminal experience.

Highlights

  • New Output Formatting Module: Introduced output_formatter.py which centralizes comprehensive Rich formatting utilities, including functions for boxes, tables, progress indicators, and status messages.
  • Enhanced Branding Module: The branding.py module has been significantly enhanced to leverage the new Rich formatting capabilities, adding functions for status boxes, tables, dividers, and color-coded status messages (success, error, warning, info).
  • Investor-Ready Display Format: The changes implement the specified investor-ready display format, providing a more polished and professional look for CLI output.
  • Comprehensive Unit Testing: A new test file test_output_formatting.py has been added, containing 56 unit tests to ensure the reliability and correctness of all new formatting functionality.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

"""

from contextlib import contextmanager
from dataclasses import dataclass, field
from contextlib import contextmanager
from dataclasses import dataclass, field
from enum import Enum
from typing import Any, Generator, List, Optional, Tuple
from typing import Any, Generator, List, Optional, Tuple

from rich import box
from rich.console import Console, Group
TimeElapsedColumn,
TimeRemainingColumn,
)
from rich.spinner import Spinner
)
from rich.spinner import Spinner
from rich.status import Status
from rich.style import Style
from rich.status import Status
from rich.style import Style
from rich.table import Table
from rich.text import Text
Issue: #242 - Output Polish: Rich Formatting with Colors, Boxes, Spinners
"""

import io
"""

import io
from unittest.mock import patch
import io
from unittest.mock import patch

import pytest
from unittest.mock import patch

import pytest
from rich.console import Console
Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a comprehensive set of rich output formatting utilities using the rich library, which is a great enhancement for the CLI's user experience. A new output_formatter.py module provides a structured and powerful way to create styled boxes, tables, and progress indicators. The existing branding.py module is also updated with new formatting functions.

My main feedback is architectural. There is significant code duplication and conceptual overlap between the new functions in branding.py and the utilities in output_formatter.py. To improve maintainability and consistency, branding.py should be refactored to act as a thin wrapper around the more generic output_formatter.py module.

I've also pointed out several opportunities for code simplification and cleanup, such as removing an unused parameter and refactoring repetitive logic. Additionally, I found an incorrect assertion in one of the new tests.

Overall, this is a fantastic addition, and with some architectural refinement, it will be a very solid and maintainable feature.

Comment on lines +137 to +139
# ============================================
# Rich Output Formatting (Issue #242)
# ============================================
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

This PR introduces a new output_formatter.py module which provides a more structured and reusable way to format output (e.g., using StatusInfo and TableColumn dataclasses). However, many of the new cx_* functions in this file reimplement similar logic instead of using the new module. This creates significant code duplication and two parallel implementations for formatting, which will be hard to maintain.

For example:

  • cx_status_box should use format_status_box from the new module.
  • cx_table is very similar to format_table.
  • cx_package_table duplicates table creation logic.

To improve the architecture, this branding.py module should be refactored to be a thin wrapper around output_formatter.py. The cx_* functions should delegate the core formatting work to the functions in the new module. This will centralize formatting logic and improve maintainability.

Comment on lines +419 to +422
def test_output_styles_defined(self):
"""Test all output styles are defined."""
styles = [OutputStyle.DEFAULT, OutputStyle.SUCCESS, OutputStyle.WARNING, OutputStyle.ERROR]
assert len(styles) == 4
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The test test_output_styles_defined incorrectly asserts that len(styles) == 4. The OutputStyle enum in cortex/output_formatter.py actually has 6 members. This test is incomplete and gives a false sense of correctness. It should be updated to check for all members of the enum.

Suggested change
def test_output_styles_defined(self):
"""Test all output styles are defined."""
styles = [OutputStyle.DEFAULT, OutputStyle.SUCCESS, OutputStyle.WARNING, OutputStyle.ERROR]
assert len(styles) == 4
def test_output_styles_defined(self):
"""Test all output styles are defined."""
assert len(OutputStyle) == 6

Comment on lines +282 to +290
# Color-code actions
if "install" in action.lower():
action_styled = f"[green]{action}[/green]"
elif "remove" in action.lower() or "uninstall" in action.lower():
action_styled = f"[red]{action}[/red]"
elif "update" in action.lower() or "upgrade" in action.lower():
action_styled = f"[yellow]{action}[/yellow]"
else:
action_styled = action
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The if/elif/else chain for styling the action string is a bit verbose and can be hard to maintain. This can be made more data-driven by using a dictionary to map keywords to styles, which is more scalable if more action types are added in the future.

Suggested change
# Color-code actions
if "install" in action.lower():
action_styled = f"[green]{action}[/green]"
elif "remove" in action.lower() or "uninstall" in action.lower():
action_styled = f"[red]{action}[/red]"
elif "update" in action.lower() or "upgrade" in action.lower():
action_styled = f"[yellow]{action}[/yellow]"
else:
action_styled = action
# Color-code actions
action_color = "white"
action_lower = action.lower()
if "install" in action_lower:
action_color = "green"
elif "remove" in action_lower or "uninstall" in action_lower:
action_color = "red"
elif "update" in action_lower or "upgrade" in action_lower:
action_color = "yellow"
action_styled = action if action_color == "white" else f"[{action_color}]{action}[/{action_color}]"


def cx_error(message: str) -> None:
"""Print an error message with X."""
console.print(f"[{CORTEX_ERROR}]✗[/{CORTEX_ERROR}] [{CORTEX_ERROR}]{message}[/{CORTEX_ERROR}]")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The cx_error function contains redundant Rich markup for coloring. The icon and the message are styled separately with the same color. This can be simplified by wrapping the entire string in a single color tag, which improves readability and maintainability.

Suggested change
console.print(f"[{CORTEX_ERROR}]✗[/{CORTEX_ERROR}] [{CORTEX_ERROR}]{message}[/{CORTEX_ERROR}]")
console.print(f"[{CORTEX_ERROR}]✗ {message}[/{CORTEX_ERROR}]")


def cx_warning(message: str) -> None:
"""Print a warning message with warning icon."""
console.print(f"[{CORTEX_WARNING}]⚠[/{CORTEX_WARNING}] [{CORTEX_WARNING}]{message}[/{CORTEX_WARNING}]")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The cx_warning function contains redundant Rich markup for coloring. The icon and the message are styled separately with the same color. This can be simplified by wrapping the entire string in a single color tag, which improves readability and maintainability.

Suggested change
console.print(f"[{CORTEX_WARNING}]⚠[/{CORTEX_WARNING}] [{CORTEX_WARNING}]{message}[/{CORTEX_WARNING}]")
console.print(f"[{CORTEX_WARNING}]⚠ {message}[/{CORTEX_WARNING}]")

Comment on lines +353 to +358
def __init__(
self,
description: str,
total: Optional[int] = None,
show_speed: bool = False,
):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The __init__ method of ProgressTracker accepts a show_speed parameter, but it is never used within the class. This can be confusing for developers. The parameter should be removed to clean up the method signature.

    def __init__(
        self,
        description: str,
        total: Optional[int] = None,
    ):

Comment on lines +443 to +461
for step in self.steps:
status = self.step_status[step]
if status == "pending":
icon = f"[dim]{STATUS_ICONS['pending']}[/dim]"
style = "dim"
elif status == "running":
icon = f"[cyan]{STATUS_ICONS['running']}[/cyan]"
style = "cyan"
elif status == "completed":
icon = f"[green]{STATUS_ICONS['success']}[/green]"
style = "green"
elif status == "failed":
icon = f"[red]{STATUS_ICONS['error']}[/red]"
style = "red"
else:
icon = f"[dim]{STATUS_ICONS['skipped']}[/dim]"
style = "dim"

lines.append(f" {icon} [{style}]{step}[/{style}]")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The if/elif/else block in the _render method for determining the icon and style based on status is repetitive. This can be refactored into a more concise and data-driven structure, like a dictionary lookup, to improve maintainability.

        status_configs = {
            "pending": ("dim", STATUS_ICONS["pending"]),
            "running": ("cyan", STATUS_ICONS["running"]),
            "completed": ("green", STATUS_ICONS["success"]),
            "failed": ("red", STATUS_ICONS["error"]),
            "skipped": ("dim", STATUS_ICONS["skipped"]),
        }
        for step in self.steps:
            status = self.step_status.get(step, "skipped")
            style, icon_char = status_configs.get(status, status_configs["skipped"])
            icon = f"[{style}]{icon_char}[/{style}]"
            lines.append(f"  {icon} [{style}]{step}[/{style}]")


def print_error(message: str):
"""Print an error message with icon."""
console.print(f"[red]{STATUS_ICONS['error']}[/red] [red]{message}[/red]")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

This line has redundant Rich markup. The icon and message are styled separately with the same color. You can simplify this by wrapping the whole string in a single [red] tag.

    console.print(f"[red]{STATUS_ICONS['error']} {message}[/red]")


def print_warning(message: str):
"""Print a warning message with icon."""
console.print(f"[yellow]{STATUS_ICONS['warning']}[/yellow] [yellow]{message}[/yellow]")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

This line has redundant Rich markup. The icon and message are styled separately with the same color. You can simplify this by wrapping the whole string in a single [yellow] tag.

    console.print(f"[yellow]{STATUS_ICONS['warning']} {message}[/yellow]")

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🤖 Fix all issues with AI agents
In `@cortex/branding.py`:
- Around line 223-255: Update the cx_table function signature to use modern PEP
585/604 type syntax: replace List[str] and Optional[...] with built-in generics
and union types (e.g., headers: list[str], rows: list[list[str]], title: str |
None = None, row_styles: list[str] | None = None) and adjust any corresponding
imports if present (remove or keep typing imports as needed); keep the rest of
the function body unchanged and ensure the annotation names reference cx_table
so the change is localized.
- Around line 142-174: The function cx_box uses legacy typing Optional[str];
update its signature to use modern union syntax (str | None) for title and
subtitle (i.e., def cx_box(content: str, title: str | None = None, subtitle: str
| None = None, status: str = "info") -> None:) and replace any other occurrences
of Optional[str] in that function; remove or update unused Optional import if no
longer needed elsewhere. Ensure type hints for title/subtitle and any related
annotations use the new PEP 604 form while leaving the rest of the function
intact.
- Line 14: The import of typing.List and typing.Tuple is deprecated; remove List
and Tuple from the typing import line and switch to built-in generic types and
PEP 604 unions throughout the module: replace usages like List[str] with
list[str], List[Tuple[str, str, str]] with list[tuple[str, str, str]],
Optional[str] with str | None and Optional[List[str]] with list[str] | None,
updating all annotations in cortex/branding.py (e.g., function signatures,
variable annotations, and return types) to use these built-ins and the | None
form.

In `@cortex/output_formatter.py`:
- Around line 169-176: The style mapping for OutputStyle.INFO is inconsistent
between the style_colors dict and format_box: update one to match the other so
both use the same color; locate the style_colors mapping (variable style_colors)
and the function format_box and change whichever uses "cyan" or "blue" so
OutputStyle.INFO is the same string in both places (e.g., set both to "blue" or
both to "cyan") and run the formatter/tests to ensure no other references rely
on the previous value.

In `@tests/test_output_formatting.py`:
- Around line 416-428: The tests for the OutputStyle enum are incomplete: they
only check DEFAULT, SUCCESS, WARNING, ERROR and assert two enum values; update
TestOutputStyle to include the missing OutputStyle.INFO and OutputStyle.MUTED
checks and assert their .value strings match the expected "info" and "muted" (in
the test_output_style_values case), and ensure the styles list in
test_output_styles_defined contains all six enum members (OutputStyle.DEFAULT,
OutputStyle.SUCCESS, OutputStyle.WARNING, OutputStyle.ERROR, OutputStyle.INFO,
OutputStyle.MUTED) so the length assertion reflects six items.
🧹 Nitpick comments (5)
cortex/output_formatter.py (3)

10-13: Use modern type hint syntax.

For Python 3.9+, prefer built-in generics and union syntax over typing imports. This aligns with the coding guidelines and matches the linter configuration.

Suggested fix
 from contextlib import contextmanager
 from dataclasses import dataclass, field
 from enum import Enum
-from typing import Any, Generator, List, Optional, Tuple
+from typing import Any, Generator

Then update usages throughout the file:

  • List[...]list[...]
  • Optional[...]... | None
  • Tuple[...]tuple[...]

15-35: Remove unused imports.

Group (line 16) and Spinner (line 30) are imported but never used in this module.

Suggested fix
 from rich import box
-from rich.console import Console, Group
+from rich.console import Console
 from rich.live import Live
 from rich.panel import Panel
 from rich.progress import (
     BarColumn,
     MofNCompleteColumn,
     Progress,
     SpinnerColumn,
     TaskID,
     TaskProgressColumn,
     TextColumn,
     TimeElapsedColumn,
     TimeRemainingColumn,
 )
-from rich.spinner import Spinner
 from rich.status import Status
 from rich.style import Style
 from rich.table import Table
 from rich.text import Text
 from rich.tree import Tree

544-550: Avoid mutating the parameter variable.

The function reassigns num_bytes from int to float during iteration. Using a separate local variable improves clarity and maintains type consistency.

Suggested fix
 def format_bytes(num_bytes: int) -> str:
     """Format bytes to human-readable string."""
+    size = float(num_bytes)
     for unit in ["B", "KB", "MB", "GB", "TB"]:
-        if abs(num_bytes) < 1024.0:
-            return f"{num_bytes:.1f} {unit}"
-        num_bytes /= 1024.0
-    return f"{num_bytes:.1f} PB"
+        if abs(size) < 1024.0:
+            return f"{size:.1f} {unit}"
+        size /= 1024.0
+    return f"{size:.1f} PB"
tests/test_output_formatting.py (1)

7-8: Remove unused import.

The io module is imported but never used in this test file.

Suggested fix
-import io
 from unittest.mock import patch
cortex/branding.py (1)

196-202: Consider consolidating duplicated style mappings.

The style_colors dictionary here duplicates the one in output_formatter.py (lines 169-176). Consider importing and reusing a shared mapping to ensure consistency and reduce maintenance burden.

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between daa52b5 and 7e63882.

📒 Files selected for processing (3)
  • cortex/branding.py
  • cortex/output_formatter.py
  • tests/test_output_formatting.py
🧰 Additional context used
📓 Path-based instructions (2)
**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

**/*.py: Follow PEP 8 style guide for Python code
Include type hints in Python code
Add docstrings for all public APIs in Python code
Use dry-run mode by default for all installation operations
Do not use silent sudo - require explicit user confirmation for privilege escalation
Implement Firejail sandboxing for execution of untrusted code
Log all operations to ~/.cortex/history.db for audit purposes

Files:

  • tests/test_output_formatting.py
  • cortex/branding.py
  • cortex/output_formatter.py
tests/**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

Maintain test coverage above 80% for pull requests

Files:

  • tests/test_output_formatting.py
🧬 Code graph analysis (2)
cortex/branding.py (5)
cortex/cli.py (1)
  • status (1173-1181)
cortex/kernel_features/kv_cache_manager.py (1)
  • status (130-137)
cortex/kernel_features/accelerator_limits.py (2)
  • status (97-105)
  • get (69-72)
cortex/kernel_features/model_lifecycle.py (1)
  • status (135-143)
cortex/graceful_degradation.py (1)
  • get (109-141)
cortex/output_formatter.py (2)
cortex/semantic_cache.py (1)
  • total (32-34)
tests/test_progress_indicators.py (1)
  • steps (315-320)
🪛 GitHub Actions: CI
cortex/branding.py

[error] 14-14: Ruff: UP035 'typing.List' is deprecated. Use 'list' instead.

🪛 GitHub Check: lint
cortex/branding.py

[failure] 14-14: Ruff (UP035)
cortex/branding.py:14:1: UP035 typing.Tuple is deprecated, use tuple instead


[failure] 14-14: Ruff (UP035)
cortex/branding.py:14:1: UP035 typing.List is deprecated, use list instead


[failure] 226-226: Ruff (UP045)
cortex/branding.py:226:12: UP045 Use X | None for type annotations


[failure] 225-225: Ruff (UP006)
cortex/branding.py:225:16: UP006 Use list instead of List for type annotation


[failure] 225-225: Ruff (UP006)
cortex/branding.py:225:11: UP006 Use list instead of List for type annotation


[failure] 224-224: Ruff (UP006)
cortex/branding.py:224:14: UP006 Use list instead of List for type annotation


[failure] 178-178: Ruff (UP006)
cortex/branding.py:178:17: UP006 Use tuple instead of Tuple for type annotation


[failure] 178-178: Ruff (UP006)
cortex/branding.py:178:12: UP006 Use list instead of List for type annotation


[failure] 145-145: Ruff (UP045)
cortex/branding.py:145:15: UP045 Use X | None for type annotations


[failure] 144-144: Ruff (UP045)
cortex/branding.py:144:12: UP045 Use X | None for type annotations

🪛 GitHub Check: Lint
cortex/branding.py

[failure] 14-14: Ruff (UP035)
cortex/branding.py:14:1: UP035 typing.Tuple is deprecated, use tuple instead


[failure] 14-14: Ruff (UP035)
cortex/branding.py:14:1: UP035 typing.List is deprecated, use list instead


[failure] 226-226: Ruff (UP045)
cortex/branding.py:226:12: UP045 Use X | None for type annotations


[failure] 225-225: Ruff (UP006)
cortex/branding.py:225:16: UP006 Use list instead of List for type annotation


[failure] 225-225: Ruff (UP006)
cortex/branding.py:225:11: UP006 Use list instead of List for type annotation


[failure] 224-224: Ruff (UP006)
cortex/branding.py:224:14: UP006 Use list instead of List for type annotation


[failure] 178-178: Ruff (UP006)
cortex/branding.py:178:17: UP006 Use tuple instead of Tuple for type annotation


[failure] 178-178: Ruff (UP006)
cortex/branding.py:178:12: UP006 Use list instead of List for type annotation


[failure] 145-145: Ruff (UP045)
cortex/branding.py:145:15: UP045 Use X | None for type annotations


[failure] 144-144: Ruff (UP045)
cortex/branding.py:144:12: UP045 Use X | None for type annotations

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: test (3.10)
  • GitHub Check: test (3.12)
  • GitHub Check: test (3.11)
🔇 Additional comments (8)
cortex/output_formatter.py (4)

341-408: LGTM!

The ProgressTracker class is well-implemented with proper context manager protocol, null checks, and clean separation of concerns.


410-499: LGTM!

The MultiStepProgress class provides a clean API for multi-step operations with proper lifecycle management. The _render method handles all status states consistently.


306-338: LGTM!

The spinner_context properly handles success and error states while re-raising exceptions to preserve error handling semantics.


501-541: LGTM!

The print helper functions provide a clean, consistent API for common output patterns.

tests/test_output_formatting.py (2)

486-524: LGTM!

The MultiStepProgress tests cover initialization and all step state transitions (running, completed, failed, skipped). Good coverage of the core functionality.


56-81: LGTM!

Good coverage of branding constants and status icons with clear test organization.

cortex/branding.py (2)

257-294: LGTM!

The action color-coding logic is well-implemented with case-insensitive matching for install, remove, and update actions.


309-332: LGTM!

Clean, focused helper functions with consistent styling. Good addition to the branding API.

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.

- Consistent visual language
"""

from typing import List, Optional, Tuple
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Fix deprecated type hint imports (CI failure).

The pipeline is failing because typing.List and typing.Tuple are deprecated in Python 3.9+. Use built-in list and tuple directly.

Suggested fix
-from typing import List, Optional, Tuple
+from typing import Optional

Then update the type annotations throughout:

  • List[str]list[str]
  • List[Tuple[str, str, str]]list[tuple[str, str, str]]
  • Optional[str]str | None
  • Optional[List[str]]list[str] | None
🧰 Tools
🪛 GitHub Actions: CI

[error] 14-14: Ruff: UP035 'typing.List' is deprecated. Use 'list' instead.

🪛 GitHub Check: lint

[failure] 14-14: Ruff (UP035)
cortex/branding.py:14:1: UP035 typing.Tuple is deprecated, use tuple instead


[failure] 14-14: Ruff (UP035)
cortex/branding.py:14:1: UP035 typing.List is deprecated, use list instead

🪛 GitHub Check: Lint

[failure] 14-14: Ruff (UP035)
cortex/branding.py:14:1: UP035 typing.Tuple is deprecated, use tuple instead


[failure] 14-14: Ruff (UP035)
cortex/branding.py:14:1: UP035 typing.List is deprecated, use list instead

🤖 Prompt for AI Agents
In `@cortex/branding.py` at line 14, The import of typing.List and typing.Tuple is
deprecated; remove List and Tuple from the typing import line and switch to
built-in generic types and PEP 604 unions throughout the module: replace usages
like List[str] with list[str], List[Tuple[str, str, str]] with list[tuple[str,
str, str]], Optional[str] with str | None and Optional[List[str]] with list[str]
| None, updating all annotations in cortex/branding.py (e.g., function
signatures, variable annotations, and return types) to use these built-ins and
the | None form.

Comment on lines +142 to +174
def cx_box(
content: str,
title: Optional[str] = None,
subtitle: Optional[str] = None,
status: str = "info",
) -> None:
"""
Print content in a styled box/panel.
Args:
content: Content to display
title: Optional box title
subtitle: Optional box subtitle
status: Style - "info", "success", "warning", "error"
"""
border_colors = {
"info": CORTEX_CYAN,
"success": CORTEX_SUCCESS,
"warning": CORTEX_WARNING,
"error": CORTEX_ERROR,
}
border_style = border_colors.get(status, CORTEX_CYAN)

panel = Panel(
content,
title=f"[bold]{title}[/bold]" if title else None,
subtitle=f"[dim]{subtitle}[/dim]" if subtitle else None,
border_style=border_style,
padding=(1, 2),
box=box.ROUNDED,
)
console.print(panel)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Update type hints to modern syntax.

Per static analysis hints on lines 144-145, use str | None instead of Optional[str]:

Suggested fix
 def cx_box(
     content: str,
-    title: Optional[str] = None,
-    subtitle: Optional[str] = None,
+    title: str | None = None,
+    subtitle: str | None = None,
     status: str = "info",
 ) -> None:
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
def cx_box(
content: str,
title: Optional[str] = None,
subtitle: Optional[str] = None,
status: str = "info",
) -> None:
"""
Print content in a styled box/panel.
Args:
content: Content to display
title: Optional box title
subtitle: Optional box subtitle
status: Style - "info", "success", "warning", "error"
"""
border_colors = {
"info": CORTEX_CYAN,
"success": CORTEX_SUCCESS,
"warning": CORTEX_WARNING,
"error": CORTEX_ERROR,
}
border_style = border_colors.get(status, CORTEX_CYAN)
panel = Panel(
content,
title=f"[bold]{title}[/bold]" if title else None,
subtitle=f"[dim]{subtitle}[/dim]" if subtitle else None,
border_style=border_style,
padding=(1, 2),
box=box.ROUNDED,
)
console.print(panel)
def cx_box(
content: str,
title: str | None = None,
subtitle: str | None = None,
status: str = "info",
) -> None:
"""
Print content in a styled box/panel.
Args:
content: Content to display
title: Optional box title
subtitle: Optional box subtitle
status: Style - "info", "success", "warning", "error"
"""
border_colors = {
"info": CORTEX_CYAN,
"success": CORTEX_SUCCESS,
"warning": CORTEX_WARNING,
"error": CORTEX_ERROR,
}
border_style = border_colors.get(status, CORTEX_CYAN)
panel = Panel(
content,
title=f"[bold]{title}[/bold]" if title else None,
subtitle=f"[dim]{subtitle}[/dim]" if subtitle else None,
border_style=border_style,
padding=(1, 2),
box=box.ROUNDED,
)
console.print(panel)
🧰 Tools
🪛 GitHub Check: lint

[failure] 145-145: Ruff (UP045)
cortex/branding.py:145:15: UP045 Use X | None for type annotations


[failure] 144-144: Ruff (UP045)
cortex/branding.py:144:12: UP045 Use X | None for type annotations

🪛 GitHub Check: Lint

[failure] 145-145: Ruff (UP045)
cortex/branding.py:145:15: UP045 Use X | None for type annotations


[failure] 144-144: Ruff (UP045)
cortex/branding.py:144:12: UP045 Use X | None for type annotations

🤖 Prompt for AI Agents
In `@cortex/branding.py` around lines 142 - 174, The function cx_box uses legacy
typing Optional[str]; update its signature to use modern union syntax (str |
None) for title and subtitle (i.e., def cx_box(content: str, title: str | None =
None, subtitle: str | None = None, status: str = "info") -> None:) and replace
any other occurrences of Optional[str] in that function; remove or update unused
Optional import if no longer needed elsewhere. Ensure type hints for
title/subtitle and any related annotations use the new PEP 604 form while
leaving the rest of the function intact.

Comment on lines +223 to +255
def cx_table(
headers: List[str],
rows: List[List[str]],
title: Optional[str] = None,
row_styles: Optional[List[str]] = None,
) -> None:
"""
Print a formatted table with Cortex styling.
Args:
headers: Column header names
rows: List of rows (each row is a list of cell values)
title: Optional table title
row_styles: Optional list of styles for each row
"""
table = Table(
title=f"[bold cyan]{title}[/bold cyan]" if title else None,
show_header=True,
header_style="bold cyan",
border_style=CORTEX_CYAN,
box=box.ROUNDED,
padding=(0, 1),
)

for header in headers:
table.add_column(header, style="cyan")

for i, row in enumerate(rows):
style = row_styles[i] if row_styles and i < len(row_styles) else None
table.add_row(*row, style=style)

console.print(table)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Update type hints to modern syntax.

Per static analysis hints on lines 224-226, update to modern Python type annotation syntax:

Suggested fix
 def cx_table(
-    headers: List[str],
-    rows: List[List[str]],
-    title: Optional[str] = None,
-    row_styles: Optional[List[str]] = None,
+    headers: list[str],
+    rows: list[list[str]],
+    title: str | None = None,
+    row_styles: list[str] | None = None,
 ) -> None:
🧰 Tools
🪛 GitHub Check: lint

[failure] 226-226: Ruff (UP045)
cortex/branding.py:226:12: UP045 Use X | None for type annotations


[failure] 225-225: Ruff (UP006)
cortex/branding.py:225:16: UP006 Use list instead of List for type annotation


[failure] 225-225: Ruff (UP006)
cortex/branding.py:225:11: UP006 Use list instead of List for type annotation


[failure] 224-224: Ruff (UP006)
cortex/branding.py:224:14: UP006 Use list instead of List for type annotation

🪛 GitHub Check: Lint

[failure] 226-226: Ruff (UP045)
cortex/branding.py:226:12: UP045 Use X | None for type annotations


[failure] 225-225: Ruff (UP006)
cortex/branding.py:225:16: UP006 Use list instead of List for type annotation


[failure] 225-225: Ruff (UP006)
cortex/branding.py:225:11: UP006 Use list instead of List for type annotation


[failure] 224-224: Ruff (UP006)
cortex/branding.py:224:14: UP006 Use list instead of List for type annotation

🤖 Prompt for AI Agents
In `@cortex/branding.py` around lines 223 - 255, Update the cx_table function
signature to use modern PEP 585/604 type syntax: replace List[str] and
Optional[...] with built-in generics and union types (e.g., headers: list[str],
rows: list[list[str]], title: str | None = None, row_styles: list[str] | None =
None) and adjust any corresponding imports if present (remove or keep typing
imports as needed); keep the rest of the function body unchanged and ensure the
annotation names reference cx_table so the change is localized.

Comment on lines +169 to +176
style_colors = {
OutputStyle.SUCCESS: "green",
OutputStyle.WARNING: "yellow",
OutputStyle.ERROR: "red",
OutputStyle.INFO: "cyan",
OutputStyle.MUTED: "dim",
OutputStyle.DEFAULT: "white",
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Inconsistent color mapping for OutputStyle.INFO.

In format_box (line 126), OutputStyle.INFO maps to "blue", but here it maps to "cyan". This inconsistency could cause unexpected visual differences between the two functions.

Suggested fix
     style_colors = {
         OutputStyle.SUCCESS: "green",
         OutputStyle.WARNING: "yellow",
         OutputStyle.ERROR: "red",
-        OutputStyle.INFO: "cyan",
+        OutputStyle.INFO: "blue",
         OutputStyle.MUTED: "dim",
         OutputStyle.DEFAULT: "white",
     }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
style_colors = {
OutputStyle.SUCCESS: "green",
OutputStyle.WARNING: "yellow",
OutputStyle.ERROR: "red",
OutputStyle.INFO: "cyan",
OutputStyle.MUTED: "dim",
OutputStyle.DEFAULT: "white",
}
style_colors = {
OutputStyle.SUCCESS: "green",
OutputStyle.WARNING: "yellow",
OutputStyle.ERROR: "red",
OutputStyle.INFO: "blue",
OutputStyle.MUTED: "dim",
OutputStyle.DEFAULT: "white",
}
🤖 Prompt for AI Agents
In `@cortex/output_formatter.py` around lines 169 - 176, The style mapping for
OutputStyle.INFO is inconsistent between the style_colors dict and format_box:
update one to match the other so both use the same color; locate the
style_colors mapping (variable style_colors) and the function format_box and
change whichever uses "cyan" or "blue" so OutputStyle.INFO is the same string in
both places (e.g., set both to "blue" or both to "cyan") and run the
formatter/tests to ensure no other references rely on the previous value.

Comment on lines +416 to +428
class TestOutputStyle:
"""Tests for OutputStyle enum."""

def test_output_styles_defined(self):
"""Test all output styles are defined."""
styles = [OutputStyle.DEFAULT, OutputStyle.SUCCESS, OutputStyle.WARNING, OutputStyle.ERROR]
assert len(styles) == 4

def test_output_style_values(self):
"""Test output style values."""
assert OutputStyle.SUCCESS.value == "success"
assert OutputStyle.ERROR.value == "error"

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Incomplete test coverage for OutputStyle enum.

The test only verifies 4 of the 6 OutputStyle values. INFO and MUTED are missing from the assertions.

Suggested fix
     def test_output_styles_defined(self):
         """Test all output styles are defined."""
-        styles = [OutputStyle.DEFAULT, OutputStyle.SUCCESS, OutputStyle.WARNING, OutputStyle.ERROR]
-        assert len(styles) == 4
+        styles = [
+            OutputStyle.DEFAULT,
+            OutputStyle.SUCCESS,
+            OutputStyle.WARNING,
+            OutputStyle.ERROR,
+            OutputStyle.INFO,
+            OutputStyle.MUTED,
+        ]
+        assert len(styles) == 6
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
class TestOutputStyle:
"""Tests for OutputStyle enum."""
def test_output_styles_defined(self):
"""Test all output styles are defined."""
styles = [OutputStyle.DEFAULT, OutputStyle.SUCCESS, OutputStyle.WARNING, OutputStyle.ERROR]
assert len(styles) == 4
def test_output_style_values(self):
"""Test output style values."""
assert OutputStyle.SUCCESS.value == "success"
assert OutputStyle.ERROR.value == "error"
class TestOutputStyle:
"""Tests for OutputStyle enum."""
def test_output_styles_defined(self):
"""Test all output styles are defined."""
styles = [
OutputStyle.DEFAULT,
OutputStyle.SUCCESS,
OutputStyle.WARNING,
OutputStyle.ERROR,
OutputStyle.INFO,
OutputStyle.MUTED,
]
assert len(styles) == 6
def test_output_style_values(self):
"""Test output style values."""
assert OutputStyle.SUCCESS.value == "success"
assert OutputStyle.ERROR.value == "error"
🤖 Prompt for AI Agents
In `@tests/test_output_formatting.py` around lines 416 - 428, The tests for the
OutputStyle enum are incomplete: they only check DEFAULT, SUCCESS, WARNING,
ERROR and assert two enum values; update TestOutputStyle to include the missing
OutputStyle.INFO and OutputStyle.MUTED checks and assert their .value strings
match the expected "info" and "muted" (in the test_output_style_values case),
and ensure the styles list in test_output_styles_defined contains all six enum
members (OutputStyle.DEFAULT, OutputStyle.SUCCESS, OutputStyle.WARNING,
OutputStyle.ERROR, OutputStyle.INFO, OutputStyle.MUTED) so the length assertion
reflects six items.

…242)

- Add output_formatter.py with comprehensive formatting utilities:
  - format_box/format_status_box for framed content
  - format_table/format_package_table for tabular data
  - ProgressTracker and MultiStepProgress for progress bars
  - spinner_context for long operations
  - Color-coded status messages and icons

- Enhance branding.py with new formatting functions:
  - cx_box, cx_status_box for boxed output
  - cx_table, cx_package_table for formatted tables
  - cx_success, cx_error, cx_warning, cx_info status messages
  - cx_divider for section separators

- Add 56 comprehensive tests in test_output_formatting.py

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@mikejmorgan-ai mikejmorgan-ai force-pushed the feature/issue-242-rich-output-formatting branch from 7e63882 to 57d701f Compare January 15, 2026 08:12
@mikejmorgan-ai mikejmorgan-ai merged commit 9522447 into main Jan 15, 2026
@mikejmorgan-ai mikejmorgan-ai deleted the feature/issue-242-rich-output-formatting branch January 15, 2026 08:12
@sonarqubecloud
Copy link

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Output Polish: Rich Formatting with Colors, Boxes, Spinners

2 participants