Bunli currently exposes useRuntime().exit() as the main way to finish a render-based command.
That makes sense as a thin wrapper over OpenTUI's manual cleanup model, but at the Bunli level it feels too low-level and easy to miss.
In practice, when building a render command, most authors are thinking in terms of:
- complete the flow
- cancel the flow
- dismiss the screen
not "shut down the renderer."
Because of that, it is easy to forget to call runtime.exit() in one of the submit / cancel / quit paths, which leaves the TUI hanging indefinitely.
Why this feels like a Bunli issue
OpenTUI itself is a lower-level renderer and explicitly expects applications to manage cleanup with renderer.destroy().
Bunli, however, is a higher-level CLI framework. Since it already wraps OpenTUI with useRuntime().exit(), it seems like a good place to provide a more semantic completion model for render commands instead of making every app manage renderer shutdown directly.
Suggested direction
It would be easier to use correctly if Bunli exposed higher-level lifecycle APIs such as:
useRuntime().complete()
useRuntime().cancel()
with exit() remaining available as the low-level primitive.
That would make common flows more natural:
onSubmit -> complete()
onCancel -> cancel()
onQuit -> cancel() or complete()
Possible follow-ups
Higher-level components could also optionally integrate with this automatically, for example:
- form-style components could support
closeOnSubmit / closeOnCancel
- pager-style components could support a built-in close behavior on quit
- development mode could warn when a render-only command never completes
Summary
This is less about changing OpenTUI's lifecycle model and more about Bunli providing a better authoring model on top of it.
Right now, render commands are easy to leave hanging because the only completion primitive exposed at the Bunli level is a manual renderer exit call.
Bunli currently exposes
useRuntime().exit()as the main way to finish arender-based command.That makes sense as a thin wrapper over OpenTUI's manual cleanup model, but at the Bunli level it feels too low-level and easy to miss.
In practice, when building a render command, most authors are thinking in terms of:
not "shut down the renderer."
Because of that, it is easy to forget to call
runtime.exit()in one of the submit / cancel / quit paths, which leaves the TUI hanging indefinitely.Why this feels like a Bunli issue
OpenTUI itself is a lower-level renderer and explicitly expects applications to manage cleanup with
renderer.destroy().Bunli, however, is a higher-level CLI framework. Since it already wraps OpenTUI with
useRuntime().exit(), it seems like a good place to provide a more semantic completion model for render commands instead of making every app manage renderer shutdown directly.Suggested direction
It would be easier to use correctly if Bunli exposed higher-level lifecycle APIs such as:
useRuntime().complete()useRuntime().cancel()with
exit()remaining available as the low-level primitive.That would make common flows more natural:
onSubmit -> complete()onCancel -> cancel()onQuit -> cancel()orcomplete()Possible follow-ups
Higher-level components could also optionally integrate with this automatically, for example:
closeOnSubmit/closeOnCancelSummary
This is less about changing OpenTUI's lifecycle model and more about Bunli providing a better authoring model on top of it.
Right now, render commands are easy to leave hanging because the only completion primitive exposed at the Bunli level is a manual renderer exit call.