Hacktoberfest 2026: the issues maintainers tagged for October, open and beginner-friendly. Browse Hacktoberfest issues

feat: add context-window meter and in-conversation search to TUI

Closed
#1,357 1 comment 0 reactions 0 assignees View on GitHub

Maintainers usually reply within 1 day

A pull request for this has already been merged.

  • #1363 by @avoidwork — merged

Assessment

Difficulty
4/5
Estimated time
3-5 days
Newbie friendliness
22/100
Issue type
Feature
Clarity
Mostly clear
Activity status
Active
Tech stack
javascript
Domain
cli

Research direction

Start with the context-window meter in src/tui/statusBar.js, where contextSize is currently rendered via formatSize in the showContext block, and reuse getContextUtilizationColor for the ratio. Search (Ctrl+F) spans src/tui/app.js, messageList.js and scrollView.js, and the issue itself recommends splitting it out, so confirm scope with the maintainer first. Done means the meter renders at 0%, 50%, 100% and falls back when contextWindow is unset, with tests passing via npm run test.

Written by the indexing model from the issue text.

Description

feature

Summary

Add a context-window meter to the TUI status bar (replacing the bare contextSize number with a visual bar) and add in-conversation search (Ctrl+F) with match highlighting and jump-to-next.

Motivation

The status bar currently shows a bare contextSize number, which is not intuitive — users cannot tell at a glance how much of the context window is consumed. Long conversations are also hard to navigate; in-conversation search lets users filter and jump to specific messages without scrolling through the whole transcript.

Proposed Solution

  1. Context-window meter — Replace the bare contextSize number in src/tui/statusBar.js with a visual bar, e.g. [▮▮▮▯▯▯] 62%, showing the proportion of the context window used.
  2. In-conversation search — Bind Ctrl+F to filter/search messages, with match highlighting and jump-to-next. Builds on the virtualized src/tui/scrollView.js and src/tui/messageList.js.

Dependencies

  • No new runtime dependencies expected — this builds on the existing TUI rendering stack. If a search/filter helper is required, prefer a lightweight in-house implementation over adding a dependency. Confirm exact packages during implementation.

Testing Strategy

  • Unit tests: Verify the meter renders correctly at 0%, 50%, and 100% context usage; verify search/filter logic matches expected messages and highlights matches.
  • Integration test: Simulate Ctrl+F in the TUI, type a query, and verify matches are highlighted and jump-to-next advances through results.
  • Edge cases: Empty conversation, no matches found, very long messages, context at 0% and 100%, search query with special characters.

Security Considerations

  • Credential storage: Not applicable — no credentials involved.
  • Input validation: Validate and sanitize the search query before filtering; guard against regex injection if the query is used in a regex.
  • OWASP: No new attack surface beyond normal TUI input handling.

Alternatives Considered

  • Meter: Keep the bare number, or show only a percentage. A visual bar was chosen for at-a-glance readability.
  • Search: A separate search panel vs. inline filter. Inline filter with jump-to-next was chosen for minimal disruption to the existing scroll view.

Split Recommendation

This issue bundles multiple distinct capabilities. Consider splitting into separate issues:

  • Context-window meter — small, self-contained change to src/tui/statusBar.js.
  • In-conversation search — larger, touches src/tui/scrollView.js and src/tui/messageList.js, and requires keyboard handling.

MVP recommendation: Start with the context-window meter as it has the least dependencies and highest immediate value.

OpenSpec Note

This project uses OpenSpec for feature development. If this request is approved, I will:

  1. Run /opsx:propose to generate a full proposal with specs and tasks
  2. Iterate on the design before any code is written
  3. Follow the task-driven implementation workflow

Additional Context

Split out from issue 1339.

Audit Findings (for Issue #1357)

  • src/tui/statusBar.js — The contextSize value is rendered via formatSize(contextSize) in the showContext block (around line 117). The contextWindow prop is already available, and getContextUtilizationColor(contextSize, contextWindow) already computes the utilization percentage. The meter can reuse this: compute contextSize / contextWindow and render a bar like [▮▮▮▯▯▯] 62%. Handle the contextWindow <= 0 (unset) case — currently getContextUtilizationColor falls back to cyan; the meter should fall back to the bare number or a neutral display.
  • src/tui/scrollView.js — VirtualScrollView exposes an imperative API via ref: scrollTo, scrollBy, scrollToTop, scrollToBottom, getScrollOffset, getContentHeight, getViewportHeight, getBottomOffset, remeasure, remeasureItem. It renders only the visible window via computeVisibleRange(heights, viewportHeight, scrollOffset, overscan). For jump-to-next, compute the matched message's cumulative offset from the offsets array and call scrollTo(offset).
  • src/tui/messageList.js — MessageList builds renderData (filtered by shouldRenderBubble) and textOffsets for selection mapping. It exposes getMessages() returning {text, top} per message — search can reuse this to locate matches and compute the scroll target. The renderItem already accepts a selection prop (global char range mapped to a local bubble range) and passes it to MessageBubble — search match highlighting can reuse this selection mechanism.
  • src/tui/app.js — The global useInput handler (line 367) routes keys in conversation view. Ctrl+F is not currently handled; add a key.ctrl && input === "f" branch to toggle search mode. Note the existing focus-aware routing (tab toggles inputFocused), so search mode must coordinate with input focus.
  • src/tui/inputArea.js — Passes contextSize and contextWindow to StatusBar (lines 191-195). No change needed here for the meter; the data source already exists.

Fix Steps

  1. Add the context-window meter — In src/tui/statusBar.js, replace the formatSize(contextSize) render in the showContext block with a visual bar. Compute utilization = contextWindow > 0 ? contextSize / contextWindow : 0, render [▮▮▮▯▯▯] 62% using block characters, and color it via the existing getContextUtilizationColor. Fall back to the bare number when contextWindow <= 0.
  2. Add a search state to MessageList — In src/tui/messageList.js, add a searchQuery state and a searchIndex (current match). Add a setSearchQuery/clearSearch imperative API. Reuse getMessages() to find matches and compute the scroll target offset.
  3. Highlight matches — In src/tui/messageList.js renderItem, when a search query is active, compute the local match ranges within each bubble's text and pass them to MessageBubble (reuse the existing selection prop mechanism or add a highlights prop).
  4. Wire Ctrl+F — In src/tui/app.js, add a key.ctrl && input === "f" branch in the global useInput handler to toggle search mode and focus the search input. Coordinate with the existing inputFocused routing so search mode takes precedence.
  5. Add jump-to-next — In src/tui/messageList.js, add a searchNext/searchPrev imperative method that advances searchIndex and calls scrollRef.current.scrollTo(offset) using the matched message's cumulative offset.
  6. Write tests — Add unit tests for the meter (0%, 50%, 100%, and unset contextWindow) and for search matching/highlighting/jump-to-next. Add an integration test simulating Ctrl+F. Run npm run test, npm run lint, and npm run coverage.
Dominant language
JavaScript
Stars
2
Forks
0
Avg merge
1h 15m
Merged PRs (30d)
237

Getting set up

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from avoidwork/madz

All issues in avoidwork/madz

Similar issues

More JavaScript issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.