项目文件夹

文件
Gelei Deng e238d701f2 feat: 🎸 version 1.0 agentic workflow (#325)
* feat: 🎸 version 1.0 agentic workflow

Major rewrite of PentestGPT to use an agentic pipeline architecture:
Core Changes: - New event-driven architecture with EventBus for
TUI-agent decoupling - Implemented AgentController with 5-state
lifecycle (IDLE->RUNNING->PAUSED->COMPLETED->ERROR) - Added AgentBackend
interface with ClaudeCodeBackend implementation - Session management
with file-based persistence for resumable pentests - Langfuse
integration for observability and tracing Interface: - New Textual-based
TUI with real-time activity feed - Keyboard shortcuts: F1 help, Ctrl+P
pause, Ctrl+Q quit - Enhanced CLI with --target, --instruction,
--non-interactive, --debug flags Project Structure: - Moved legacy
multi-LLM version (v0.15) to legacy/ directory - New pentestgpt/core/
for agent, controller, events, session modules - New
pentestgpt/interface/ for TUI and CLI components - New
pentestgpt/benchmark/ for xbow benchmark integration - Comprehensive
test suite in tests/ with unit and integration tests DevOps: - Docker
support with Ubuntu 24.04 container - GitHub Actions CI/CD pipeline -
Makefile with dev commands (test, lint, format, typecheck) - Added
xbow-validation-benchmarks as submodule

* style: format code with Black

This commit fixes the style issues introduced in abe3be0 according to the output
from Black.

Details: https://github.com/GreyDGL/PentestGPT/pull/325

* fix: 🐛 fix test pipeline

* feat: 🎸 update format

* feat: 🎸 update

---------

Co-authored-by: deepsource-autofix[bot] <62050782+deepsource-autofix[bot]@users.noreply.github.com>
2025-12-13 01:57:24 +08:00

114 行
4.9 KiB
Python

"""Splash screen component with ASCII banner for PentestGPT TUI."""
from collections.abc import Iterator
from typing import TYPE_CHECKING, Any
from rich.align import Align
from rich.console import Group
from rich.style import Style
from rich.text import Text
from textual.widgets import Static
if TYPE_CHECKING:
from textual.timer import Timer
class SplashScreen(Static):
"""Animated splash screen with ASCII banner and loading indicator."""
# Color scheme - modern indigo/purple
PRIMARY_COLOR = "#6366f1"
SECONDARY_COLOR = "#8b5cf6"
# ASCII Art Banner - Clean and modern design
BANNER = """
██████╗ ███████╗███╗ ██╗████████╗███████╗███████╗████████╗ ██████╗ ██████╗ ████████╗
██╔══██╗██╔════╝████╗ ██║╚══██╔══╝██╔════╝██╔════╝╚══██╔══╝██╔════╝ ██╔══██╗╚══██╔══╝
██████╔╝█████╗ ██╔██╗ ██║ ██║ █████╗ ███████╗ ██║ ██║ ███╗██████╔╝ ██║
██╔═══╝ ██╔══╝ ██║╚██╗██║ ██║ ██╔══╝ ╚════██║ ██║ ██║ ██║██╔═══╝ ██║
██║ ███████╗██║ ╚████║ ██║ ███████╗███████║ ██║ ╚██████╔╝██║ ██║
╚═╝ ╚══════╝╚═╝ ╚═══╝ ╚═╝ ╚══════╝╚══════╝ ╚═╝ ╚═════╝ ╚═╝ ╚═╝
"""
def __init__(self, *args: Any, **kwargs: Any) -> None:
"""Initialize splash screen."""
super().__init__(*args, **kwargs)
self._animation_step = 0
self._animation_timer: Timer | None = None
self._panel_static: Static | None = None
self._version = "1.0.0"
def compose(self) -> Iterator[Static]:
"""Create the splash screen content."""
self._animation_step = 0
loading_text = self._build_loading_text(self._animation_step)
content = self._build_content(loading_text)
panel_static = Static(content, id="splash_content")
self._panel_static = panel_static
yield panel_static
def on_mount(self) -> None:
"""Start animation when mounted."""
self._animation_timer = self.set_interval(0.4, self._animate_loading)
def on_unmount(self) -> None:
"""Stop animation when unmounted."""
if self._animation_timer is not None:
self._animation_timer.stop()
self._animation_timer = None
def _animate_loading(self) -> None:
"""Animate the loading indicator."""
if not self._panel_static:
return
self._animation_step = (self._animation_step + 1) % 4
loading_text = self._build_loading_text(self._animation_step)
content = self._build_content(loading_text)
self._panel_static.update(content)
def _build_content(self, loading_text: Text) -> Group:
"""Build the complete splash screen content."""
# Banner with gradient effect
banner_text = Text(self.BANNER.strip("\n"), justify="center")
banner_text.stylize(self.PRIMARY_COLOR)
# Title line
title_text = Text()
title_text.append("AI-Powered ", style=Style(color="#a3a3a3"))
title_text.append("Penetration Testing", style=Style(color=self.PRIMARY_COLOR, bold=True))
title_text.append(" Assistant", style=Style(color="#a3a3a3"))
# Version
version_text = Text(f"v{self._version}", style=Style(color="#525252", dim=True))
# Tagline
tagline_text = Text(
"AI Security Agent", style=Style(color=self.SECONDARY_COLOR, italic=True)
)
return Group(
Align.center(banner_text),
Align.center(Text(" ")),
Align.center(title_text),
Align.center(version_text),
Align.center(Text(" ")),
Align.center(tagline_text),
Align.center(Text(" ")),
Align.center(Text(" ")),
Align.center(loading_text),
)
def _build_loading_text(self, phase: int) -> Text:
"""Build animated loading text with dots."""
dots = "." * phase
spaces = " " * (3 - phase)
text = Text()
text.append("Initializing", style=Style(color=self.PRIMARY_COLOR, bold=True))
text.append(dots, style=Style(color=self.SECONDARY_COLOR))
text.append(spaces) # Keep consistent width
return text