mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-24 11:25:50 -06:00
fix(tui): close selection overlays and report rejected handlers (#124876)
openSelector's onSelect fired the async handler with void and only closed the overlay after a successful await. A rejecting handler (e.g. setAgent -> setSession against a failing gateway) left the selector stranded open with an unhandled rejection: the TUI froze on the picker with no visible cause — a silent dead-end. Root cause: failure path missing from the overlay lifecycle. The handler now catches, surfaces the cause via chatLog, and always closes the overlay. Regression: /agent selection with a rejecting setSession asserts the overlay closes and the cause reaches the chat log — fails pre-fix.
This commit is contained in:
committed by
GitHub
parent
a4efa7c22b
commit
00990506c0
@@ -741,6 +741,28 @@ describe("tui command handlers", () => {
|
||||
expect(closeOverlay).toHaveBeenCalledWith(overlayHandle);
|
||||
});
|
||||
|
||||
it("closes the overlay and reports the cause when a selection handler rejects", async () => {
|
||||
const setSession = vi
|
||||
.fn()
|
||||
.mockRejectedValue(new Error("gateway unavailable")) as SetSessionMock;
|
||||
const { handleCommand, openOverlay, closeOverlay, overlayHandle, addSystem } = createHarness({
|
||||
setSession,
|
||||
agents: [{ id: "work" }],
|
||||
});
|
||||
|
||||
await handleCommand("/agent");
|
||||
const selector = firstMockArg(openOverlay, "openOverlay") as SelectableOverlay;
|
||||
selector?.onSelect?.({ value: "work", label: "work" });
|
||||
await flushAsyncSelect();
|
||||
|
||||
// The selector must not stay stranded open on a rejected selection, and
|
||||
// the failure must reach the chat log instead of an unhandled rejection.
|
||||
expect(closeOverlay).toHaveBeenCalledWith(overlayHandle);
|
||||
expect(
|
||||
addSystem.mock.calls.some(([line]) => String(line).includes("gateway unavailable")),
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
it("forwards /context list directly", async () => {
|
||||
const { handleCommand, sendChat, openOverlay } = createHarness();
|
||||
|
||||
|
||||
@@ -304,7 +304,13 @@ export function createCommandHandlers(context: CommandHandlerContext) {
|
||||
) => {
|
||||
selector.onSelect = (item) => {
|
||||
void (async () => {
|
||||
await onSelect(item.value);
|
||||
try {
|
||||
await onSelect(item.value);
|
||||
} catch (err) {
|
||||
// A rejected selection must not strand the overlay open with an
|
||||
// unhandled rejection; close it and surface the cause in chat.
|
||||
chatLog.addSystem(`selection failed: ${formatTuiErrorMessage(err)}`);
|
||||
}
|
||||
closeOverlayAndRender(overlayHandle);
|
||||
})();
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user