fix: ensure header visibility with explicit newline and nil checks

This commit is contained in:
大森 2026-05-10 15:00:41 +08:00
parent 8619a7f35c
commit 9fec5df6f7
2 changed files with 69 additions and 47 deletions

View File

@ -212,17 +212,18 @@ func (m *Model) updateLayout() {
rightWidth := 42
leftWidth := m.width - rightWidth - 3
headerHeight := 3
mainHeight := m.height - headerHeight - 1
inputHeight := 5
chatHeight := mainHeight - inputHeight
if chatHeight < 10 {
chatHeight = 10
headerHeight := 2
mainHeight := m.height - headerHeight
if mainHeight < 10 {
mainHeight = 10
}
chatHeight := mainHeight - 9
if chatHeight < 5 {
chatHeight = 5
}
m.textarea.SetWidth(leftWidth)
m.viewport.Width = leftWidth
m.viewport.Height = chatHeight
if !m.ready {
m.viewport = viewport.New(leftWidth, chatHeight)
@ -265,33 +266,18 @@ func (m Model) View() string {
return "Initializing..."
}
rightWidth := 42
leftWidth := m.width - rightWidth - 3
rightWidth := 40
leftWidth := m.width - rightWidth - 2
header := m.renderHeader()
headerHeight := lipgloss.Height(header)
mainHeight := m.height - headerHeight
inputHeight := 5
chatHeight := mainHeight - inputHeight
if chatHeight < 10 {
chatHeight = 10
}
chatBox := boxStyle.Width(leftWidth).Height(chatHeight).Render(m.viewport.View())
chatBox := boxStyle.Width(leftWidth).Height(m.height - 8).Render(m.viewport.View())
inputBox := boxStyle.Width(leftWidth).Render(m.textarea.View())
leftPanel := lipgloss.JoinVertical(lipgloss.Left, chatBox, inputBox)
stats := m.renderStats()
agents := m.renderAgents()
statsHeight := lipgloss.Height(stats)
agentsHeight := lipgloss.Height(agents)
remainingHeight := mainHeight - statsHeight - agentsHeight - 2
if remainingHeight < 3 {
remainingHeight = 3
}
empty := boxStyle.Width(rightWidth - 4).Height(remainingHeight).Render("")
empty := boxStyle.Width(rightWidth - 2).Height(m.height - lipgloss.Height(stats) - lipgloss.Height(agents) - 5).Render("")
rightPanel := lipgloss.JoinVertical(lipgloss.Left, stats, agents, empty)
if m.loading {
@ -299,19 +285,21 @@ func (m Model) View() string {
}
body := lipgloss.JoinHorizontal(lipgloss.Top, leftPanel, rightPanel)
return lipgloss.JoinVertical(lipgloss.Left, header, body)
return header + "\n" + body
}
func (m Model) renderHeader() string {
version := "v0.1.0"
title := titleStyle.Render("orca.agent ") + mutedStyle.Render(version)
title := "orca.agent " + version
line := strings.Repeat("─", m.width-2)
return lipgloss.NewStyle().
Width(m.width).
Padding(0, 1).
BorderBottom(true).
BorderStyle(lipgloss.NormalBorder()).
BorderForeground(lipgloss.Color(colors.border)).
Render(title)
Bold(true).
Foreground(lipgloss.Color(colors.primary)).
Render(title) + "\n" + lipgloss.NewStyle().
Foreground(lipgloss.Color(colors.border)).
Render(line)
}
func (m Model) renderStats() string {
@ -319,17 +307,23 @@ func (m Model) renderStats() string {
b.WriteString(titleStyle.Render("Statistics") + "\n\n")
tools := 0
if m.kernel != nil {
if tm := m.kernel.ToolManager(); tm != nil {
tools = tm.Count()
}
}
skills := 0
if m.kernel != nil {
if sm := m.kernel.SkillManager(); sm != nil {
skills = len(sm.ListSkills())
}
}
agents := 0
if m.kernel != nil {
if as := m.kernel.ActorSystem(); as != nil {
agents = as.AgentCount()
}
}
b.WriteString(statLabelStyle.Render("Tools: "))
b.WriteString(statValueStyle.Render(fmt.Sprintf("%d", tools)) + "\n")
@ -345,6 +339,7 @@ func (m Model) renderAgents() string {
var b strings.Builder
b.WriteString(titleStyle.Render("Active Agents") + "\n\n")
if m.kernel != nil {
if as := m.kernel.ActorSystem(); as != nil {
for _, info := range as.AgentInfos() {
status := "idle"
@ -356,6 +351,7 @@ func (m Model) renderAgents() string {
b.WriteString(fmt.Sprintf("• %s: %s\n", info.ID, style.Render(status)))
}
}
}
return boxStyle.Width(38).Render(b.String())
}

View File

@ -1,8 +1,11 @@
package tui
import (
"strings"
"testing"
"time"
"github.com/charmbracelet/bubbles/textarea"
)
func TestEventWriter(t *testing.T) {
@ -74,3 +77,26 @@ func TestModelFormatMessage(t *testing.T) {
t.Error("system message should not be empty")
}
}
func TestViewContainsHeader(t *testing.T) {
ta := textarea.New()
ta.ShowLineNumbers = false
ta.KeyMap.InsertNewline.SetEnabled(false)
m := Model{
width: 120,
height: 40,
textarea: ta,
messages: []ChatMessage{},
events: make(chan Event, 10),
agentRuns: make(map[string]bool),
}
m.updateLayout()
view := m.View()
if view == "Initializing..." {
t.Fatal("view should not be initializing")
}
if !strings.Contains(view, "orca.agent") {
t.Errorf("view should contain 'orca.agent', got:\n%s", view[:min(200, len(view))])
}
}