-
feat(tui): issue #13 — §5 layout reshape + Tools pane (v0.4.0)
released this
2026-05-23 21:41:16 -07:00 | 262 commits to main since this releaseReshape the TUI from vertical-stack single-pane to Horizontal
two-column with TabbedContent on the right; v1 has a single Tools
tab that consumes ToolStart/ToolResult SSE events previously
rendered inline in the transcript. Foundation for the rest of
design-brief §5; subsequent panes (Persona/AdminEvents/BifrostState/
ServerLog) plug in as sibling TabPanes when their substrate
blockers resolve.Three coupled pieces, all in-place amendments to issues #4 + #12:
- Layout: compose() yields Horizontal#main-row containing
Vertical#left-column (transcript + thinking-current + prompt) and
Vertical#right-column (TabbedContent#side-panes with
TabPane#tools-tab → RichLog#tools-log). Width split 2fr:1fr. CSS
dock rules narrow to per-container scope so thinking-current
toggling doesn't reflow the right column. - Tools pane: TuiPresenterState.render() signature widens with
tools_log: RichLog. ToolStart/ToolResult route there per INV-014;
every other event keeps its issue-#12 routing. Plain-label
fallback under render-exception preserves routing (INV-009). - Ctrl+1 binding + pane-name widget: BINDINGS gains
Binding("ctrl+1", "focus_tools") which programmatically sets
TabbedContent.active; Textual's default preserves Input focus per
INV-016 (test asserts; regression path documented).
Static#pane-name in the footer renders "Tools" v1 (static — no
tab-switch handler wiring lands in #13 per amendment-2 from
Volva paraphrase review).
CLI mode (--send) is unaffected by design per INV-018 — non-
interactive, no tabs concept; CLI keeps inline tool-event rendering.Contract: docs/contracts/issues/13.contract.md (drift-check clean,
two amendments applied from Volva contract-paraphrase pass).Tests: +9 net (TestLayoutShape × 7 + TestTuiPresenterState routing
× 3, minus 1 deprecated test_tool_start_demoted superseded by
test_tool_start_routes_to_tools_log). 236 total GREEN; ruff clean.Live smoke against personal Worldtree's mimir: tool-using turn
(KB search) populated tools_log with tool_start + tool_result for
search_library + read_note; transcript stayed chat-only with
worker_phase + thinking. Routing-not-duplication confirmed
end-to-end.Downloads
- Layout: compose() yields Horizontal#main-row containing