Skip to content

30 visible bugs in the status line renderer, widgets and TUI #63

Closed

Description

@axisrow

Thirty bugs you can see on screen, found in one bug hunt on main (a2c1161). Each one was reproduced in the real program before any code changed:

  • Piped status lines were rendered through xterm.js with JetBrainsMono Nerd Font.
  • The TUI was driven in tmux at 120×40.

Fixes with regression tests are in #61. The Powerline font-detection bug found in the same hunt is tracked separately in #62.

Code links point to the pre-fix lines on a2c1161.

Status line rendering

A. "⚠ Some lines are truncated" when nothing is cut

  • Trigger: Terminal Width "Full width minus 40", plus any ... in widget text. Examples: CWD segments (.../Projects/my-project), a Custom Command preview longer than 20 chars, a Link, a widget cut by its own max width.
  • You see: the main menu warns about truncation. In the screenshot the line is 44 columns wide with 80 available.
  • Expected: the warning appears only when a line was actually cut.
  • Code: truncation is detected by searching the line for ..., in renderer.ts#L1053-L1054. The warning is in MainMenu.tsx#L247-L256.

A — before

B. Regular mode: a preserve-colors Custom Command loses its background after its own reset

  • Trigger: Powerline off, Custom Command with preserve colors on and a background (its own or the global override). The command is printf "\033[31mred\033[0m tail".
  • You see: the blue stops right after red. tail sits on the terminal background, then the blue padding resumes.
  • Expected: the background continues to the end of the widget. Powerline mode already does this since 1a6e588.
  • Code: renderer.ts#L1236-L1255.

B — before

R9. Styles a preserve-colors command leaves open bleed into the rest of the line

  • Trigger: Powerline off, Custom Command with preserve colors on: printf "\033[1;4mX" (bold and underline, no reset).
  • You see: the separators, Model and Cost after it are bold and underlined too.
  • Expected: only X is styled. Powerline mode closes the widget with \x1b[0m.
  • Code: renderer.ts#L1236-L1255.

R9 — before

R1. A stray | before a flex gap when the widget after it is empty

  • Trigger: Powerline off, line Model, Separator, Git Branch (hide when not in git), Flex Separator, Session Cost, run outside a git repo.
  • You see: Opus 4.6 | $0.42. The branch is hidden, but its separator dangles in front of the gap.
  • Expected: the separator collapses with the hidden widget, as it already does at the end of a line.
  • Code: separator collapse in renderer.ts#L1142-L1171. The end-of-line case that already works is renderer.ts#L1277-L1280.

R1 — before

R6. A widget that prints only color codes still counts as visible

  • Trigger: Custom Command printf "\033[33m%s\033[0m" "$EMPTY_VAR", which prints no visible text.
  • You see: A | | B in regular mode, and an empty grey block between two arrows in Powerline mode.
  • Expected: A | B. The widget hides like any other empty widget.
  • Code: the content is kept even when its visible width is 0, in renderer.ts#L941-L952.

R6 — before

R4. Regular-mode theme: a merge blocked by a separator still makes two widgets share one color

  • Trigger: Powerline off, theme Dracula. Alpha has merge on, but a separator follows it.
  • You see: Alpha and Beta are separate (a | sits between them), yet both get palette slot 1. Every later widget shifts by one.
  • Expected: a widget shares a color only when it really merges into the next one, as in Powerline mode.
  • Code: renderer.ts#L1265-L1266.

R4 — before

R7. Terminal width unknown: a flex separator at a line edge prints |

  • Trigger: the width cannot be detected (always on Windows), and a flex separator is the first or last item on a line.
  • You see: the line starts or ends with a stray |.
  • Expected: nothing at the edge. Powerline mode falls back to a plain space.
  • Code: renderer.ts#L1421-L1423.

R7 — before

R8. "Inherit separator colors" ignores the regular-mode theme

  • Trigger: Powerline off, theme Dracula, Inherit separator colors on.
  • You see: the separator after the purple Alpha is default white.
  • Expected: a separator takes the color the widget before it actually shows.
  • Code: renderer.ts#L1188-L1202 and renderer.ts#L1316-L1327.

R8 — before

R5. dim: parens breaks a branch link whose name contains (…)

  • Trigger: Git Branch with the repo link on, dim set to parens, branch fix(ui).
  • You see: (ui)⎇ fix(ui). The link is gone, and the line is 4 columns wider than the renderer measured, so the right-aligned Cost overflows.
  • Why: the dim code is inserted inside the OSC 8 URL (…/tree/fix(ui)). The sanitizer then drops the broken link opener and prints the URL's (ui) as text.
  • Expected: a working link ⎇ fix(ui) with (ui) dimmed.
  • Code: applyParensDim in colors.ts#L131-L136.

R5 — before

Widgets

W15. Context Bar shows 100% and a full bar before the window is full

  • Trigger: 199,200 of 200,000 tokens used.
  • You see: 199k/200k (100%) right next to Context % showing 99.6%.
  • Expected: (99%) while any tokens are still free.
  • Code: ContextBar.ts#L127-L129.

W15 — before

W12. Floating-point noise in token counts: 699.9999999999999

  • Trigger: a payload with context_window: {context_window_size: 200000, used_percentage: 0.35} and no current_usage.
  • You see: Context Length and Context Bar print 699.9999999999999.
  • Expected: 700.
  • Code: the token count derived from the percentage is never rounded, in context-window.ts#L102-L104.

W12 — before

W5. No billion tier for token counts: 1246.4M

  • Trigger: a long agentic session whose cumulative counts pass 1e9 (8,000 tool calls with about 155k cache-read tokens each).
  • You see: Cached: 1246.4M. This is the same class of bug as the already-fixed 1000.0k.
  • Expected: 1.2B.
  • Code: format-tokens.ts#L14-L19.

W5 — before

W13. Reset timers stay on [Loading] when usage has loaded but the window has not started

  • Trigger: rate_limits with used_percentage: 0 for five_hour and seven_day, and no resets_at yet.
  • You see: Weekly Reset: [Loading] indefinitely, while the usage widgets next to it already show 0.0%.
  • Expected: a fresh window has no reset time until first use, so say so, for example [Not started].
  • Code: USAGE_TIMER_LOADING_MESSAGE in WeeklyResetTimer.ts. BlockResetTimer.ts has the same branch.

W13 — before

W2. Edit Line: the long Context Bar has no modifier

  • Trigger: Edit Line with one Context Bar in "progress" mode (32 cells) and one in the default mode (16 cells).
  • You see: the default bar is labeled (medium bar), but the long one has no label.
  • Expected: (long bar), as every other bar widget labels this mode (src/widgets/shared/usage-display.ts).
  • Code: ContextBar.ts#L51-L57.

W2 — before

W8. Compaction Counter: the format named "icon-space-number" renders without the space

  • Trigger: Edit Line with a Compaction Counter.
  • You see: the editor says (icon-space-number), while the preview prints ↻2. The space was removed in e48c036, but the name was kept.
  • Expected: a label that matches the output.
  • Code: CompactionCounter.ts#L41.

W8 — before

TUI

D. Terminal Width menu marks the wrong option as "(default)" and states the wrong reserve

  • Trigger: fresh config → Terminal Options → Terminal Width.
  • You see: "Full width always (active)" sits right above "Full width minus 40 (default)". The description also says "minus 4 characters".
  • Expected: the default is Full width always (src/types/Settings.ts, README, docs/USAGE.md), and the renderer reserves 6 characters.
  • Code: TerminalWidthMenu.tsx#L46-L53.

D — before

E. Edit Line: the width-detection note is squeezed into two side-by-side columns

  • Trigger: a line with a Flex Separator while the terminal width cannot be detected (always on Windows).
  • You see: the two sentences of the note are laid out as a row, and each half wraps inside its own narrow column.
  • Expected: two lines, one under the other.
  • Code: the Box lacks flexDirection='column', in ItemsEditor.tsx#L499-L502.

E — before

F1. Delete-line dialog: ☰ Line2

  • Trigger: Edit Lines → Line 2 → (d)elete.
  • You see: ☰ Line2 (1 widget), while the list just before shows ☰ Line 2 (1 widget).
  • Code: LineSelector.tsx#L192-L197.

F — before

F2. Edit Colors: (s)how separators:OFF

  • Trigger: Powerline off → Edit Colors → any line.
  • You see: no space before ON/OFF.
  • Code: ColorMenu.tsx#L605-L608.

Screenshot: the bottom panel of the F1 image above.

T3. After Powerline Setup, the main-menu highlight lands on the wrong item

  • Trigger: Main menu → ⚡ Powerline Setup → (t) to turn Powerline on → Yes → ESC.
  • You see: ▶ is on 💻 Terminal Options. Turning Powerline off the same way lands on 🧶 Line Themes.
  • Why: the stored index was taken while 🌈 Theme was listed. Powerline hides that entry, so every index after it is off by one. The install and uninstall return targets have the same problem.
  • Code: App.tsx#L1614-L1616 and getMainMenuInstallSelectionIndex in MainMenu.tsx#L224.

T3 — before

T4. Presets keeps the first-run welcome and hides the "replaces your configuration" warning

  • Trigger: start with no settings.json → pick Starter → Main Menu → 🧩 Presets.
  • You see: the first-run welcome again, and no warning.
  • Expected: the title "Presets" plus the yellow "Applying a preset replaces your entire configuration.". Without it, a second preset silently wipes the configuration that was just set up.
  • Code: the first-run flag is fixed for the whole session, in App.tsx#L526 and App.tsx#L1666.

T4 — before

T8. Edit Colors offers the Flex Separator, whose color is never rendered

  • Trigger: Edit Colors → Line 1 → select Flex Separator → press → three times.
  • You see: "Current foreground: Bright Green", but nothing in the preview changes, because flex separators are plain spaces.
  • Expected: Flex Separator is not in the list.
  • Code: ColorMenu.tsx#L58-L67.

T8 — before

T10. After deleting the last line, Edit Lines opens with "← Back" highlighted

  • Trigger: Edit Lines → open Line 3 → ESC → (d)elete → Yes → ESC → Edit Lines again.
  • You see: ▶ on "← Back", so Enter leaves the screen instead of opening a line.
  • Why: the remembered selection (index 2) is not clamped after the delete.
  • Code: App.tsx#L1318-L1338.

T10 — before

T11a. Theme names shown as mangled keys: "Onedark", "Tokyonight", "Nord-aurora"

  • Trigger: pick One Dark (or Tokyo Night, Nord Aurora) in Powerline Setup → Themes.
  • You see: "(Onedark)" in Powerline Setup and "Colors are currently managed by the Powerline theme: Onedark" in Edit Colors.
  • Expected: "One Dark", as the theme picker calls it.
  • Code: PowerlineSetup.tsx#L96-L104 and LineSelector.tsx#L156-L160.

T11 — before

T11b. The Edit Colors hint points to a screen that does not exist

  • You see: "Change to 'Custom' theme in Powerline Configuration → Themes".
  • Expected: the screen is called "⚡ Powerline Setup".
  • Code: LineSelector.tsx#L168-L173.

Screenshot: the bottom panel of the T11a image above.

T13. Color Level change: Yes / No with no question

  • Trigger: a widget with a hex color → Terminal Options → Color Level.
  • You see: the warning is followed by Yes and No, with no question.
  • Why: TerminalOptionsMenu passes message="Continue?", but the inline ConfirmDialog never renders it.
  • Code: TerminalOptionsMenu.tsx#L140-L147.

T13 — before

T15. Add widget → "All": the list is not scrolled, and the selection and header leave the screen

  • Trigger: terminal 120×40 → Edit Line → (a)dd → Enter on "All".
  • You see: all 93 entries are rendered at once. The visible part starts at entry 57. The ▶ (on entry 1), the title and the search field are above the top of the terminal. The description at the bottom belongs to an entry you cannot see.
  • Expected: a window around the selection, as the other searchable pickers do.
  • Code: ItemsEditor.tsx#L574-L598.

T15 — before

T16. Global Overrides: "Compact Labels:" is one column off

T16 — before

T9. Install menu: after cancelling, the package step opens on "← Back"

  • Trigger: npm not installed → Install → Pinned → ▶ on "bun add -g …" → Enter → No → Pinned again.
  • You see: ▶ is on "← Back".
  • Why: the remembered choice is stored as a fixed index (bun = 1), but the list counts only the enabled entries, so index 1 is "← Back".
  • Code: InstallMenu.tsx#L220.

T9 — before

T1. The pinned-mismatch screen labels a file path as the "Current pinned version"

  • Trigger: Claude Code's statusLine runs a pinned global ccstatusline (v2.2.0) and you open a newer TUI.
  • You see: "Current pinned version:" followed by the path of the pinned binary (the relaunch command). The version is already in the sentence above.
  • Expected: a label that matches what follows, for example "Relaunch the pinned version with:".
  • Code: App.tsx#L278-L282.

T1 — before


Generated by Claude Code

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions