feat(tui): structured event bus for live attack monitoring#390
Merged
Nicola Franco (franconicola) merged 1 commit intoMay 23, 2026
Merged
Conversation
The TUI previously regex-parsed stringified log lines to populate its Actions tab, which meant the panel was effectively dead (the matcher was never instantiated outside tests) and the per-attack progress bar was a 2-second time-based fake. The Tracker/StepTracker already produced structured events for the same data — they just never reached the TUI live. This change wires a thread-safe `TUIEventBus` (subscribe/unsubscribe/ emit) end-to-end from `HackAgent.hack(...)` through `orchestrator .execute(...)` and `TrackingCoordinator` into `Tracker` and `StepTracker`, replaces the orphan `_tui_app`/`_tui_log_callback` parameters with `_tui_event_bus`, and has the Actions viewer subscribe to `goal_started` / `goal_finalized` / `step_started` / `trace_added` events. The progress bar now advances against real `expected_total_ goals`. The Logs viewer gains a structured `_records` buffer with per-level filters, case-insensitive search, and save-to-file. Dead code (`actions_logger.py`, `views/dashboard.py`, `attach_tui_handler`/ `detach_tui_handler`) is removed; `HackAgentTUI.show_*` notification helpers and `action_refresh` now actually work. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
| with tracker.track_step("Failing", "STEP_X"): | ||
| raise RuntimeError("boom") | ||
|
|
||
| assert len(received) == 1 |
| path = v.save_logs_to_file() | ||
| assert path is not None | ||
| assert path.startswith(str(tmp_path)) | ||
| content = open(path).read() |
| def _on_event(event: Any) -> None: | ||
| try: | ||
| app.call_from_thread(self._handle_event, event) | ||
| except Exception: |
| if hasattr(descendant, "refresh_data"): | ||
| descendant.refresh_data() | ||
| return | ||
| except Exception: |
| return | ||
| try: | ||
| subs.remove(callback) | ||
| except ValueError: |
| try: | ||
| log_widget = self.query_one("#attack-log-display", RichLog) | ||
| log_widget.clear() | ||
| except Exception: |
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
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.
The TUI previously regex-parsed stringified log lines to populate its Actions tab, which meant the panel was effectively dead (the matcher was never instantiated outside tests) and the per-attack progress bar was a 2-second time-based fake. The Tracker/StepTracker already produced structured events for the same data — they just never reached the TUI live.
This change wires a thread-safe
TUIEventBus(subscribe/unsubscribe/ emit) end-to-end fromHackAgent.hack(...)throughorchestrator .execute(...)andTrackingCoordinatorintoTrackerandStepTracker, replaces the orphan_tui_app/_tui_log_callbackparameters with_tui_event_bus, and has the Actions viewer subscribe togoal_started/goal_finalized/step_started/trace_addedevents. The progress bar now advances against realexpected_total_ goals. The Logs viewer gains a structured_recordsbuffer with per-level filters, case-insensitive search, and save-to-file. Dead code (actions_logger.py,views/dashboard.py,attach_tui_handler/detach_tui_handler) is removed;HackAgentTUI.show_*notification helpers andaction_refreshnow actually work.