[WIP] Split oversized TUI views and CLI command files - #525
Merged
Nicola Franco (franconicola) merged 10 commits intoJul 26, 2026
Conversation
3 tasks
| bias_gap_str = ( | ||
| f" Bias gap: [bold]{float(bias_gap):.3f}[/bold]" | ||
| ) | ||
| except (TypeError, ValueError): |
| _backend = self.create_backend() | ||
| _res_page = _backend.list_results(run_id=_rid, page=1, page_size=500) | ||
| run_results = list(_res_page.items) | ||
| except Exception: |
| if not attack_type_display: | ||
| attack_type_display = getattr(_att, "type", "") or "" | ||
| break | ||
| except Exception: |
| else run.timestamp.replace(tzinfo=tz.UTC) | ||
| ) | ||
| run_age = (now - run_timestamp).total_seconds() / 60 | ||
| except Exception: |
| ): | ||
| delta = run.completed_at - run.started_at | ||
| duration = f"{delta.total_seconds():.1f}s" | ||
| except Exception: |
Member
|
@claude[agent] fix the comments from co-pilot |
| from textual.drivers.linux_driver import LinuxDriver | ||
|
|
||
| LinuxDriver._query_in_band_window_resize = lambda self: None | ||
| except Exception: |
| from textual.drivers.linux_inline_driver import LinuxInlineDriver | ||
|
|
||
| LinuxInlineDriver._query_in_band_window_resize = lambda self: None | ||
| except Exception: |
| try: | ||
| if tui_log_handler in hackagent_logger.handlers: | ||
| hackagent_logger.removeHandler(tui_log_handler) | ||
| except Exception: |
| try: | ||
| self.query_one("#escalate-only-mitigated", Checkbox).display = is_chain | ||
| self.query_one("#escalate-only-mitigated-help", Static).display = is_chain | ||
| except Exception: |
Nicola Franco (franconicola)
marked this pull request as ready for review
July 26, 2026 16:05
Copilot started reviewing on behalf of
Nicola Franco (franconicola)
July 26, 2026 16:05
View session
There was a problem hiding this comment.
Pull request overview
This PR refactors oversized CLI/TUI modules into smaller packages, extracting reusable helpers (notably for hackagent eval config parsing and TUI views) and adding snapshot-based UI regression tests to guard layout changes.
Changes:
- Split
hackagent cli tuiviews into packages with router-style__init__.pyre-exports, and extracted results/attacks tab logic into mixins/modules. - Refactored
hackagent scaninto a package (helpers.py,command.py,quick.py) and adjusted unit tests to patch the new import paths. - Added
pytest-textual-snapshotand introduced snapshot tests + standalone Textual “app” harnesses forAttacksTabandResultsTab.
Reviewed changes
Copilot reviewed 64 out of 69 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/unit/cli/tui/test_view_snapshots.py | Adds snapshot tests for extracted TUI tabs. |
| tests/unit/cli/tui/snapshot_apps/init.py | Declares snapshot-app package. |
| tests/unit/cli/tui/snapshot_apps/attacks_tab_app.py | Standalone Textual app for AttacksTab snapshotting. |
| tests/unit/cli/tui/snapshot_apps/results_tab_app.py | Standalone Textual app for ResultsTab snapshotting. |
| tests/unit/cli/test_scan_command.py | Updates patch paths to new scan package structure. |
| tests/unit/cli/test_attack_config.py | Adds unit tests for parse_config / guardrail config helpers. |
| pyproject.toml | Adds pytest-textual-snapshot dev dependency. |
| hackagent/cli/main.py | Moves help/TUI bootstrap helpers into dedicated modules and adjusts imports/registration. |
| hackagent/cli/help_page.py | Extracts rich --help rendering into its own module. |
| hackagent/cli/bootstrap.py | Extracts default TUI launch + terminal patch + welcome screen. |
| hackagent/cli/commands/scan/init.py | Creates router module re-exporting scan API (compat surface). |
| hackagent/cli/commands/scan/command.py | Holds the scan click command (logic moved out of former monolith). |
| hackagent/cli/commands/scan/helpers.py | Extracts scan preset defaults + pure helpers (provider endpoint, ASR parsing). |
| hackagent/cli/commands/scan/quick.py | Extracts reusable run_quick_scan implementation behind hackagent eval. |
| hackagent/cli/commands/attack/init.py | Creates router module re-exporting eval surface + helpers. |
| hackagent/cli/commands/attack/catalog.py | Centralizes strategy metadata used by eval list/info. |
| hackagent/cli/commands/attack/options.py | Centralizes shared click options for strategy commands. |
| hackagent/cli/commands/attack/config.py | Implements parse_config/goal parsing/guardrail-config helpers. |
| hackagent/cli/commands/attack/runner.py | Shared execution path for all hackagent eval <strategy> commands. |
| hackagent/cli/commands/attack/display.py | Rich rendering helpers for eval command output. |
| hackagent/cli/commands/attack/group.py | Defines hackagent eval group and campaign entrypoint behavior. |
| hackagent/cli/commands/attack/info.py | Implements hackagent eval list/info. |
| hackagent/cli/commands/attack/strategies.py | Generates per-strategy hackagent eval <strategy> subcommands. |
| hackagent/cli/commands/attack/chain.py | Adds/maintains hackagent eval chain command. |
| hackagent/cli/tui/views/attacks/init.py | Router/re-export module preserving historical import surface. |
| hackagent/cli/tui/views/attacks/tab.py | New AttacksTab router composing extracted mixins. |
| hackagent/cli/tui/views/attacks/layout.py | Extracted widget-tree composition for AttacksTab. |
| hackagent/cli/tui/views/attacks/helpers.py | Extracted module-level constants/utilities for AttacksTab. |
| hackagent/cli/tui/views/attacks/runner.py | Extracted validation + worker-launch logic for AttacksTab. |
| hackagent/cli/tui/views/results/init.py | Router/re-export module preserving historical import surface. |
| hackagent/cli/tui/views/results/tab.py | New ResultsTab router composing extracted mixins. |
| hackagent/cli/tui/views/results/table.py | Extracted run-list table rendering for results view. |
| hackagent/cli/tui/views/results/details.py | Extracted right-panel run/result detail rendering. |
| hackagent/cli/tui/views/results/export.py | Extracted CSV/JSON export actions for results view. |
| hackagent/cli/tui/views/results/formatters/init.py | Aggregates pure formatting helpers for results view. |
| hackagent/cli/tui/views/results/formatters/datetimes.py | Extracted datetime coercion + local formatting. |
| hackagent/cli/tui/views/results/formatters/text.py | Extracted Rich escaping + message formatting utilities. |
| hackagent/cli/tui/views/results/formatters/summaries.py | Extracted summary/detail string builders for results/traces/config. |
| hackagent/cli/tui/views/results/formatters/run_report.py | Extracted run-level report header builder. |
| hackagent/cli/tui/attack_specs/init.py | Introduces TUI-local spec registry as a decoupled package. |
| hackagent/cli/tui/attack_specs/registry.py | Registry for ordered technique_key -> spec mapping. |
| hackagent/cli/tui/attack_specs/types.py | Dataclasses/enums for declarative form specs + validation. |
| hackagent/cli/tui/attack_specs/specs/init.py | Imports/registers all per-technique specs. |
| hackagent/cli/tui/attack_specs/specs/advprefix.py | Adds AdvPrefix spec. |
| hackagent/cli/tui/attack_specs/specs/autodan_turbo.py | Adds AutoDAN-Turbo spec. |
| hackagent/cli/tui/attack_specs/specs/baseline.py | Adds Baseline spec. |
| hackagent/cli/tui/attack_specs/specs/bon.py | Adds BoN spec. |
| hackagent/cli/tui/attack_specs/specs/cipherchat.py | Adds CipherChat spec. |
| hackagent/cli/tui/attack_specs/specs/fc.py | Adds FC-Attack spec. |
| hackagent/cli/tui/attack_specs/specs/flipattack.py | Adds FlipAttack spec. |
| hackagent/cli/tui/attack_specs/specs/h4rm3l.py | Adds h4rm3l spec. |
| hackagent/cli/tui/attack_specs/specs/mml.py | Adds MML spec. |
| hackagent/cli/tui/attack_specs/specs/pair.py | Adds PAIR spec. |
| hackagent/cli/tui/attack_specs/specs/pap.py | Adds PAP spec. |
| hackagent/cli/tui/attack_specs/specs/static_template.py | Adds Static Template spec. |
| hackagent/cli/tui/attack_specs/specs/tap.py | Adds TAP spec. |
| hackagent/cli/tui/attack_specs/specs/tfc.py | Adds tFC-Attack spec. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
418
to
+424
| if __name__ == "__main__": | ||
| cli() | ||
|
|
||
|
|
||
| # Add command groups | ||
| cli.add_command(config.config) | ||
| cli.add_command(agent.agent) |
Comment on lines
+226
to
+234
| def on_button_pressed(self, event: Button.Pressed) -> None: | ||
| """Handle button press events.""" | ||
| if event.button.id == "refresh-results": | ||
| self.refresh_data() | ||
| elif event.button.id == "export-csv": | ||
| self._export_results_csv() | ||
| elif event.button.id == "export-json": | ||
| self._export_results_json() | ||
|
|
Comment on lines
+41
to
+74
| for result in self.results_data: | ||
| # Get status | ||
| status = "Unknown" | ||
| if hasattr(result, "evaluation_status"): | ||
| status_val = result.evaluation_status | ||
| status = ( | ||
| status_val.value | ||
| if hasattr(status_val, "value") | ||
| else str(status_val) | ||
| ) | ||
|
|
||
| # Get created date | ||
| created = "Unknown" | ||
| if hasattr(result, "created_at") and result.created_at: | ||
| created = str(result.created_at) | ||
|
|
||
| # Calculate duration | ||
| duration = "N/A" | ||
| if hasattr(result, "run") and result.run: | ||
| run = result.run | ||
| if ( | ||
| hasattr(run, "started_at") | ||
| and run.started_at | ||
| and hasattr(run, "completed_at") | ||
| and run.completed_at | ||
| ): | ||
| try: | ||
| if isinstance(run.started_at, datetime) and isinstance( | ||
| run.completed_at, datetime | ||
| ): | ||
| delta = run.completed_at - run.started_at | ||
| duration = f"{delta.total_seconds():.1f}s" | ||
| except Exception: | ||
| pass |
Comment on lines
+253
to
+257
| def action_show_summary(self) -> None: | ||
| """Show a quick summary for the selected run.""" | ||
| if self.selected_result: | ||
| self._show_result_summary(self.selected_result) | ||
|
|
| self._show_advanced = ( | ||
| pinned or self._advanced_hover_preview or self._advanced_focus_preview | ||
| ) | ||
| except Exception: |
Agent-Logs-Url: https://github.com/AISecurityLab/hackagent/sessions/8f5a3923-b690-4604-a3d2-79d15cb36b4b Co-authored-by: franconicola <51865029+franconicola@users.noreply.github.com>
Agent-Logs-Url: https://github.com/AISecurityLab/hackagent/sessions/8f5a3923-b690-4604-a3d2-79d15cb36b4b Co-authored-by: franconicola <51865029+franconicola@users.noreply.github.com>
Agent-Logs-Url: https://github.com/AISecurityLab/hackagent/sessions/8f5a3923-b690-4604-a3d2-79d15cb36b4b Co-authored-by: franconicola <51865029+franconicola@users.noreply.github.com>
Agent-Logs-Url: https://github.com/AISecurityLab/hackagent/sessions/8f5a3923-b690-4604-a3d2-79d15cb36b4b Co-authored-by: franconicola <51865029+franconicola@users.noreply.github.com>
Agent-Logs-Url: https://github.com/AISecurityLab/hackagent/sessions/8f5a3923-b690-4604-a3d2-79d15cb36b4b Co-authored-by: franconicola <51865029+franconicola@users.noreply.github.com>
Agent-Logs-Url: https://github.com/AISecurityLab/hackagent/sessions/8f5a3923-b690-4604-a3d2-79d15cb36b4b Co-authored-by: franconicola <51865029+franconicola@users.noreply.github.com>
Agent-Logs-Url: https://github.com/AISecurityLab/hackagent/sessions/8f5a3923-b690-4604-a3d2-79d15cb36b4b Co-authored-by: franconicola <51865029+franconicola@users.noreply.github.com>
Agent-Logs-Url: https://github.com/AISecurityLab/hackagent/sessions/8f5a3923-b690-4604-a3d2-79d15cb36b4b Co-authored-by: franconicola <51865029+franconicola@users.noreply.github.com>
Agent-Logs-Url: https://github.com/AISecurityLab/hackagent/sessions/8f5a3923-b690-4604-a3d2-79d15cb36b4b Co-authored-by: franconicola <51865029+franconicola@users.noreply.github.com>
Nicola Franco (franconicola)
force-pushed
the
claude/split-oversized-tui-views
branch
from
July 26, 2026 16:23
d677b28 to
a46ea5d
Compare
Codecov Report❌ Patch coverage is 📢 Thoughts on this report? Let us know! |
Copilot stopped work on behalf of
Nicola Franco (franconicola) due to an error
July 26, 2026 17:40
Nicola Franco (franconicola)
deleted the
claude/split-oversized-tui-views
branch
July 26, 2026 19:21
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Thanks for asking me to work on this. I will get started on it and keep this PR's description up to date as I form a plan and make progress.