Skip to content

Commit 184aa6c

Browse files
committed
✨ feat: add persistent AI environment info bar to TUI
1 parent 72b282b commit 184aa6c

1 file changed

Lines changed: 65 additions & 51 deletions

File tree

cmd/vibeaura/chat.go

Lines changed: 65 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -243,11 +243,18 @@ var (
243243
Padding(0, 1).
244244
Bold(true)
245245

246-
statusMessageStyle = lipgloss.NewStyle().
246+
statusMessageStyle = lipgloss.NewStyle().
247+
Foreground(lipgloss.Color("#7D56F4")).
248+
Bold(true)
249+
250+
envStyle = lipgloss.NewStyle().
251+
Foreground(lipgloss.Color("#626262")).
252+
Italic(true)
253+
254+
envValueStyle = lipgloss.NewStyle().
247255
Foreground(lipgloss.Color("#7D56F4")).
248256
Bold(true)
249-
)
250-
257+
)
251258
type chatState struct {
252259
Messages []string `json:"messages"`
253260
Input string `json:"input"`
@@ -2294,54 +2301,61 @@ func (m *model) View() string {
22942301
)
22952302
}
22962303

2297-
// 3. Status Bar (Dynamic)
2298-
statusBar := ""
2299-
if m.isThinking || m.isStreaming {
2300-
statusIcon := m.lastStatus.Icon
2301-
if statusIcon == "" {
2302-
statusIcon = "⏳"
2303-
}
2304-
if m.isStreaming {
2305-
statusIcon = "📡"
2306-
}
2307-
2308-
step := m.lastStatus.Step
2309-
if step == "" && m.isStreaming {
2310-
step = "STREAMING"
2311-
}
2312-
2313-
label := statusLabelStyle.Render(fmt.Sprintf(" %s %s ", statusIcon, strings.ToUpper(step)))
2314-
msg := statusMessageStyle.Render(" " + m.lastStatus.Message)
2315-
if m.isStreaming {
2316-
msg = statusMessageStyle.Render(" Receiving response...")
2317-
}
2318-
statusBar = "\n" + label + msg + "\n"
2319-
} else if m.lastUsage.TotalTokens > 0 {
2320-
usageInfo := fmt.Sprintf(" 🪙 Tokens: %d (In: %d, Out: %d)",
2321-
m.lastUsage.TotalTokens, m.lastUsage.InputTokens, m.lastUsage.OutputTokens)
2322-
if m.lastUsage.Cost > 0 {
2323-
usageInfo += fmt.Sprintf(" | 💵 Cost: $%.4f", m.lastUsage.Cost)
2324-
}
2325-
statusBar = "\n" + subtleStyle.Render(usageInfo) + "\n"
2326-
}
2327-
// 4. Input Box
2328-
inputView := m.textarea.View()
2329-
if m.focus == focusInput {
2330-
inputView = activeBorder.Width(m.width - 2).Render(inputView)
2331-
} else {
2332-
inputView = inactiveBorder.Width(m.width - 2).Render(inputView)
2333-
}
2334-
2335-
view := fmt.Sprintf(
2336-
"%s\n%s\n%s\n%s%s\n%s",
2337-
header,
2338-
lipgloss.NewStyle().Foreground(lipgloss.Color("#444444")).Render(border),
2339-
mainContent,
2340-
lipgloss.NewStyle().Foreground(lipgloss.Color("#444444")).Render(border),
2341-
statusBar,
2342-
inputView,
2343-
)
2344-
2304+
// 3. Status Bar (Dynamic)
2305+
cfg := m.brain.Config()
2306+
envBar := fmt.Sprintf(" %s %s │ %s %s │ %s %s ",
2307+
envStyle.Render("Provider:"), envValueStyle.Render(cfg.Model.Provider),
2308+
envStyle.Render("Model:"), envValueStyle.Render(cfg.Model.Name),
2309+
envStyle.Render("Agent:"), envValueStyle.Render(cfg.Agent.Mode),
2310+
)
2311+
2312+
statusBar := ""
2313+
if m.isThinking || m.isStreaming {
2314+
statusIcon := m.lastStatus.Icon
2315+
if statusIcon == "" {
2316+
statusIcon = "⏳"
2317+
}
2318+
if m.isStreaming {
2319+
statusIcon = "📡"
2320+
}
2321+
2322+
step := m.lastStatus.Step
2323+
if step == "" && m.isStreaming {
2324+
step = "STREAMING"
2325+
}
2326+
2327+
label := statusLabelStyle.Render(fmt.Sprintf(" %s %s ", statusIcon, strings.ToUpper(step)))
2328+
msg := statusMessageStyle.Render(" " + m.lastStatus.Message)
2329+
if m.isStreaming {
2330+
msg = statusMessageStyle.Render(" Receiving response...")
2331+
}
2332+
statusBar = "\n" + label + msg + "\n"
2333+
} else if m.lastUsage.TotalTokens > 0 {
2334+
usageInfo := fmt.Sprintf(" 🪙 Tokens: %d (In: %d, Out: %d)",
2335+
m.lastUsage.TotalTokens, m.lastUsage.InputTokens, m.lastUsage.OutputTokens)
2336+
if m.lastUsage.Cost > 0 {
2337+
usageInfo += fmt.Sprintf(" | 💵 Cost: $%.4f", m.lastUsage.Cost)
2338+
}
2339+
statusBar = "\n" + subtleStyle.Render(usageInfo) + "\n"
2340+
}
2341+
// 4. Input Box
2342+
inputView := m.textarea.View()
2343+
if m.focus == focusInput {
2344+
inputView = activeBorder.Width(m.width - 2).Render(inputView)
2345+
} else {
2346+
inputView = inactiveBorder.Width(m.width - 2).Render(inputView)
2347+
}
2348+
2349+
view := fmt.Sprintf(
2350+
"%s\n%s\n%s\n%s\n%s%s\n%s",
2351+
header,
2352+
lipgloss.NewStyle().Foreground(lipgloss.Color("#444444")).Render(border),
2353+
mainContent,
2354+
envBar,
2355+
lipgloss.NewStyle().Foreground(lipgloss.Color("#444444")).Render(border),
2356+
statusBar,
2357+
inputView,
2358+
)
23452359
if !m.isCapturing {
23462360
if suggs := m.renderSuggestions(); suggs != "" {
23472361
view += "\n" + suggs

0 commit comments

Comments
 (0)