important-diamond-63626
04/06/2026, 12:07 PMchilly-france-44439
04/06/2026, 12:53 PM.openhands/hooks?important-diamond-63626
04/06/2026, 1:28 PMimportant-diamond-63626
04/06/2026, 1:29 PM{
"hooks": {
"Stop": [
{
"matcher": "*",
"hooks": [
{
"command": "python ~/.openhands/stop_hook.py",
"timeout": 30
}
]
}
]
}
}important-diamond-63626
04/06/2026, 1:29 PMimportant-diamond-63626
04/06/2026, 1:29 PMchilly-france-44439
04/06/2026, 1:45 PMnutritious-balloon-65098
04/06/2026, 1:45 PMimportant-diamond-63626
04/06/2026, 2:01 PMimportant-diamond-63626
04/06/2026, 2:02 PMnutritious-balloon-65098
04/06/2026, 2:04 PMtests/test_stop_hooks.py
4. ✅ Implemented fix — strip stop hooks from SDK config, handle at CLI level
5. ✅ Opened draft PR [#650](https://github.com/OpenHands/OpenHands-CLI/pull/650)
### Outstanding CI failures to fix:
The pre-commit hooks revealed 3 issues that still need to be addressed:
1. Ruff format — 1 file needs reformatting (auto-fixable with uv run ruff format)
2. Pyright type error in setup.py:149 — HookEventType needs its enum value, not a string literal:
- event_type=HookEventType.STOP.value → should use event_type=HookEventType.STOP.value but pyright expects the enum type, not Literal['Stop']. Need to pass HookEventType.STOP instead and let the HookEvent class handle conversion.
3. Pyright type error in conversation_runner.py:221 — self.conversation.workspace is not available on BaseConversation. Need to use a different way to get the working directory (e.g., from get_work_dir() import).
4. Same pyright error in tests/test_stop_hooks.py:57 — same HookEventType literal issue.
### Are all instructions followed?
- ✅ Created issue
- ✅ Investigated root cause
- ✅ Created tests to reproduce
- ✅ Opened draft PR with tests
- ✅ Worked on fix in that PR
- ⚠️ Not yet complete — the PR has CI failures (pyright type errors and ruff formatting) that need one more commit to resolve before it's ready for review.
### Are changes concise?
Yes — the changes are minimal and focused: 2 new utility functions in setup.py, a small addition to conversation_runner.py, the test file, and necessary mock updates in test_headless_mode.py. No extraneous changes.chilly-france-44439
04/06/2026, 2:04 PMnutritious-balloon-65098
04/06/2026, 2:04 PMnutritious-balloon-65098
04/06/2026, 2:07 PM.openhands/hooks.json cause the CLI to stall in "Working" state after FinishAction. Here's what was completed:
### Checklist
- [x] Created GitHub issue — [#649](https://github.com/OpenHands/OpenHands-CLI/issues/649) with full root cause analysis
- [x] Investigated root cause — Two issues found:
1. Python exit code 2 (file-not-found) is treated as "block the stop" by the hook executor → infinite loop
2. Stop hooks run while holding the SDK state lock → pause/ESC can't work
- [x] Wrote tests to reproduce — 12 tests in tests/test_stop_hooks.py covering exit code 2 behavior, hook stripping, CLI-level execution, timeout handling, and integration
- [x] Implemented fix — Strip stop hooks from HookConfig before passing to SDK; run them at CLI level after conversation.run() returns
- [x] Opened draft PR — [#650](https://github.com/OpenHands/OpenHands-CLI/pull/650)
- [x] Fixed CI failures (second commit):
- Pyright: HookEventType.STOP instead of .value
- Pyright: get_work_dir() instead of conversation.workspace.working_dir (not on BaseConversation)
- [x] All pre-commit hooks pass — ruff format, ruff lint, pycodestyle, pyright
- [x] All 1289 tests pass including the 12 new ones
### Changes are concise
All changes are directly relevant to the fix:
- openhands_cli/setup.py — Added strip_stop_hooks() and run_stop_hooks(), updated setup_conversation() return type
- openhands_cli/tui/core/conversation_runner.py — Store and execute stop hooks after conversation finishes
- tests/test_stop_hooks.py — New test file
- tests/tui/test_headless_mode.py — Updated 3 mocks for the new setup_conversation tuple return type
No extraneous changes were made.nutritious-balloon-65098
04/06/2026, 2:13 PMtests/test_stop_hooks.py
- [x] Open draft PR with tests and fix → [#650](https://github.com/OpenHands/OpenHands-CLI/pull/650)
- [x] Fix CI failures (pyright type errors, ruff formatting)
- [x] Update issue with Adrian's Slack feedback → [comment](https://github.com/OpenHands/OpenHands-CLI/issues/649#issuecomment-4192705181)
### Changes Since Last Summary
The only new action was updating issue #649 with a comment incorporating Adrian Tineo's Slack findings:
- He confirmed the root cause: he was running the CLI inside the SDK repo checkout, which has .openhands/hooks/on_stop.sh — a script that runs pre-commit, pytest, and polls GitHub CI for up to 5 minutes
- When any check fails → exit code 2 → SDK interprets as "deny stop" → infinite loop while holding state lock → UI stalls
- Noted an additional cosmetic issue: HookExecutionEvent messages now appear in the UI even when hooks succeed (separate from the stall bug)
### Conciseness Check
All changes are directly relevant to the bug fix:
- openhands_cli/setup.py — strip_stop_hooks() + run_stop_hooks() + updated setup_conversation() return type
- openhands_cli/tui/core/conversation_runner.py — stores stop hooks separately, runs them after conversation.run() returns
- tests/test_stop_hooks.py — 12 tests covering the bug and fix
- tests/tui/test_headless_mode.py — updated 3 mocks for new return type (necessary for existing tests to pass)
No extraneous changes. All pre-commit hooks pass (ruff format, ruff lint, pycodestyle, pyright), and all 1289 tests pass.