refactor: redesign finished dialogs and UI elements
This commit is contained in:
@@ -36,7 +36,7 @@ Screen {
|
||||
}
|
||||
|
||||
#sidebar {
|
||||
width: 25%;
|
||||
width: 20%;
|
||||
background: transparent;
|
||||
margin-left: 1;
|
||||
}
|
||||
@@ -174,7 +174,7 @@ VulnerabilityDetailScreen {
|
||||
}
|
||||
|
||||
#chat_area_container {
|
||||
width: 75%;
|
||||
width: 80%;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
|
||||
@@ -24,30 +24,26 @@ async def run_cli(args: Any) -> None: # noqa: PLR0915
|
||||
console = Console()
|
||||
|
||||
start_text = Text()
|
||||
start_text.append("🦉 ", style="bold white")
|
||||
start_text.append("STRIX CYBERSECURITY AGENT", style="bold green")
|
||||
start_text.append("Penetration test initiated", style="bold #22c55e")
|
||||
|
||||
target_text = Text()
|
||||
target_text.append("Target", style="dim")
|
||||
target_text.append(" ")
|
||||
if len(args.targets_info) == 1:
|
||||
target_text.append("🎯 Target: ", style="bold cyan")
|
||||
target_text.append(args.targets_info[0]["original"], style="bold white")
|
||||
else:
|
||||
target_text.append("🎯 Targets: ", style="bold cyan")
|
||||
target_text.append(f"{len(args.targets_info)} targets\n", style="bold white")
|
||||
for i, target_info in enumerate(args.targets_info):
|
||||
target_text.append(" • ", style="dim white")
|
||||
target_text.append(f"{len(args.targets_info)} targets", style="bold white")
|
||||
for target_info in args.targets_info:
|
||||
target_text.append("\n ")
|
||||
target_text.append(target_info["original"], style="white")
|
||||
if i < len(args.targets_info) - 1:
|
||||
target_text.append("\n")
|
||||
|
||||
results_text = Text()
|
||||
results_text.append("📊 Results will be saved to: ", style="bold cyan")
|
||||
results_text.append(f"strix_runs/{args.run_name}", style="bold white")
|
||||
results_text.append("Output", style="dim")
|
||||
results_text.append(" ")
|
||||
results_text.append(f"strix_runs/{args.run_name}", style="#60a5fa")
|
||||
|
||||
note_text = Text()
|
||||
note_text.append("\n\n", style="dim")
|
||||
note_text.append("⏱️ ", style="dim")
|
||||
note_text.append("This may take a while depending on target complexity. ", style="dim")
|
||||
note_text.append("Vulnerabilities will be displayed in real-time.", style="dim")
|
||||
|
||||
startup_panel = Panel(
|
||||
@@ -59,9 +55,9 @@ async def run_cli(args: Any) -> None: # noqa: PLR0915
|
||||
results_text,
|
||||
note_text,
|
||||
),
|
||||
title="[bold green]🛡️ STRIX PENETRATION TEST INITIATED",
|
||||
title_align="center",
|
||||
border_style="green",
|
||||
title="[bold white]STRIX",
|
||||
title_align="left",
|
||||
border_style="#22c55e",
|
||||
padding=(1, 2),
|
||||
)
|
||||
|
||||
@@ -126,8 +122,7 @@ async def run_cli(args: Any) -> None: # noqa: PLR0915
|
||||
|
||||
def create_live_status() -> Panel:
|
||||
status_text = Text()
|
||||
status_text.append("🦉 ", style="bold white")
|
||||
status_text.append("Running penetration test...", style="bold #22c55e")
|
||||
status_text.append("Penetration test in progress", style="bold #22c55e")
|
||||
status_text.append("\n\n")
|
||||
|
||||
stats_text = build_live_stats_text(tracer, agent_config)
|
||||
@@ -136,8 +131,8 @@ async def run_cli(args: Any) -> None: # noqa: PLR0915
|
||||
|
||||
return Panel(
|
||||
status_text,
|
||||
title="[bold #22c55e]🔍 Live Penetration Test Status",
|
||||
title_align="center",
|
||||
title="[bold white]STRIX",
|
||||
title_align="left",
|
||||
border_style="#22c55e",
|
||||
padding=(1, 2),
|
||||
)
|
||||
@@ -169,7 +164,7 @@ async def run_cli(args: Any) -> None: # noqa: PLR0915
|
||||
error_msg = result.get("error", "Unknown error")
|
||||
error_details = result.get("details")
|
||||
console.print()
|
||||
console.print(f"[bold red]❌ Penetration test failed:[/] {error_msg}")
|
||||
console.print(f"[bold red]Penetration test failed:[/] {error_msg}")
|
||||
if error_details:
|
||||
console.print(f"[dim]{error_details}[/]")
|
||||
console.print()
|
||||
@@ -186,8 +181,7 @@ async def run_cli(args: Any) -> None: # noqa: PLR0915
|
||||
console.print()
|
||||
|
||||
final_report_text = Text()
|
||||
final_report_text.append("📄 ", style="bold cyan")
|
||||
final_report_text.append("FINAL PENETRATION TEST REPORT", style="bold cyan")
|
||||
final_report_text.append("Penetration test summary", style="bold #60a5fa")
|
||||
|
||||
final_report_panel = Panel(
|
||||
Text.assemble(
|
||||
@@ -195,9 +189,9 @@ async def run_cli(args: Any) -> None: # noqa: PLR0915
|
||||
"\n\n",
|
||||
tracer.final_scan_result,
|
||||
),
|
||||
title="[bold cyan]📊 PENETRATION TEST SUMMARY",
|
||||
title_align="center",
|
||||
border_style="cyan",
|
||||
title="[bold white]STRIX",
|
||||
title_align="left",
|
||||
border_style="#60a5fa",
|
||||
padding=(1, 2),
|
||||
)
|
||||
|
||||
|
||||
@@ -76,7 +76,6 @@ def validate_environment() -> None: # noqa: PLR0912, PLR0915
|
||||
|
||||
if missing_required_vars:
|
||||
error_text = Text()
|
||||
error_text.append("❌ ", style="bold red")
|
||||
error_text.append("MISSING REQUIRED ENVIRONMENT VARIABLES", style="bold red")
|
||||
error_text.append("\n\n", style="white")
|
||||
|
||||
@@ -163,8 +162,8 @@ def validate_environment() -> None: # noqa: PLR0912, PLR0915
|
||||
|
||||
panel = Panel(
|
||||
error_text,
|
||||
title="[bold red]🛡️ STRIX CONFIGURATION ERROR",
|
||||
title_align="center",
|
||||
title="[bold white]STRIX",
|
||||
title_align="left",
|
||||
border_style="red",
|
||||
padding=(1, 2),
|
||||
)
|
||||
@@ -179,7 +178,6 @@ def check_docker_installed() -> None:
|
||||
if shutil.which("docker") is None:
|
||||
console = Console()
|
||||
error_text = Text()
|
||||
error_text.append("❌ ", style="bold red")
|
||||
error_text.append("DOCKER NOT INSTALLED", style="bold red")
|
||||
error_text.append("\n\n", style="white")
|
||||
error_text.append("The 'docker' CLI was not found in your PATH.\n", style="white")
|
||||
@@ -189,8 +187,8 @@ def check_docker_installed() -> None:
|
||||
|
||||
panel = Panel(
|
||||
error_text,
|
||||
title="[bold red]🛡️ STRIX STARTUP ERROR",
|
||||
title_align="center",
|
||||
title="[bold white]STRIX",
|
||||
title_align="left",
|
||||
border_style="red",
|
||||
padding=(1, 2),
|
||||
)
|
||||
@@ -234,7 +232,6 @@ async def warm_up_llm() -> None:
|
||||
|
||||
except Exception as e: # noqa: BLE001
|
||||
error_text = Text()
|
||||
error_text.append("❌ ", style="bold red")
|
||||
error_text.append("LLM CONNECTION FAILED", style="bold red")
|
||||
error_text.append("\n\n", style="white")
|
||||
error_text.append("Could not establish connection to the language model.\n", style="white")
|
||||
@@ -243,8 +240,8 @@ async def warm_up_llm() -> None:
|
||||
|
||||
panel = Panel(
|
||||
error_text,
|
||||
title="[bold red]🛡️ STRIX STARTUP ERROR",
|
||||
title_align="center",
|
||||
title="[bold white]STRIX",
|
||||
title_align="left",
|
||||
border_style="red",
|
||||
padding=(1, 2),
|
||||
)
|
||||
@@ -410,30 +407,22 @@ def display_completion_message(args: argparse.Namespace, results_path: Path) ->
|
||||
|
||||
completion_text = Text()
|
||||
if scan_completed:
|
||||
completion_text.append("🦉 ", style="bold white")
|
||||
completion_text.append("AGENT FINISHED", style="bold green")
|
||||
completion_text.append(" • ", style="dim white")
|
||||
completion_text.append("Penetration test completed", style="white")
|
||||
completion_text.append("Penetration test completed", style="bold #22c55e")
|
||||
else:
|
||||
completion_text.append("🦉 ", style="bold white")
|
||||
completion_text.append("SESSION ENDED", style="bold yellow")
|
||||
completion_text.append(" • ", style="dim white")
|
||||
completion_text.append("Penetration test interrupted by user", style="white")
|
||||
|
||||
stats_text = build_final_stats_text(tracer)
|
||||
completion_text.append("SESSION ENDED", style="bold #eab308")
|
||||
|
||||
target_text = Text()
|
||||
target_text.append("Target", style="dim")
|
||||
target_text.append(" ")
|
||||
if len(args.targets_info) == 1:
|
||||
target_text.append("🎯 Target: ", style="bold cyan")
|
||||
target_text.append(args.targets_info[0]["original"], style="bold white")
|
||||
else:
|
||||
target_text.append("🎯 Targets: ", style="bold cyan")
|
||||
target_text.append(f"{len(args.targets_info)} targets\n", style="bold white")
|
||||
for i, target_info in enumerate(args.targets_info):
|
||||
target_text.append(" • ", style="dim white")
|
||||
target_text.append(f"{len(args.targets_info)} targets", style="bold white")
|
||||
for target_info in args.targets_info:
|
||||
target_text.append("\n ")
|
||||
target_text.append(target_info["original"], style="white")
|
||||
if i < len(args.targets_info) - 1:
|
||||
target_text.append("\n")
|
||||
|
||||
stats_text = build_final_stats_text(tracer)
|
||||
|
||||
panel_parts = [completion_text, "\n\n", target_text]
|
||||
|
||||
@@ -442,18 +431,20 @@ def display_completion_message(args: argparse.Namespace, results_path: Path) ->
|
||||
|
||||
if scan_completed or has_vulnerabilities:
|
||||
results_text = Text()
|
||||
results_text.append("📊 Results Saved To: ", style="bold cyan")
|
||||
results_text.append(str(results_path), style="bold yellow")
|
||||
panel_parts.extend(["\n\n", results_text])
|
||||
results_text.append("\n")
|
||||
results_text.append("Output", style="dim")
|
||||
results_text.append(" ")
|
||||
results_text.append(str(results_path), style="#60a5fa")
|
||||
panel_parts.extend(["\n", results_text])
|
||||
|
||||
panel_content = Text.assemble(*panel_parts)
|
||||
|
||||
border_style = "green" if scan_completed else "yellow"
|
||||
border_style = "#22c55e" if scan_completed else "#eab308"
|
||||
|
||||
panel = Panel(
|
||||
panel_content,
|
||||
title="[bold green]🛡️ STRIX CYBERSECURITY AGENT",
|
||||
title_align="center",
|
||||
title="[bold white]STRIX",
|
||||
title_align="left",
|
||||
border_style=border_style,
|
||||
padding=(1, 2),
|
||||
)
|
||||
@@ -461,8 +452,7 @@ def display_completion_message(args: argparse.Namespace, results_path: Path) ->
|
||||
console.print("\n")
|
||||
console.print(panel)
|
||||
console.print()
|
||||
console.print("[dim]🌐 Website:[/] [cyan]https://strix.ai[/]")
|
||||
console.print("[dim]💬 Discord:[/] [cyan]https://discord.gg/YjKFvEZSdZ[/]")
|
||||
console.print("[#60a5fa]strix.ai[/] [dim]·[/] [#60a5fa]discord.gg/YjKFvEZSdZ[/]")
|
||||
console.print()
|
||||
|
||||
|
||||
@@ -474,7 +464,7 @@ def pull_docker_image() -> None:
|
||||
return
|
||||
|
||||
console.print()
|
||||
console.print(f"[bold cyan]🐳 Pulling Docker image:[/] {Config.get('strix_image')}")
|
||||
console.print(f"[dim]Pulling image[/] {Config.get('strix_image')}")
|
||||
console.print("[dim yellow]This only happens on first run and may take a few minutes...[/]")
|
||||
console.print()
|
||||
|
||||
@@ -489,7 +479,6 @@ def pull_docker_image() -> None:
|
||||
except DockerException as e:
|
||||
console.print()
|
||||
error_text = Text()
|
||||
error_text.append("❌ ", style="bold red")
|
||||
error_text.append("FAILED TO PULL IMAGE", style="bold red")
|
||||
error_text.append("\n\n", style="white")
|
||||
error_text.append(f"Could not download: {Config.get('strix_image')}\n", style="white")
|
||||
@@ -497,8 +486,8 @@ def pull_docker_image() -> None:
|
||||
|
||||
panel = Panel(
|
||||
error_text,
|
||||
title="[bold red]🛡️ DOCKER PULL ERROR",
|
||||
title_align="center",
|
||||
title="[bold white]STRIX",
|
||||
title_align="left",
|
||||
border_style="red",
|
||||
padding=(1, 2),
|
||||
)
|
||||
@@ -506,8 +495,7 @@ def pull_docker_image() -> None:
|
||||
sys.exit(1)
|
||||
|
||||
success_text = Text()
|
||||
success_text.append("✅ ", style="bold green")
|
||||
success_text.append("Successfully pulled Docker image", style="green")
|
||||
success_text.append("Docker image ready", style="#22c55e")
|
||||
console.print(success_text)
|
||||
console.print()
|
||||
|
||||
|
||||
@@ -92,12 +92,13 @@ class AgentFinishRenderer(BaseToolRenderer):
|
||||
success = args.get("success", True)
|
||||
|
||||
text = Text()
|
||||
text.append("🏁 ")
|
||||
|
||||
if success:
|
||||
text.append("Agent completed", style="bold #fbbf24")
|
||||
text.append("◆ ", style="#22c55e")
|
||||
text.append("Agent completed", style="bold #22c55e")
|
||||
else:
|
||||
text.append("Agent failed", style="bold #fbbf24")
|
||||
text.append("◆ ", style="#ef4444")
|
||||
text.append("Agent failed", style="bold #ef4444")
|
||||
|
||||
if result_summary:
|
||||
text.append("\n ")
|
||||
|
||||
@@ -65,16 +65,16 @@ class StrReplaceEditorRenderer(BaseToolRenderer):
|
||||
text = Text()
|
||||
|
||||
icons_and_labels = {
|
||||
"view": ("📖 ", "Reading file", "#10b981"),
|
||||
"str_replace": ("✏️ ", "Editing file", "#10b981"),
|
||||
"create": ("📝 ", "Creating file", "#10b981"),
|
||||
"insert": ("✏️ ", "Inserting text", "#10b981"),
|
||||
"undo_edit": ("↩️ ", "Undoing edit", "#10b981"),
|
||||
"view": ("◇ ", "read", "#10b981"),
|
||||
"str_replace": ("◇ ", "edit", "#10b981"),
|
||||
"create": ("◇ ", "create", "#10b981"),
|
||||
"insert": ("◇ ", "insert", "#10b981"),
|
||||
"undo_edit": ("◇ ", "undo", "#10b981"),
|
||||
}
|
||||
|
||||
icon, label, color = icons_and_labels.get(command, ("📄 ", "File operation", "#10b981"))
|
||||
text.append(icon)
|
||||
text.append(label, style=f"bold {color}")
|
||||
icon, label, color = icons_and_labels.get(command, ("◇ ", "file", "#10b981"))
|
||||
text.append(icon, style=color)
|
||||
text.append(label, style="dim")
|
||||
|
||||
if path:
|
||||
path_display = path[-60:] if len(path) > 60 else path
|
||||
@@ -158,23 +158,20 @@ class SearchFilesRenderer(BaseToolRenderer):
|
||||
regex = args.get("regex", "")
|
||||
|
||||
text = Text()
|
||||
text.append("🔍 ")
|
||||
text.append("Searching files", style="bold purple")
|
||||
text.append(" ")
|
||||
text.append("◇ ", style="#a855f7")
|
||||
text.append("search", style="dim")
|
||||
text.append(" ")
|
||||
|
||||
if path and regex:
|
||||
text.append(path, style="dim")
|
||||
text.append(" for '", style="dim")
|
||||
text.append(regex, style="dim")
|
||||
text.append("'", style="dim")
|
||||
text.append(" ", style="dim")
|
||||
text.append(regex, style="#a855f7")
|
||||
elif path:
|
||||
text.append(path, style="dim")
|
||||
elif regex:
|
||||
text.append("'", style="dim")
|
||||
text.append(regex, style="dim")
|
||||
text.append("'", style="dim")
|
||||
text.append(regex, style="#a855f7")
|
||||
else:
|
||||
text.append("Searching...", style="dim")
|
||||
text.append("...", style="dim")
|
||||
|
||||
css_classes = cls.get_css_classes("completed")
|
||||
return Static(text, classes=css_classes)
|
||||
|
||||
@@ -27,8 +27,8 @@ class FinishScanRenderer(BaseToolRenderer):
|
||||
recommendations = args.get("recommendations", "")
|
||||
|
||||
text = Text()
|
||||
text.append("🏁 ")
|
||||
text.append("Finishing Scan", style="bold #dc2626")
|
||||
text.append("◆ ", style="#22c55e")
|
||||
text.append("Penetration test completed", style="bold #22c55e")
|
||||
|
||||
if executive_summary:
|
||||
text.append("\n\n")
|
||||
|
||||
@@ -21,8 +21,8 @@ class CreateNoteRenderer(BaseToolRenderer):
|
||||
category = args.get("category", "general")
|
||||
|
||||
text = Text()
|
||||
text.append("📝 ")
|
||||
text.append("Note", style="bold #fbbf24")
|
||||
text.append("◇ ", style="#fbbf24")
|
||||
text.append("note", style="dim")
|
||||
text.append(" ")
|
||||
text.append(f"({category})", style="dim")
|
||||
|
||||
@@ -50,8 +50,8 @@ class DeleteNoteRenderer(BaseToolRenderer):
|
||||
@classmethod
|
||||
def render(cls, tool_data: dict[str, Any]) -> Static: # noqa: ARG003
|
||||
text = Text()
|
||||
text.append("📝 ")
|
||||
text.append("Note Removed", style="bold #94a3b8")
|
||||
text.append("◇ ", style="#fbbf24")
|
||||
text.append("note removed", style="dim")
|
||||
|
||||
css_classes = cls.get_css_classes("completed")
|
||||
return Static(text, classes=css_classes)
|
||||
@@ -70,8 +70,8 @@ class UpdateNoteRenderer(BaseToolRenderer):
|
||||
content = args.get("content")
|
||||
|
||||
text = Text()
|
||||
text.append("📝 ")
|
||||
text.append("Note Updated", style="bold #fbbf24")
|
||||
text.append("◇ ", style="#fbbf24")
|
||||
text.append("note updated", style="dim")
|
||||
|
||||
if title:
|
||||
text.append("\n ")
|
||||
@@ -99,8 +99,8 @@ class ListNotesRenderer(BaseToolRenderer):
|
||||
result = tool_data.get("result")
|
||||
|
||||
text = Text()
|
||||
text.append("📝 ")
|
||||
text.append("Notes", style="bold #fbbf24")
|
||||
text.append("◇ ", style="#fbbf24")
|
||||
text.append("notes", style="dim")
|
||||
|
||||
if isinstance(result, str) and result.strip():
|
||||
text.append("\n ")
|
||||
|
||||
@@ -19,7 +19,8 @@ class ScanStartInfoRenderer(BaseToolRenderer):
|
||||
targets = args.get("targets", [])
|
||||
|
||||
text = Text()
|
||||
text.append("🚀 Starting penetration test")
|
||||
text.append("◈ ", style="#22c55e")
|
||||
text.append("Starting penetration test")
|
||||
|
||||
if len(targets) == 1:
|
||||
text.append(" on ")
|
||||
|
||||
@@ -192,7 +192,7 @@ class SplashScreen(Static): # type: ignore[misc]
|
||||
class HelpScreen(ModalScreen): # type: ignore[misc]
|
||||
def compose(self) -> ComposeResult:
|
||||
yield Grid(
|
||||
Label("🦉 Strix Help", id="help_title"),
|
||||
Label("Strix Help", id="help_title"),
|
||||
Label(
|
||||
"F1 Help\nCtrl+Q/C Quit\nESC Stop Agent\n"
|
||||
"Enter Send message to agent\nTab Switch panels\n↑/↓ Navigate tree",
|
||||
@@ -668,7 +668,7 @@ class QuitScreen(ModalScreen): # type: ignore[misc]
|
||||
class StrixTUIApp(App): # type: ignore[misc]
|
||||
CSS_PATH = "assets/tui_styles.tcss"
|
||||
|
||||
SIDEBAR_MIN_WIDTH = 100
|
||||
SIDEBAR_MIN_WIDTH = 140
|
||||
|
||||
selected_agent_id: reactive[str | None] = reactive(default=None)
|
||||
show_splash: reactive[bool] = reactive(default=True)
|
||||
@@ -795,7 +795,7 @@ class StrixTUIApp(App): # type: ignore[misc]
|
||||
chat_input.set_app_reference(self)
|
||||
chat_input_container = Horizontal(chat_prompt, chat_input, id="chat_input_container")
|
||||
|
||||
agents_tree = Tree("🤖 Active Agents", id="agents_tree")
|
||||
agents_tree = Tree("Agents", id="agents_tree")
|
||||
agents_tree.root.expand()
|
||||
agents_tree.show_root = False
|
||||
|
||||
@@ -911,16 +911,16 @@ class StrixTUIApp(App): # type: ignore[misc]
|
||||
status = agent_data.get("status", "running")
|
||||
|
||||
status_indicators = {
|
||||
"running": "🟢",
|
||||
"waiting": "⏸️",
|
||||
"completed": "✅",
|
||||
"failed": "❌",
|
||||
"stopped": "⏹️",
|
||||
"stopping": "⏸️",
|
||||
"llm_failed": "🔴",
|
||||
"running": "●",
|
||||
"waiting": "○",
|
||||
"completed": "◆",
|
||||
"failed": "◇",
|
||||
"stopped": "■",
|
||||
"stopping": "○",
|
||||
"llm_failed": "◇",
|
||||
}
|
||||
|
||||
status_icon = status_indicators.get(status, "🔵")
|
||||
status_icon = status_indicators.get(status, "○")
|
||||
vuln_count = self._agent_vulnerability_count(agent_id)
|
||||
vuln_indicator = f" ({vuln_count})" if vuln_count > 0 else ""
|
||||
agent_name = f"{status_icon} {agent_name_raw}{vuln_indicator}"
|
||||
@@ -1466,15 +1466,15 @@ class StrixTUIApp(App): # type: ignore[misc]
|
||||
agent_name_raw = agent_data.get("name", "Agent")
|
||||
|
||||
status_indicators = {
|
||||
"running": "🟢",
|
||||
"waiting": "🟡",
|
||||
"completed": "✅",
|
||||
"failed": "❌",
|
||||
"stopped": "⏹️",
|
||||
"stopping": "⏸️",
|
||||
"running": "●",
|
||||
"waiting": "○",
|
||||
"completed": "◆",
|
||||
"failed": "◇",
|
||||
"stopped": "■",
|
||||
"stopping": "○",
|
||||
}
|
||||
|
||||
status_icon = status_indicators.get(status, "🔵")
|
||||
status_icon = status_indicators.get(status, "○")
|
||||
vuln_count = self._agent_vulnerability_count(agent_id)
|
||||
vuln_indicator = f" ({vuln_count})" if vuln_count > 0 else ""
|
||||
agent_name = f"{status_icon} {agent_name_raw}{vuln_indicator}"
|
||||
@@ -1540,15 +1540,15 @@ class StrixTUIApp(App): # type: ignore[misc]
|
||||
status = agent_data.get("status", "running")
|
||||
|
||||
status_indicators = {
|
||||
"running": "🟢",
|
||||
"waiting": "🟡",
|
||||
"completed": "✅",
|
||||
"failed": "❌",
|
||||
"stopped": "⏹️",
|
||||
"stopping": "⏸️",
|
||||
"running": "●",
|
||||
"waiting": "○",
|
||||
"completed": "◆",
|
||||
"failed": "◇",
|
||||
"stopped": "■",
|
||||
"stopping": "○",
|
||||
}
|
||||
|
||||
status_icon = status_indicators.get(status, "🔵")
|
||||
status_icon = status_indicators.get(status, "○")
|
||||
vuln_count = self._agent_vulnerability_count(agent_id)
|
||||
vuln_indicator = f" ({vuln_count})" if vuln_count > 0 else ""
|
||||
agent_name = f"{status_icon} {agent_name_raw}{vuln_indicator}"
|
||||
|
||||
@@ -208,7 +208,7 @@ def _build_vulnerability_stats(stats_text: Text, tracer: Any) -> None:
|
||||
if severity in severity_counts:
|
||||
severity_counts[severity] += 1
|
||||
|
||||
stats_text.append("🔍 Vulnerabilities Found: ", style="bold red")
|
||||
stats_text.append("Vulnerabilities ", style="bold red")
|
||||
|
||||
severity_parts = []
|
||||
for severity in ["critical", "high", "medium", "low", "info"]:
|
||||
@@ -230,7 +230,7 @@ def _build_vulnerability_stats(stats_text: Text, tracer: Any) -> None:
|
||||
stats_text.append(")", style="dim white")
|
||||
stats_text.append("\n")
|
||||
else:
|
||||
stats_text.append("🔍 Vulnerabilities Found: ", style="bold green")
|
||||
stats_text.append("Vulnerabilities ", style="bold #22c55e")
|
||||
stats_text.append("0", style="bold white")
|
||||
stats_text.append(" (No exploitable vulnerabilities detected)", style="dim green")
|
||||
stats_text.append("\n")
|
||||
@@ -240,29 +240,29 @@ def _build_llm_stats(stats_text: Text, total_stats: dict[str, Any]) -> None:
|
||||
"""Build LLM usage section of stats text."""
|
||||
if total_stats["requests"] > 0:
|
||||
stats_text.append("\n")
|
||||
stats_text.append("📥 Input Tokens: ", style="bold cyan")
|
||||
stats_text.append(format_token_count(total_stats["input_tokens"]), style="bold white")
|
||||
stats_text.append("Input Tokens ", style="dim")
|
||||
stats_text.append(format_token_count(total_stats["input_tokens"]), style="white")
|
||||
|
||||
if total_stats["cached_tokens"] > 0:
|
||||
stats_text.append(" • ", style="dim white")
|
||||
stats_text.append("⚡ Cached Tokens: ", style="bold green")
|
||||
stats_text.append(format_token_count(total_stats["cached_tokens"]), style="bold white")
|
||||
stats_text.append(" · ", style="dim white")
|
||||
stats_text.append("Cached Tokens ", style="dim")
|
||||
stats_text.append(format_token_count(total_stats["cached_tokens"]), style="#22c55e")
|
||||
|
||||
stats_text.append(" • ", style="dim white")
|
||||
stats_text.append("📤 Output Tokens: ", style="bold cyan")
|
||||
stats_text.append(format_token_count(total_stats["output_tokens"]), style="bold white")
|
||||
stats_text.append(" · ", style="dim white")
|
||||
stats_text.append("Output Tokens ", style="dim")
|
||||
stats_text.append(format_token_count(total_stats["output_tokens"]), style="white")
|
||||
|
||||
if total_stats["cost"] > 0:
|
||||
stats_text.append(" • ", style="dim white")
|
||||
stats_text.append("💰 Total Cost: ", style="bold cyan")
|
||||
stats_text.append(f"${total_stats['cost']:.4f}", style="bold yellow")
|
||||
stats_text.append(" · ", style="dim white")
|
||||
stats_text.append("Cost ", style="dim")
|
||||
stats_text.append(f"${total_stats['cost']:.4f}", style="bold #fbbf24")
|
||||
else:
|
||||
stats_text.append("\n")
|
||||
stats_text.append("💰 Total Cost: ", style="bold cyan")
|
||||
stats_text.append("$0.0000 ", style="bold yellow")
|
||||
stats_text.append("• ", style="bold white")
|
||||
stats_text.append("📊 Tokens: ", style="bold cyan")
|
||||
stats_text.append("0", style="bold white")
|
||||
stats_text.append("Cost ", style="dim")
|
||||
stats_text.append("$0.0000 ", style="#fbbf24")
|
||||
stats_text.append("· ", style="dim white")
|
||||
stats_text.append("Tokens ", style="dim")
|
||||
stats_text.append("0", style="white")
|
||||
|
||||
|
||||
def build_final_stats_text(tracer: Any) -> Text:
|
||||
@@ -276,10 +276,12 @@ def build_final_stats_text(tracer: Any) -> Text:
|
||||
tool_count = tracer.get_real_tool_count()
|
||||
agent_count = len(tracer.agents)
|
||||
|
||||
stats_text.append("🤖 Agents Used: ", style="bold cyan")
|
||||
stats_text.append("Agents", style="dim")
|
||||
stats_text.append(" ")
|
||||
stats_text.append(str(agent_count), style="bold white")
|
||||
stats_text.append(" • ", style="dim white")
|
||||
stats_text.append("🛠️ Tools Called: ", style="bold cyan")
|
||||
stats_text.append(" · ", style="dim white")
|
||||
stats_text.append("Tools", style="dim")
|
||||
stats_text.append(" ")
|
||||
stats_text.append(str(tool_count), style="bold white")
|
||||
|
||||
llm_stats = tracer.get_total_llm_stats()
|
||||
@@ -296,15 +298,16 @@ def build_live_stats_text(tracer: Any, agent_config: dict[str, Any] | None = Non
|
||||
if agent_config:
|
||||
llm_config = agent_config["llm_config"]
|
||||
model = getattr(llm_config, "model_name", "Unknown")
|
||||
stats_text.append(f"🧠 Model: {model}")
|
||||
stats_text.append("Model ", style="dim")
|
||||
stats_text.append(model, style="white")
|
||||
stats_text.append("\n")
|
||||
|
||||
vuln_count = len(tracer.vulnerability_reports)
|
||||
tool_count = tracer.get_real_tool_count()
|
||||
agent_count = len(tracer.agents)
|
||||
|
||||
stats_text.append("🔍 Vulnerabilities: ", style="bold white")
|
||||
stats_text.append(f"{vuln_count}", style="dim white")
|
||||
stats_text.append("Vulnerabilities ", style="dim")
|
||||
stats_text.append(f"{vuln_count}", style="white")
|
||||
stats_text.append("\n")
|
||||
if vuln_count > 0:
|
||||
severity_counts = {"critical": 0, "high": 0, "medium": 0, "low": 0, "info": 0}
|
||||
@@ -330,33 +333,32 @@ def build_live_stats_text(tracer: Any, agent_config: dict[str, Any] | None = Non
|
||||
|
||||
stats_text.append("\n")
|
||||
|
||||
stats_text.append("🤖 Agents: ", style="bold white")
|
||||
stats_text.append(str(agent_count), style="dim white")
|
||||
stats_text.append(" • ", style="dim white")
|
||||
stats_text.append("🛠️ Tools: ", style="bold white")
|
||||
stats_text.append(str(tool_count), style="dim white")
|
||||
stats_text.append("Agents ", style="dim")
|
||||
stats_text.append(str(agent_count), style="white")
|
||||
stats_text.append(" · ", style="dim white")
|
||||
stats_text.append("Tools ", style="dim")
|
||||
stats_text.append(str(tool_count), style="white")
|
||||
|
||||
llm_stats = tracer.get_total_llm_stats()
|
||||
total_stats = llm_stats["total"]
|
||||
|
||||
stats_text.append("\n")
|
||||
|
||||
stats_text.append("📥 Input: ", style="bold white")
|
||||
stats_text.append(format_token_count(total_stats["input_tokens"]), style="dim white")
|
||||
stats_text.append("Input Tokens ", style="dim")
|
||||
stats_text.append(format_token_count(total_stats["input_tokens"]), style="white")
|
||||
|
||||
stats_text.append(" • ", style="dim white")
|
||||
stats_text.append("⚡ ", style="bold white")
|
||||
stats_text.append("Cached: ", style="bold white")
|
||||
stats_text.append(format_token_count(total_stats["cached_tokens"]), style="dim white")
|
||||
stats_text.append(" · ", style="dim white")
|
||||
stats_text.append("Cached Tokens ", style="dim")
|
||||
stats_text.append(format_token_count(total_stats["cached_tokens"]), style="#22c55e")
|
||||
|
||||
stats_text.append("\n")
|
||||
|
||||
stats_text.append("📤 Output: ", style="bold white")
|
||||
stats_text.append(format_token_count(total_stats["output_tokens"]), style="dim white")
|
||||
stats_text.append("Output Tokens ", style="dim")
|
||||
stats_text.append(format_token_count(total_stats["output_tokens"]), style="white")
|
||||
|
||||
stats_text.append(" • ", style="dim white")
|
||||
stats_text.append("💰 Cost: ", style="bold white")
|
||||
stats_text.append(f"${total_stats['cost']:.4f}", style="dim white")
|
||||
stats_text.append(" · ", style="dim white")
|
||||
stats_text.append("Cost ", style="dim")
|
||||
stats_text.append(f"${total_stats['cost']:.4f}", style="#fbbf24")
|
||||
|
||||
return stats_text
|
||||
|
||||
@@ -668,7 +670,6 @@ def clone_repository(repo_url: str, run_name: str, dest_name: str | None = None)
|
||||
|
||||
except subprocess.CalledProcessError as e:
|
||||
error_text = Text()
|
||||
error_text.append("❌ ", style="bold red")
|
||||
error_text.append("REPOSITORY CLONE FAILED", style="bold red")
|
||||
error_text.append("\n\n", style="white")
|
||||
error_text.append(f"Could not clone repository: {repo_url}\n", style="white")
|
||||
@@ -678,8 +679,8 @@ def clone_repository(repo_url: str, run_name: str, dest_name: str | None = None)
|
||||
|
||||
panel = Panel(
|
||||
error_text,
|
||||
title="[bold red]🛡️ STRIX CLONE ERROR",
|
||||
title_align="center",
|
||||
title="[bold white]STRIX",
|
||||
title_align="left",
|
||||
border_style="red",
|
||||
padding=(1, 2),
|
||||
)
|
||||
@@ -689,7 +690,6 @@ def clone_repository(repo_url: str, run_name: str, dest_name: str | None = None)
|
||||
sys.exit(1)
|
||||
except FileNotFoundError:
|
||||
error_text = Text()
|
||||
error_text.append("❌ ", style="bold red")
|
||||
error_text.append("GIT NOT FOUND", style="bold red")
|
||||
error_text.append("\n\n", style="white")
|
||||
error_text.append("Git is not installed or not available in PATH.\n", style="white")
|
||||
@@ -697,8 +697,8 @@ def clone_repository(repo_url: str, run_name: str, dest_name: str | None = None)
|
||||
|
||||
panel = Panel(
|
||||
error_text,
|
||||
title="[bold red]🛡️ STRIX CLONE ERROR",
|
||||
title_align="center",
|
||||
title="[bold white]STRIX",
|
||||
title_align="left",
|
||||
border_style="red",
|
||||
padding=(1, 2),
|
||||
)
|
||||
@@ -715,7 +715,6 @@ def check_docker_connection() -> Any:
|
||||
except DockerException:
|
||||
console = Console()
|
||||
error_text = Text()
|
||||
error_text.append("❌ ", style="bold red")
|
||||
error_text.append("DOCKER NOT AVAILABLE", style="bold red")
|
||||
error_text.append("\n\n", style="white")
|
||||
error_text.append("Cannot connect to Docker daemon.\n", style="white")
|
||||
@@ -726,8 +725,8 @@ def check_docker_connection() -> Any:
|
||||
|
||||
panel = Panel(
|
||||
error_text,
|
||||
title="[bold red]🛡️ STRIX STARTUP ERROR",
|
||||
title_align="center",
|
||||
title="[bold white]STRIX",
|
||||
title_align="left",
|
||||
border_style="red",
|
||||
padding=(1, 2),
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user