feat(tui-go): health-checks pane
Surface the health subsystem (llama/event-store/disk probes) in the TUI, mirroring the session-stats pane: ClientMessage.GetHealthChecks -> ServerMessage.HealthChecks (health.checks, reuses HealthReport) -> StreamQueries.healthChecks via HealthInspectionService; Go OverlayHealth on key H + palette 'health checks', pull-based fetch, per-subject status with degraded loud. Empty/disabled -> visible fallback (no blank/lie). Go+Kotlin golden tests pin the wire contract field-for-field. Observability spec §4/§3.
This commit is contained in:
@@ -61,6 +61,8 @@ func (m Model) renderOverlay(base string) string {
|
||||
return m.center(m.statsModal())
|
||||
case OverlayIdeas:
|
||||
return m.center(m.ideasModal())
|
||||
case OverlayHealth:
|
||||
return m.center(m.healthModal())
|
||||
}
|
||||
return base
|
||||
}
|
||||
@@ -750,6 +752,66 @@ func (m Model) statsModal() string {
|
||||
return t.Overlay.Width(w).Render(b.String())
|
||||
}
|
||||
|
||||
func (m Model) healthModal() string {
|
||||
t := m.theme
|
||||
w := m.modalWidth()
|
||||
|
||||
var b strings.Builder
|
||||
b.WriteString(m.titleLine("health checks"))
|
||||
b.WriteString("\n\n")
|
||||
|
||||
if m.healthLoading || m.health == nil {
|
||||
msg := "loading…"
|
||||
if !m.healthLoading && m.health == nil {
|
||||
msg = "no health report available"
|
||||
}
|
||||
b.WriteString(mbg(t, " "+msg, t.P.Faint) + "\n")
|
||||
b.WriteString("\n" + modalHints(t, [][2]string{{"H/esc", "close"}}))
|
||||
return t.Overlay.Width(w).Render(b.String())
|
||||
}
|
||||
|
||||
h := m.health
|
||||
cw := w - 4
|
||||
|
||||
// overall status header
|
||||
overallFg := t.P.OK
|
||||
if h.Overall == "DEGRADED" {
|
||||
overallFg = t.P.Bad
|
||||
}
|
||||
overall := lipgloss.NewStyle().Foreground(overallFg).Background(t.P.BgPanel).Bold(true).Render(h.Overall)
|
||||
b.WriteString(clip(mbg(t, " overall ", t.P.Faint)+overall+mbg(t, " checked "+h.CheckedAt, t.P.Faint), cw) + "\n\n")
|
||||
|
||||
if len(h.Subjects) == 0 {
|
||||
b.WriteString(mbg(t, " no health probes recorded — health monitoring may be disabled", t.P.Faint) + "\n")
|
||||
b.WriteString("\n" + modalHints(t, [][2]string{{"H/esc", "close"}}))
|
||||
return t.Overlay.Width(w).Render(b.String())
|
||||
}
|
||||
|
||||
section := func(label string) string {
|
||||
return lipgloss.NewStyle().Foreground(t.P.Accent2).Background(t.P.BgPanel).Bold(true).Render(label)
|
||||
}
|
||||
put := func(styled string) { b.WriteString(clip(styled, cw) + "\n") }
|
||||
faint := func(s string) string { return mbg(t, s, t.P.Faint) }
|
||||
|
||||
for _, sub := range h.Subjects {
|
||||
statusFg := t.P.OK
|
||||
if sub.Status == "DEGRADED" {
|
||||
statusFg = t.P.Bad
|
||||
}
|
||||
statusLabel := lipgloss.NewStyle().Foreground(statusFg).Background(t.P.BgPanel).Bold(sub.Status == "DEGRADED").Render(sub.Status)
|
||||
b.WriteString(section(sub.Subject) + mbg(t, " ", t.P.BgPanel) + statusLabel + "\n")
|
||||
put(faint(fmt.Sprintf(" metric %-18s value %d", sub.Metric, sub.ObservedValue)))
|
||||
if sub.Detail != "" {
|
||||
put(faint(" " + truncate(sub.Detail, cw-4)))
|
||||
}
|
||||
put(faint(" since " + sub.Since))
|
||||
b.WriteString("\n")
|
||||
}
|
||||
|
||||
b.WriteString(modalHints(t, [][2]string{{"H/esc", "close"}}))
|
||||
return t.Overlay.Width(w).Render(b.String())
|
||||
}
|
||||
|
||||
// shortID trims a long artifact id for the list column while staying identifiable.
|
||||
func shortID(id string) string {
|
||||
if len(id) <= 14 {
|
||||
|
||||
Reference in New Issue
Block a user