Add ui.custom() for custom hook components with keyboard focus

- Add custom() to HookUIContext: returns { close, requestRender }
- Component receives keyboard input via handleInput()
- CustomMessageComponent default rendering now limits to 5 lines when collapsed
- Add snake.ts example hook with /snake command
This commit is contained in:
Mario Zechner 2025-12-27 03:17:38 +01:00
parent a8866d7a83
commit 14ad8d6228
9 changed files with 315 additions and 2 deletions

View file

@ -90,6 +90,7 @@ function createNoOpUIContext(): HookUIContext {
confirm: async () => false,
input: async () => null,
notify: () => {},
custom: () => ({ close: () => {}, requestRender: () => {} }),
};
}

View file

@ -13,8 +13,6 @@ export type {
AgentEndEvent,
AgentStartEvent,
BashToolResultEvent,
HookMessageRenderer,
HookMessageRenderOptions,
CustomToolResultEvent,
EditToolResultEvent,
ExecOptions,
@ -28,6 +26,8 @@ export type {
HookEventContext,
HookFactory,
HookMessage,
HookMessageRenderer,
HookMessageRenderOptions,
HookUIContext,
LsToolResultEvent,
ReadToolResultEvent,

View file

@ -52,6 +52,7 @@ const noOpUIContext: HookUIContext = {
confirm: async () => false,
input: async () => null,
notify: () => {},
custom: () => ({ close: () => {}, requestRender: () => {} }),
};
/**

View file

@ -54,6 +54,15 @@ export interface HookUIContext {
* Show a notification to the user.
*/
notify(message: string, type?: "info" | "warning" | "error"): void;
/**
* Show a custom component with keyboard focus.
* The component receives keyboard input via handleInput() if implemented.
*
* @param component - Component to display (implement handleInput for keyboard, dispose for cleanup)
* @returns Object with close() to restore normal UI and requestRender() to trigger redraw
*/
custom(component: Component & { dispose?(): void }): { close: () => void; requestRender: () => void };
}
/**