Hooks can render custom status (#385)

* Add ctx.ui.setStatus(key, text) API for hooks to display status in footer

- Add setStatus to HookUIContext interface
- Implement in interactive mode (FooterComponent)
- Implement in RPC mode (fire-and-forget)
- Add no-op implementations for headless contexts
- Multiple statuses displayed on single line, sorted by key
- Supports ANSI styling (hooks handle their own colors)

* Remove setStatus from changelog for now

* Fix hook status API to follow TUI rules

- Sanitize status text: replace newlines, tabs, carriage returns with spaces
- Truncate combined status line to terminal width using truncateToWidth
- Update JSDoc to document sanitization and truncation behavior
- Remove unused createHookUIContext method
- Add missing setStatus to test mock

* Add setStatus to changelog

* Use dim ellipsis for hook status truncation for consistency with footer style

---------

Co-authored-by: Mario Zechner <badlogicgames@gmail.com>
This commit is contained in:
Prateek Sunal 2026-01-02 02:05:37 +05:30 committed by GitHub
parent 89db7ed024
commit 9b2aa4a683
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 90 additions and 3 deletions

View file

@ -423,6 +423,10 @@ const name = await ctx.ui.input("Name:", "placeholder");
// Notification (non-blocking)
ctx.ui.notify("Done!", "info"); // "info" | "warning" | "error"
// Set status text in footer (persistent until cleared)
ctx.ui.setStatus("my-hook", "Processing 5/10..."); // Set status
ctx.ui.setStatus("my-hook", undefined); // Clear status
// Set the core input editor text (pre-fill prompts, generated content)
ctx.ui.setEditorText("Generated prompt text here...");
@ -430,6 +434,12 @@ ctx.ui.setEditorText("Generated prompt text here...");
const currentText = ctx.ui.getEditorText();
```
**Status text notes:**
- Multiple hooks can set their own status using unique keys
- Statuses are displayed on a single line in the footer, sorted alphabetically by key
- Text is sanitized (newlines/tabs replaced with spaces) and truncated to terminal width
- ANSI escape codes for styling are preserved
**Custom components:**
Show a custom TUI component with keyboard focus:
@ -731,7 +741,7 @@ See [examples/hooks/snake.ts](../examples/hooks/snake.ts) for a complete example
| RPC | JSON protocol | Host handles UI |
| Print (`-p`) | No-op (returns null/false) | Hooks run but can't prompt |
In print mode, `select()` returns `undefined`, `confirm()` returns `false`, `input()` returns `undefined`, `getEditorText()` returns `""`, and `setEditorText()` is a no-op. Design hooks to handle this by checking `ctx.hasUI`.
In print mode, `select()` returns `undefined`, `confirm()` returns `false`, `input()` returns `undefined`, `getEditorText()` returns `""`, and `setEditorText()`/`setStatus()` are no-ops. Design hooks to handle this by checking `ctx.hasUI`.
## Error Handling