feat: add context-window meter and in-conversation search to TUI
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
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
- Context-window meter — Replace the bare
contextSizenumber insrc/tui/statusBar.jswith a visual bar, e.g.[▮▮▮▯▯▯] 62%, showing the proportion of the context window used. - In-conversation search — Bind Ctrl+F to filter/search messages, with match highlighting and jump-to-next. Builds on the virtualized
src/tui/scrollView.jsandsrc/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.jsandsrc/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:
- Run
/opsx:proposeto generate a full proposal with specs and tasks - Iterate on the design before any code is written
- Follow the task-driven implementation workflow
Additional Context
Split out from issue 1339.
Audit Findings (for Issue #1357)
src/tui/statusBar.js— ThecontextSizevalue is rendered viaformatSize(contextSize)in theshowContextblock (around line 117). ThecontextWindowprop is already available, andgetContextUtilizationColor(contextSize, contextWindow)already computes the utilization percentage. The meter can reuse this: computecontextSize / contextWindowand render a bar like[▮▮▮▯▯▯] 62%. Handle thecontextWindow <= 0(unset) case — currentlygetContextUtilizationColorfalls back to cyan; the meter should fall back to the bare number or a neutral display.src/tui/scrollView.js—VirtualScrollViewexposes an imperative API via ref:scrollTo,scrollBy,scrollToTop,scrollToBottom,getScrollOffset,getContentHeight,getViewportHeight,getBottomOffset,remeasure,remeasureItem. It renders only the visible window viacomputeVisibleRange(heights, viewportHeight, scrollOffset, overscan). For jump-to-next, compute the matched message's cumulative offset from theoffsetsarray and callscrollTo(offset).src/tui/messageList.js—MessageListbuildsrenderData(filtered byshouldRenderBubble) andtextOffsetsfor selection mapping. It exposesgetMessages()returning{text, top}per message — search can reuse this to locate matches and compute the scroll target. TherenderItemalready accepts aselectionprop (global char range mapped to a local bubble range) and passes it toMessageBubble— search match highlighting can reuse this selection mechanism.src/tui/app.js— The globaluseInputhandler (line 367) routes keys in conversation view. Ctrl+F is not currently handled; add akey.ctrl && input === "f"branch to toggle search mode. Note the existing focus-aware routing (tab togglesinputFocused), so search mode must coordinate with input focus.src/tui/inputArea.js— PassescontextSizeandcontextWindowtoStatusBar(lines 191-195). No change needed here for the meter; the data source already exists.
Fix Steps
- Add the context-window meter — In
src/tui/statusBar.js, replace theformatSize(contextSize)render in theshowContextblock with a visual bar. Computeutilization = contextWindow > 0 ? contextSize / contextWindow : 0, render[▮▮▮▯▯▯] 62%using block characters, and color it via the existinggetContextUtilizationColor. Fall back to the bare number whencontextWindow <= 0. - Add a search state to MessageList — In
src/tui/messageList.js, add asearchQuerystate and asearchIndex(current match). Add asetSearchQuery/clearSearchimperative API. ReusegetMessages()to find matches and compute the scroll target offset. - Highlight matches — In
src/tui/messageList.jsrenderItem, when a search query is active, compute the local match ranges within each bubble's text and pass them toMessageBubble(reuse the existingselectionprop mechanism or add ahighlightsprop). - Wire Ctrl+F — In
src/tui/app.js, add akey.ctrl && input === "f"branch in the globaluseInputhandler to toggle search mode and focus the search input. Coordinate with the existinginputFocusedrouting so search mode takes precedence. - Add jump-to-next — In
src/tui/messageList.js, add asearchNext/searchPrevimperative method that advancessearchIndexand callsscrollRef.current.scrollTo(offset)using the matched message's cumulative offset. - 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, andnpm run coverage.
- Dominant language
- JavaScript
- Stars
- 2
- Forks
- 0
- Avg merge
- 1h 15m
- Merged PRs (30d)
- 237
Getting set up
- Ships a Dockerfile or Docker Compose file
- Has a pull request template
- Read the contributing guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from avoidwork/madz
-
feat: add dedicated subagent view to TUIPossibly taken @avoidwork claimed this 1 day ago. Openapproved feature in progress
Difficulty 4/5 3-5 days Newbie friendliness 22/100
avoidwork/madz#1360 · 1 comment ·
Maintainers usually reply within 1 day
-
feature
Difficulty 4/5 3-5 days Newbie friendliness 22/100
avoidwork/madz#1358 · 1 comment ·
Maintainers usually reply within 1 day
-
feature
Difficulty 5/5 Over a week Newbie friendliness 15/100
avoidwork/madz#1355 · 1 comment ·
Maintainers usually reply within 1 day
-
feature
Difficulty 5/5 Over a week Newbie friendliness 35/100
Maintainers usually reply within 1 day
Similar issues
-
Difficulty 2/5 1-3 hours Newbie friendliness 76/100
-
enhancement
Difficulty 1/5 1-3 hours Newbie friendliness 85/100
holepunchto/hrpc-test#28 ·
-
good first issue
Difficulty 1/5 1-3 hours Newbie friendliness 88/100
anoopcodehack/DevBoard#616 ·
Maintainers usually reply within 2 days
-
idnits3
Difficulty 2/5 1-3 hours Newbie friendliness 63/100
ietf-tools/idnits#319 ·
-
Difficulty 1/5 Under an hour Newbie friendliness 76/100
521xueweihan/HelloGitHub#3939 ·