diff --git a/mcp_server/cli.py b/mcp_server/cli.py index ac716e5..d64deec 100644 --- a/mcp_server/cli.py +++ b/mcp_server/cli.py @@ -266,7 +266,7 @@ async def cmd_retry_generation(args: argparse.Namespace) -> int: print(f"Using project root: {root}") set_project_root(root) - generation_id = resolve_generation_id(None, root) + generation_id = resolve_generation_id(args.generation_id, root) if not generation_id: print("No previous generation found. Run `specflow run-generation` to start one.") return 0 @@ -564,7 +564,13 @@ def _build_parser() -> argparse.ArgumentParser: subparsers.add_parser("check-status", help="Check progress of a running generation") # retry-generation - subparsers.add_parser("retry-generation", help="Retry a failed generation") + p_retry = subparsers.add_parser("retry-generation", help="Retry a failed generation") + p_retry.add_argument( + "--generation-id", + default=None, + dest="generation_id", + help="Generation ID (default: from specflow_session.json)", + ) # download-outputs p_dl = subparsers.add_parser( diff --git a/mcp_server/tests/test_cli.py b/mcp_server/tests/test_cli.py index 9c93c75..b64e39a 100644 --- a/mcp_server/tests/test_cli.py +++ b/mcp_server/tests/test_cli.py @@ -283,7 +283,7 @@ async def test_calls_retry_endpoint(self, tmp_project): from services.session import write_session write_session("gen-xyz", tmp_project) - args = SimpleNamespace(root_path=str(tmp_project), command="retry-generation") + args = SimpleNamespace(root_path=str(tmp_project), command="retry-generation", generation_id=None) # check_status_safe returns failed → proceed to retry POST with patch( @@ -308,7 +308,7 @@ async def test_blocks_when_already_running(self, tmp_project, capsys): from services.session import write_session write_session("gen-running", tmp_project) - args = SimpleNamespace(root_path=str(tmp_project), command="retry-generation") + args = SimpleNamespace(root_path=str(tmp_project), command="retry-generation", generation_id=None) with patch( "services.tool_helpers.check_status_safe", diff --git a/mcp_server/tests/test_tui_app.py b/mcp_server/tests/test_tui_app.py index 7b70857..07aabfb 100644 --- a/mcp_server/tests/test_tui_app.py +++ b/mcp_server/tests/test_tui_app.py @@ -1136,13 +1136,13 @@ async def test_retry_runs_action_when_confirmed(self): patch.object(app, "push_screen_wait", new=AsyncMock(return_value=True)), patch.object(screen, "_run_suspended", new=AsyncMock()) as run_susp, # do_retry is async; force a sync mock so the flow's - # ``do_retry(root)`` yields a sentinel, not a live coroutine. + # ``do_retry(root, generation_id)`` yields a sentinel, not a live coroutine. patch( "tui.app.actions.do_retry", new=MagicMock(return_value="retry-coro") ) as do_retry, ): await screen._retry_flow() - do_retry.assert_called_once_with(app.root) + do_retry.assert_called_once_with(app.root, "gen_x") run_susp.assert_awaited_once_with("retry-coro") @pytest.mark.asyncio diff --git a/mcp_server/tui/actions.py b/mcp_server/tui/actions.py index d9ec9b7..556a32c 100644 --- a/mcp_server/tui/actions.py +++ b/mcp_server/tui/actions.py @@ -44,9 +44,11 @@ def _ns(**overrides: object) -> SimpleNamespace: return SimpleNamespace(**base) -async def do_retry(root: Path) -> int: +async def do_retry(root: Path, generation_id: str | None = None) -> int: """Retry the current generation (reuses ``cmd_retry_generation`` guards).""" - return await cli.cmd_retry_generation(_ns(root_path=str(root))) + return await cli.cmd_retry_generation( + _ns(root_path=str(root), generation_id=generation_id) + ) async def do_clear_set(set_number: int) -> int: diff --git a/mcp_server/tui/app.py b/mcp_server/tui/app.py index c909ad5..243c00e 100644 --- a/mcp_server/tui/app.py +++ b/mcp_server/tui/app.py @@ -628,7 +628,7 @@ async def _retry_flow(self) -> None: ) ) if ok: - await self._run_suspended(actions.do_retry(self.app.root)) + await self._run_suspended(actions.do_retry(self.app.root, self._generation_id)) def action_clear(self) -> None: self.run_worker(self._clear_flow(), exclusive=True)