* fix(cli): restore banner, footer, and loading states in the OpenTUI shell
The batched OpenTUI migration restructured the original single-file backend
into modules and dropped three user-visible pieces of the chrome along the
way: the startup banner, the bottom status line, and the responding
spinner. The OpenTUI renderer therefore booted into a screen that looked
nothing like the ink one it was meant to replace.
Rebuild all three as their own modules and mount them in the app shell,
following the ink layout: banner at the top, loading indicator above the
composer, status line at the bottom.
Two defects carried over from the original implementation are fixed rather
than copied. The context-usage label was missing its percent sign, and the
approval-mode colour check compared against a label that never matched, so
the auto-edit mode fell through to the default colour.
The context-file count is intentionally not restored: the shell no longer
tracks it and the current ink footer dropped it too.
* fix(cli): tick the OpenTUI spinner at the rate ink uses
The restored spinner ran at 120ms, carried over from the pre-batch
implementation, while the ink responding spinner it mirrors runs the same
frame set at 80ms and the existing OpenTUI compaction spinner does too. The
same animation therefore looked visibly slower under one renderer.
Name the interval and set it to the shared rate. The frame set itself is
unchanged.
* fix(release): sync the OSS mirror by what the tag shipped, not by a variable
The workflow that mirrors a release to Aliyun OSS decided whether to expect
the bun/OpenTUI preview archives from a repository variable. A repository
variable describes the default branch, while the checkout and the downloaded
assets come from the tag being synced, and the workflow can be re-dispatched
for any tag. Re-syncing a tag cut before the preview flavor existed therefore
asked that tag's own verify script for archives the release never shipped:
v0.22.3 fails because its script does not know the flag at all, and v0.23.0
fails on a missing checksum entry.
Derive the flag once from the archives actually downloaded and let all three
consumers read it, so the mirror follows the release instead of the branch.
Two related gaps in the same gate are closed here. The test covering it
asserted only the variable name, so inverting the comparison and silently
changing the flavor's default polarity stayed green; it now pins the
operator. And the variable appeared in no documentation, so an operator had
no way to learn that leaving it unset is what keeps the flavor off.
* fix(cli): source the OpenTUI chrome from main's shared helpers
The restored banner, footer, and responding indicator had grown private
copies of mappings main already owns, so the two renderers could drift.
Route the approval-mode label through formatApprovalModeName, extract the
context-usage format and version-label rules into ink-free helpers both
trees consume, and take the spinner frames and loading phrases from the
shared constants and cycler.
Also truncate the footer rows and the indicator phrase to the terminal
width so a long branch, path, or phrase cannot wrap the chrome mid-turn,
and read typed Config accessors in the banner instead of structural
casts and a manual package.json read.