diff --git a/strix/interface/cli.py b/strix/interface/cli.py index d225e50..d382a80 100644 --- a/strix/interface/cli.py +++ b/strix/interface/cli.py @@ -21,7 +21,6 @@ from strix.telemetry.tracer import Tracer, set_global_tracer from .utils import ( build_live_stats_text, - format_resume_hint, format_vulnerability_report, ) @@ -140,10 +139,6 @@ async def run_cli(args: Any) -> None: # noqa: PLR0915 def signal_handler(_signum: int, _frame: Any) -> None: tracer.cleanup() - hint = format_resume_hint(args.run_name) - if hint is not None: - console.print() - console.print(hint) sys.exit(1) atexit.register(cleanup_on_exit) @@ -217,10 +212,6 @@ async def run_cli(args: Any) -> None: # noqa: PLR0915 except Exception as e: console.print(f"[bold red]Error during penetration test:[/] {e}") - hint = format_resume_hint(args.run_name) - if hint is not None: - console.print() - console.print(hint) raise if tracer.final_scan_result: diff --git a/strix/interface/main.py b/strix/interface/main.py index 488e8be..96002c5 100644 --- a/strix/interface/main.py +++ b/strix/interface/main.py @@ -464,6 +464,14 @@ def display_completion_message(args: argparse.Namespace, results_path: Path) -> results_text.append(str(results_path), style="#60a5fa") panel_parts.extend(["\n", results_text]) + if not scan_completed: + resume_text = Text() + resume_text.append("\n") + resume_text.append("Resume", style="dim") + resume_text.append(" ") + resume_text.append(f"strix --run-name {args.run_name}", style="#22c55e") + panel_parts.extend(["\n", resume_text]) + panel_content = Text.assemble(*panel_parts) border_style = "#22c55e" if scan_completed else "#eab308" diff --git a/strix/interface/tui.py b/strix/interface/tui.py index 3623271..1e1d9af 100644 --- a/strix/interface/tui.py +++ b/strix/interface/tui.py @@ -35,7 +35,7 @@ from strix.config import load_settings from strix.interface.tool_components.agent_message_renderer import AgentMessageRenderer from strix.interface.tool_components.registry import get_tool_renderer from strix.interface.tool_components.user_message_renderer import UserMessageRenderer -from strix.interface.utils import build_tui_stats_text, format_resume_hint +from strix.interface.utils import build_tui_stats_text from strix.orchestration.scan import run_strix_scan from strix.runtime import session_manager from strix.telemetry.tracer import Tracer, set_global_tracer @@ -1991,16 +1991,4 @@ class StrixTUIApp(App): # type: ignore[misc] async def run_tui(args: argparse.Namespace) -> None: """Run strix in interactive TUI mode with textual.""" app = StrixTUIApp(args) - try: - await app.run_async() - finally: - # After Textual restores the real terminal, print the resume - # hint so the user knows the exact ``strix --run-name X`` - # invocation that picks up where they left off. - from rich.console import Console - - hint = format_resume_hint(getattr(args, "run_name", None)) - if hint is not None: - console = Console() - console.print() - console.print(hint) + await app.run_async() diff --git a/strix/interface/utils.py b/strix/interface/utils.py index ddf95e3..1acd4a7 100644 --- a/strix/interface/utils.py +++ b/strix/interface/utils.py @@ -1449,37 +1449,3 @@ def validate_config_file(config_path: str) -> Path: sys.exit(1) return path - - -def format_resume_hint(run_name: str | None) -> Panel | None: - """Tell the user how to resume the current run, if it persisted state. - - Returns a Rich :class:`Panel` ready to ``console.print`` when - ``strix_runs//bus.json`` exists (i.e. the scan registered - at least the root agent and has snapshot state to resume from). - Returns ``None`` when there's nothing to resume — e.g. the user hit - Ctrl+C before sandbox bring-up, or no run-name was assigned yet. - - Mirrors the auto-resume contract in ``orchestration/scan.py``: - re-running with the same ``--run-name`` picks up where this scan - left off; deleting ``strix_runs//`` forces a fresh start. - """ - if not run_name: - return None - run_dir = Path("strix_runs") / run_name - if not (run_dir / "bus.json").exists(): - return None - - text = Text() - text.append("Run paused. Resume any time with:\n\n", style="white") - text.append(f" strix --run-name {run_name}\n", style="bold #60a5fa") - text.append("\nOr delete ", style="dim") - text.append(f"strix_runs/{run_name}/", style="bold dim") - text.append(" to start fresh.", style="dim") - return Panel( - text, - title="[bold white]STRIX", - title_align="left", - border_style="#60a5fa", - padding=(1, 2), - )