commit 0410ef7ba8957da5063c5a28a67ec1cb6b575f30 equwal <13551856+equwal@users.noreply.github.com> 2026-10-03 19:17:32 -0700 Report an error when no Wayland session can show bemenu Over SSH on g, WAYLAND_DISPLAY is unset. bemenu then exits with code 1, the same code as Escape, so handoff.py told the agent that the user answered Not done. MenuDialog now refuses to start without WAYLAND_DISPLAY, and the agent gets status error. Release 0.6.1.
.claude-plugin/marketplace.json | 2 +- .claude-plugin/plugin.json | 2 +- skills/deploy-handoff/handoff.py | 3 +++ skills/deploy-handoff/test_handoff.py | 11 +++++++++++ 4 files changed, 16 insertions(+), 2 deletions(-)
diff --git a/.claude-plugin/marketplace.json b/.claude-plugin/marketplace.json index c0655a2..60cfaf3 100644 --- a/.claude-plugin/marketplace.json +++ b/.claude-plugin/marketplace.json @@ -10,7 +10,7 @@ { "name": "deploy-handoff", "description": "Drives your browser through deploy, billing, and sign-in pages, and opens pull request forms. Then a dialog shows you the final click. Claude never makes it for you.", - "version": "0.6.0", + "version": "0.6.1", "author": { "name": "equwal" }, diff --git a/.claude-plugin/plugin.json b/.claude-plugin/plugin.json index 8808ccd..c2d102c 100644 --- a/.claude-plugin/plugin.json +++ b/.claude-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "deploy-handoff", - "version": "0.6.0", + "version": "0.6.1", "description": "Drives your browser through deploy, billing, and sign-in pages, and opens pull request forms. Then a dialog shows you the final click. Claude never makes it for you.", "author": { "name": "equwal", diff --git a/skills/deploy-handoff/handoff.py b/skills/deploy-handoff/handoff.py index e597666..e08a80e 100644 --- a/skills/deploy-handoff/handoff.py +++ b/skills/deploy-handoff/handoff.py @@ -529,6 +529,9 @@ class MenuDialog: def __init__(self, request: Request, timeout_minutes: float, reopen: Callable[[], None]): if shutil.which("bemenu") is None: raise HandoffError("Cannot show the steps: install Python Tk or bemenu.") + # Without a session, bemenu exits as if the user pressed Escape. + if not os.environ.get("WAYLAND_DISPLAY"): + raise HandoffError("Cannot show the steps: WAYLAND_DISPLAY is not set.") self.title = request.title self.deadline = time.monotonic() + timeout_minutes * 60 steps = [f"{number}. {step}" for number, step in enumerate(request.steps, 1)] diff --git a/skills/deploy-handoff/test_handoff.py b/skills/deploy-handoff/test_handoff.py index 86ff32d..26223ca 100644 --- a/skills/deploy-handoff/test_handoff.py +++ b/skills/deploy-handoff/test_handoff.py @@ -654,6 +654,9 @@ class MenuDialogTest(unittest.TestCase): which = mock.patch("shutil.which", return_value="/usr/bin/bemenu") which.start() self.addCleanup(which.stop) + display = mock.patch.dict("os.environ", {"WAYLAND_DISPLAY": "wayland-1"}) + display.start() + self.addCleanup(display.stop) self.request = Request("Publish 1.2", "https://github.com/o", ("Click it.",)) def answer(self, *results: subprocess.CompletedProcess[str] | Exception) -> mock.MagicMock: @@ -706,6 +709,14 @@ class MenuDialogTest(unittest.TestCase): ): handoff.MenuDialog(self.request, 1, lambda: None) + def test_no_wayland_session_is_an_error(self) -> None: + # Over SSH on g, bemenu exited with code 1 and the script said "not_done". + with ( + mock.patch.dict("os.environ", {"WAYLAND_DISPLAY": ""}), + self.assertRaises(HandoffError), + ): + handoff.MenuDialog(self.request, 1, lambda: None) + class MainTest(unittest.TestCase): """Test main with a fake browser and a fake dialog."""