Skip to content

Comments

Update status tui#448

Open
evisdren wants to merge 7 commits intomainfrom
update_status_tui
Open

Update status tui#448
evisdren wants to merge 7 commits intomainfrom
update_status_tui

Conversation

@evisdren
Copy link
Contributor

@evisdren evisdren commented Feb 20, 2026

Updates entire status output to be better formatted and easier to read.

Top is the current prod, bottom is the new implementation
image

evisdren and others added 4 commits February 20, 2026 10:55
Add lipgloss-based styling to the status command with colored dots,
separator-delimited fields, session cards showing phase/files/tokens,
and aggregate footer stats. Falls back to plain text for non-terminals.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Entire-Checkpoint: 7c52cb84aa82
Drop session phase (active/idle/ended) and per-session file counts
from status output. Token calculation validated correct (sums
Input+CacheCreation+CacheRead+Output recursively, excludes
APICallCount). Add comprehensive TTY/color detection tests:
NO_COLOR env, regular file, non-TTY buffer, render toggle,
plain-text section rules.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add > chevron before first prompt in session cards
- Remove repo name from Active Sessions section header
- Remove total tokens from aggregate footer (keep session count)
- Add blank line above the status line for visual separation

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@evisdren evisdren requested a review from a team as a code owner February 20, 2026 20:08
Copilot AI review requested due to automatic review settings February 20, 2026 20:08
@cursor
Copy link

cursor bot commented Feb 20, 2026

PR Summary

Low Risk
Primarily CLI output formatting changes plus a new dependency (lipgloss); low functional risk but may affect snapshot/regex-based tooling that parses entire status output.

Overview
Updates entire status to a more TUI-like, colorized format (TTY-only, NO_COLOR respected) using a new statusStyles helper and lipgloss, including separators, section rules, and bold/dim styling.

Enhances the short/detailed settings line to include strategy display with · separators and the current repo branch, and rewrites active session rendering to a multi-line per-session layout that adds token usage (tokens 1.2k) and an aggregate footer while removing the previous bracketed/phase-style output. Tests are updated/expanded to match the new output and cover token aggregation and styling helpers.

Written by Cursor Bugbot for commit f48ef4b. Configure here.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR enhances the entire status command with an improved terminal UI using the charmbracelet/lipgloss library for styled output. The changes introduce color-coded status indicators, better visual separation with section rules, and token usage display for active sessions.

Changes:

  • Adds lipgloss as a direct dependency for terminal styling
  • Introduces status_style.go with reusable styling utilities (colors, formatting helpers)
  • Updates status.go to use the new styling system with visual indicators (● for enabled, ○ for disabled)
  • Adds token count display in active session summaries
  • Comprehensive test coverage for new styling functions with accessibility considerations

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 5 comments.

File Description
go.mod Moves lipgloss from indirect to direct dependency (correctly reflects new import)
cmd/entire/cli/status_style.go New file containing styling utilities: color detection, terminal width, token formatting, and section rules
cmd/entire/cli/status.go Updates status output formatting to use new styling system, adds token display, changes session header structure
cmd/entire/cli/status_test.go Updates tests for new output format, adds comprehensive unit tests for styling functions

func (s statusStyles) sectionRule(label string, width int) string {
prefix := "── "
content := label + " "
usedWidth := len(prefix) + len(content)
Copy link

Copilot AI Feb 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The width calculation uses len() which counts bytes, not runes. The box-drawing character '─' is a multi-byte UTF-8 character. This could lead to incorrect width calculations and visual misalignment. Use len([]rune(prefix)) and len([]rune(content)) to count actual displayed characters instead.

Suggested change
usedWidth := len(prefix) + len(content)
usedWidth := len([]rune(prefix)) + len([]rune(content))

Copilot uses AI. Check for mistakes.
Comment on lines 320 to 323
stats = append(stats, "tokens "+sty.render(sty.bold, formatTokenCount(totalTokens(st.TokenUsage))))

statsLine := strings.Join(stats, sty.render(sty.dim, " · "))
fmt.Fprintln(w, sty.render(sty.dim, statsLine))
Copy link

Copilot AI Feb 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The token count is rendered with bold styling and embedded in the stats array, then the entire statsLine (including the already-styled token count) is joined with styled separators and wrapped in dim styling. This creates nested styling which could lead to rendering issues. The bold token count will be wrapped in dim styling, potentially losing the bold emphasis. Consider not styling individual stats elements and only applying dim to the separator, or apply dim to each element separately before joining with plain separators.

Copilot uses AI. Check for mistakes.
Comment on lines 283 to 285
for _, g := range sortedGroups {
fmt.Fprintln(w, sty.sectionRule("Active Sessions", sty.width))
fmt.Fprintln(w)
Copy link

Copilot AI Feb 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The section header "Active Sessions" is now printed once per worktree group (inside the loop), whereas the previous implementation printed it once at the top. This means if there are multiple worktrees with active sessions, the heading will be repeated multiple times. Consider moving the header outside the loop (before line 283) if you want it to appear only once, or clarify in comments if the per-group header is intentional.

Suggested change
for _, g := range sortedGroups {
fmt.Fprintln(w, sty.sectionRule("Active Sessions", sty.width))
fmt.Fprintln(w)
printedHeader := false
for _, g := range sortedGroups {
if !printedHeader {
fmt.Fprintln(w, sty.sectionRule("Active Sessions", sty.width))
fmt.Fprintln(w)
printedHeader = true
}

Copilot uses AI. Check for mistakes.

// Footer: horizontal rule + session count
fmt.Fprintln(w, sty.horizontalRule(sty.width))
footer := fmt.Sprintf("%d sessions", totalSessions)
Copy link

Copilot AI Feb 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The footer always uses the plural form "sessions" even when totalSessions is 1. Consider using proper pluralization: if totalSessions == 1, use "1 session" (singular), otherwise use "%d sessions" (plural).

Suggested change
footer := fmt.Sprintf("%d sessions", totalSessions)
var footer string
if totalSessions == 1 {
footer = "1 session"
} else {
footer = fmt.Sprintf("%d sessions", totalSessions)
}

Copilot uses AI. Check for mistakes.
Comment on lines 76 to 80
if w, _, err := term.GetSize(int(os.Stdout.Fd())); err == nil && w > 0 {
if w > 80 {
return 80
}
return w
Copy link

Copilot AI Feb 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The function always reads terminal width from os.Stdout, but the actual output may be written to a different io.Writer (passed to newStatusStyles). This is inconsistent and could cause incorrect width calculations when output is redirected or in tests. Consider accepting the writer as a parameter and checking its file descriptor if it's an *os.File, similar to shouldUseColor.

Suggested change
if w, _, err := term.GetSize(int(os.Stdout.Fd())); err == nil && w > 0 {
if w > 80 {
return 80
}
return w
// Prefer Stdout for width, but fall back to Stderr if Stdout is not a terminal
files := []*os.File{os.Stdout, os.Stderr}
for _, f := range files {
if f == nil {
continue
}
if w, _, err := term.GetSize(int(f.Fd())); err == nil && w > 0 {
if w > 80 {
return 80
}
return w
}

Copilot uses AI. Check for mistakes.
Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 4 potential issues.

Bugbot Autofix is OFF. To automatically fix reported issues with Cloud Agents, enable Autofix in the Cursor dashboard.

Comment @cursor review or bugbot run to trigger another review on this PR

fmt.Fprintf(w, " %s\n", header)
for _, g := range sortedGroups {
fmt.Fprintln(w, sty.sectionRule("Active Sessions", sty.width))
fmt.Fprintln(w)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Section header repeats inside worktree group loop

Medium Severity

The sectionRule("Active Sessions", ...) call is inside the for _, g := range sortedGroups loop, so it prints the "Active Sessions" header once per worktree group instead of once before the loop. The old code printed the header once before the loop. With multiple worktrees, users see repeated identical section headers with no indication of which worktree each group belongs to (the old per-group path/branch header was also removed).

Fix in Cursor Fix in Web

prefix := "── "
content := label + " "
usedWidth := len(prefix) + len(content)
trailing := width - usedWidth
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Byte length used instead of display width for Unicode

Low Severity

sectionRule computes usedWidth via len(prefix) which returns the byte count, not the display column width. The prefix "── " contains two characters (U+2500, 3 bytes each in UTF-8), so len() returns 7 instead of the correct display width of 3. This makes the trailing rule 4 columns shorter than the terminal width.

Fix in Cursor Fix in Web

// Styles
green lipgloss.Style
red lipgloss.Style
gray lipgloss.Style
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unused gray field defined but never referenced

Low Severity

The gray field in statusStyles is defined and initialized but never read anywhere. Since statusStyles is a new unexported type introduced in this PR, all usage is visible in the diff — sty.green, sty.red, sty.bold, sty.dim, sty.agent, and sty.cyan are all referenced, but sty.gray is not. This is dead code.

Additional Locations (1)

Fix in Cursor Fix in Web


// Footer: horizontal rule + session count
fmt.Fprintln(w, sty.horizontalRule(sty.width))
footer := fmt.Sprintf("%d sessions", totalSessions)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Footer displays "1 sessions" missing singular form

Low Severity

The footer uses fmt.Sprintf("%d sessions", totalSessions) which always prints the plural "sessions". When there is exactly one active session, this produces the grammatically incorrect string "1 sessions" instead of "1 session". Having a single active session is arguably the most common case.

Fix in Cursor Fix in Web

evisdren and others added 3 commits February 20, 2026 12:24
getTerminalWidth now checks the output writer's fd first, then
falls back to Stdout/Stderr. This ensures correct width when
output is redirected to a different file descriptor.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Covers getTerminalWidth, newStatusStyles width, sectionRule narrow edge case,
activeTimeDisplay hours/days, and unit tests for formatSettingsStatusShort
and formatSettingsStatus.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

1 participant