@@ -56,51 +56,73 @@ func (m *UI) modelInfo(width int) string {
5656 return common.ModelInfo(m.com.Styles, modelName, providerName, reasoningInfo, modelContext, width)
5757}
5858
59−// getDynamicHeightLimits will give us the num of items to show in each section based on the hight
59+// getDynamicHeightLimits will give us the num of items to show in each section based on the height
6060// some items are more important than others.
61−func getDynamicHeightLimits(availableHeight int) (maxFiles, maxLSPs, maxMCPs int) {
61+func getDynamicHeightLimits(availableHeight, fileCount, lspCount, mcpCount, skillCount int) (maxFiles, maxLSPs, maxMCPs, maxSkills int) {
6262 const (
63− minItemsPerSection = 2
64− defaultMaxFilesShown = 10
65− defaultMaxLSPsShown = 8
66− defaultMaxMCPsShown = 8
63+ minItemsPerSection = 2
64+ // Keep these high so dynamic layout uses available sidebar space
65+ // instead of hitting small hard limits.
66+ defaultMaxFilesShown = 1000
67+ defaultMaxLSPsShown = 1000
68+ defaultMaxMCPsShown = 1000
69+ defaultMaxSkillsShown = 1000
6770 minAvailableHeightLimit = 10
6871 )
6972
70− // If we have very little space, use minimum values
7173 if availableHeight < minAvailableHeightLimit {
72− return minItemsPerSection, minItemsPerSection, minItemsPerSection
74+ return minItemsPerSection, minItemsPerSection, minItemsPerSection, minItemsPerSection
7375 }
7476
75− // Distribute available height among the three sections
76− // Give priority to files, then LSPs, then MCPs
77− totalSections := 3
78− heightPerSection := availableHeight / totalSections
79−
80− // Calculate limits for each section, ensuring minimums
81− maxFiles = max(minItemsPerSection, min(defaultMaxFilesShown, heightPerSection))
82− maxLSPs = max(minItemsPerSection, min(defaultMaxLSPsShown, heightPerSection))
83− maxMCPs = max(minItemsPerSection, min(defaultMaxMCPsShown, heightPerSection))
84−
85− // If we have extra space, give it to files first
86− remainingHeight := availableHeight - (maxFiles + maxLSPs + maxMCPs)
87− if remainingHeight > 0 {
88− extraForFiles := min(remainingHeight, defaultMaxFilesShown-maxFiles)
89− maxFiles += extraForFiles
90− remainingHeight -= extraForFiles
91−
92− if remainingHeight > 0 {
93− extraForLSPs := min(remainingHeight, defaultMaxLSPsShown-maxLSPs)
94− maxLSPs += extraForLSPs
95− remainingHeight -= extraForLSPs
96−
97− if remainingHeight > 0 {
98− maxMCPs += min(remainingHeight, defaultMaxMCPsShown-maxMCPs)
77+ maxFiles = minItemsPerSection
78+ maxLSPs = minItemsPerSection
79+ maxMCPs = minItemsPerSection
80+ maxSkills = minItemsPerSection
81+
82+ remainingHeight := max(0, availableHeight-(minItemsPerSection*4))
83+
84+ sectionValues := []*int{&maxFiles, &maxLSPs, &maxMCPs, &maxSkills}
85+ sectionCaps := []int{defaultMaxFilesShown, defaultMaxLSPsShown, defaultMaxMCPsShown, defaultMaxSkillsShown}
86+ sectionNeeds := []int{max(0, fileCount-maxFiles), max(0, lspCount-maxLSPs), max(0, mcpCount-maxMCPs), max(0, skillCount-maxSkills)}
87+
88+ for remainingHeight > 0 {
89+ allocated := false
90+ for i, section := range sectionValues {
91+ if remainingHeight == 0 {
92+ break
93+ }
94+ if sectionNeeds[i] == 0 || *section >= sectionCaps[i] {
95+ continue
96+ }
97+ *section = *section + 1
98+ sectionNeeds[i]--
99+ remainingHeight--
100+ allocated = true
101+ }
102+ if !allocated {
103+ break
104+ }
105+ }
106+
107+ for remainingHeight > 0 {
108+ allocated := false
109+ for i, section := range sectionValues {
110+ if remainingHeight == 0 {
111+ break
112+ }
113+ if *section >= sectionCaps[i] {
114+ continue
99115 }
116+ *section = *section + 1
117+ remainingHeight--
118+ allocated = true
119+ }
120+ if !allocated {
121+ break
100122 }
101123 }
102124
103− return maxFiles, maxLSPs, maxMCPs
125+ return maxFiles, maxLSPs, maxMCPs, maxSkills
104126}
105127
106128// sidebar renders the chat sidebar containing session title, working
@@ -142,11 +164,31 @@ func (m *UI) drawSidebar(scr uv.Screen, area uv.Rectangle) {
142164 layout.Len(lipgloss.Height(sidebarHeader)),
143165 layout.Fill(1),
144166 ).Split(m.layout.sidebar).Assign(new(image.Rectangle), &remainingHeightArea)
145− remainingHeight := remainingHeightArea.Dy() - 10
146− maxFiles, maxLSPs, maxMCPs := getDynamicHeightLimits(remainingHeight)
167+ remainingHeight := remainingHeightArea.Dy() - 6
168+ filesCount := 0
169+ for _, f := range m.sessionFiles {
170+ if f.Additions == 0 && f.Deletions == 0 {
171+ continue
172+ }
173+ filesCount++
174+ }
175+
176+ lspsCount := len(m.lspStates)
177+
178+ mcpsCount := 0
179+ for _, mcpCfg := range m.com.Config().MCP.Sorted() {
180+ if _, ok := m.mcpStates[mcpCfg.Name]; ok {
181+ mcpsCount++
182+ }
183+ }
184+
185+ skillsCount := len(m.skillStatusItems())
186+
187+ maxFiles, maxLSPs, maxMCPs, maxSkills := getDynamicHeightLimits(remainingHeight, filesCount, lspsCount, mcpsCount, skillsCount)
147188
148189 lspSection := m.lspInfo(width, maxLSPs, true)
149190 mcpSection := m.mcpInfo(width, maxMCPs, true)
191+ skillsSection := m.skillsInfo(width, maxSkills, true)
150192 filesSection := m.filesInfo(m.com.Workspace.WorkingDir(), width, maxFiles, true)
151193
152194 uv.NewStyledString(
@@ -162,6 +204,8 @@ func (m *UI) drawSidebar(scr uv.Screen, area uv.Rectangle) {
162204 lspSection,
163205 "",
164206 mcpSection,
207+ "",
208+ skillsSection,
165209 ),
166210 ),
167211 ).Draw(scr, area)