From 4231098ab0170107b38f13680ca854cc8e598d0a Mon Sep 17 00:00:00 2001 From: Andrew Barnes Date: Sun, 12 Jul 2026 16:21:48 -0400 Subject: [PATCH] fix(hooks): emit valid Codex cleanup output --- src/serena/hooks.py | 10 +++++++++- test/serena/test_hooks.py | 21 +++++++++++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/src/serena/hooks.py b/src/serena/hooks.py index e4c76769c6..8071f48a3d 100644 --- a/src/serena/hooks.py +++ b/src/serena/hooks.py @@ -591,7 +591,15 @@ def activate(client: str) -> None: @click.command("cleanup", help="Set this as hook at session end all hook data for the current session") @_client_option def cleanup(client: str) -> None: - SessionEndCleanupHook(HookClient(client)).execute() + hook_client = HookClient(client) + try: + SessionEndCleanupHook(hook_client).execute() + except Exception as exc: + if hook_client != HookClient.CODEX: + raise + click.echo(f"Serena cleanup failed: {exc}", err=True) + if hook_client == HookClient.CODEX: + click.echo(json.dumps({"continue": True})) @staticmethod @click.command( diff --git a/test/serena/test_hooks.py b/test/serena/test_hooks.py index d7287678b9..8030e1275c 100644 --- a/test/serena/test_hooks.py +++ b/test/serena/test_hooks.py @@ -693,6 +693,27 @@ def test_cleanup_command(self, tmp_path: Path): assert result.exit_code == 0 assert not session_dir.exists() + def test_codex_cleanup_emits_valid_stop_hook_json(self, tmp_path: Path): + runner = CliRunner() + stdin_json = json.dumps({"session_id": "codex-cleanup"}) + with patch("serena.hooks.serena_home_dir", str(tmp_path)): + result = runner.invoke(hook_commands, ["cleanup", "--client", "codex"], input=stdin_json) + + assert result.exit_code == 0 + assert json.loads(result.stdout) == {"continue": True} + + def test_codex_cleanup_without_session_id_still_emits_valid_json(self): + runner = CliRunner() + result = runner.invoke( + hook_commands, + ["cleanup", "--client", "codex"], + input=json.dumps({"stop_hook_active": False}), + ) + + assert result.exit_code == 0 + assert json.loads(result.stdout) == {"continue": True} + assert "Session ID is required" in result.stderr + def test_remind_command(self, tmp_path: Path): """Invoke the remind command enough times to trigger a deny.""" runner = CliRunner()