fix(tui): keep approval controls visible for long prompts (#1132)#1156
Merged
Aaronontheweb merged 4 commits intoMay 24, 2026
Merged
Conversation
…v#1132) Long shell_execute approval bodies in `netclaw chat` wrapped over many lines inside the Input panel and pushed the selection list and `[Enter] Confirm` hint past the panel cap, leaving the user unable to respond. Render a one-line summary plus a single-line truncated body with a `[Ctrl+V to view full]` affordance by default; Ctrl+V expands the body to a 5-row cap (with full text always available in the chat history pane above) while keeping all selection options on-screen. The wire-level `DisplayText` is untouched so non-TUI surfaces still see the full prompt. Adds headless ChatPageTests using Termina's VirtualTerminal and commits ASCII frame snapshots under tests/Tui/__snapshots__/ as the visual regression artifact for the issue.
Address scaling issues flagged in code review of the initial netclaw-dev#1132 fix. Previously the body width (76 cols), expanded body cap (5 rows), Input panel cap (14 rows), and status bar text were all hardcoded, producing clipped affordances on narrow terminals, clipped tails for >5-line bodies, and a layout that hit the cap exactly with the 5-option production approval set. - Inject IAnsiTerminal into ChatPage; read live width/height in the DynamicLayoutNode callback so body width, expanded body cap, and panel cap all scale with the actual terminal size. - Expanded body cap derives from terminal height and live option count: panelMax = max(8, height/2); bodyMax = panelMax - (4 + optionCount). - Status bar text now picks short/medium/full key-hint variants based on width and includes UiVersion in CombineLatest so resize re-emits. - Subscribe to ResizeEvent in OnBound and bump UiVersion to trigger a layout re-evaluation on terminal resize. - Restore the [PgUp/PgDn] Scroll hint to the pending-interaction key string (the design's stated escape hatch for >cap bodies). Adds four new headless tests covering 60-col narrow terminal, the 5-option production set in expanded mode, a 16-row small terminal (chat history must stay visible), and a terminal-resize round-trip.
The outer Input panel's HeightAuto(max) constraint was captured once at first navigation and never updated on terminal resize. Even though the inner DynamicLayoutNode re-evaluated body width and expanded-body caps on resize, the outer panel's frozen max prevented the layout from actually growing when the terminal got taller. Termina 0.10.0 adds ReactivePage.InvalidateLayout() which discards the cached layout tree and rebuilds via BuildLayout() with fresh state. Now the resize handler calls InvalidateLayout() so the panel cap follows _terminal.Height changes — completing the dynamic scaling fix for netclaw-dev#1132. Ref: Termina PR netclaw-dev#219 (ResizeEvent forwarding), PR netclaw-dev#220 (InvalidateLayout)
9f927b1 to
79b4595
Compare
Collaborator
Author
|
Haven't had a chance to test this locally but best as I can tell from the ASCII output from Termina's |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes #1132. Long
shell_executeapproval prompts (cdwith many path arguments, etc.) wrapped over many lines inside the Input panel and pushed both the selection list and the[Enter] Confirmstatus hint off-screen, leaving users unable to respond.The fix renders a summary + a bounded body + hint + selection list.
Ctrl+Vtoggles between collapsed (one-line truncated) and expanded (multi-line) body. All sizing scales with the terminal: body width, expanded body cap, Input panel cap, and status bar text are all derived from liveIAnsiTerminal.Width/Heightat each render, and the page subscribes toResizeEventto re-render on terminal resize.IAnsiTerminalis injected intoChatPage. TheDynamicLayoutNodecallback reads width/height every render.panelMax - (4 + optionCount)wherepanelMax = max(8, terminalHeight / 2). Adapts to the actualApprovalOptions.Countso the 5-option production set (Once, This chat, Always here, Always anywhere, Deny) doesn't clip.terminalWidth - 4; narrow terminals get a proportionally shorter truncation.[PgUp/PgDn] Scrollhint is restored to the pending-interaction state — the design's stated escape hatch for >cap bodies.DisplayText(ShellApprovalMatcher.FormatForDisplay,ToolAccessPolicy,SessionToolExecutionPipeline) is unchanged — non-TUI surfaces (headless-p, JSON-RPC, future channels) still see the full prompt.What the new screen looks like
Collapsed (default) on a 120-col terminal:
Expanded (after pressing
Ctrl+V) — body now scales to the available panel height:The tail of the body (
SENTINEL_TAIL_MARKER Patterns: cd) now renders inside the Input panel — earlier versions of this branch clipped it at a hardcoded 5-row cap.Full ASCII captures committed under
src/Netclaw.Cli.Tests/Tui/__snapshots__/chat-approval-{collapsed,expanded}.txt.Tests
ChatPageTestsexercises the fix headlessly via Termina'sVirtualTerminal(same pattern asApprovalsManagerPageTests):LongApprovalBody_KeepsControlsVisible— direct regression for UX: Long approval prompts hide choices #1132 at 120×40.CollapsedView_ShowsEllipsisAndCtrlVHint,CtrlV_TogglesFullBodyAndKeepsControlsVisible,NewInteraction_ResetsCollapsedState— toggle and state semantics.NarrowTerminal_PreservesCtrlVHint— 60-col terminal: Ctrl+V affordance must remain visible.FiveOptionApproval_AllOptionsVisibleWhenExpanded— the canonical production option set fits in expanded mode without clipping.SmallTerminal_PanelDoesNotEatChatHistory— 16-row terminal: the Input panel cap scales down so the chat history pane still renders.Resize_RerendersStatusBarAndBody— 120 → 50 col resize re-renders with the shortened status text.LongApprovalBody_RenderedFrameSnapshot— writes the ASCII frames above to__snapshots__/.Test plan
dotnet test src/Netclaw.Cli.Tests— 752/752 pass (9 ChatPage tests + 743 existing)dotnet slopwatch analyze— 0 issues./scripts/Add-FileHeaders.ps1 -Verify— cleannetclaw chatagainst a real provider; trigger a long approval; resize the terminal; confirm layout adapts andCtrl+Vworks as shown above.Marked draft
Per request, opening in draft so the rendering and scaling behavior can be reviewed before merging.