feat: paginate the eval --rich dashboard with left/right arrow keys#1912
Conversation
When rollout rows overflow the eval `--rich` dashboard, the left/right arrows now page through them. Auto-advance is preserved: it drives paging until the first arrow press, then hands off seamlessly (continuing from the page on screen) and stays where the user leaves it. Key reading lives in the shared `live_view` engine behind an optional `on_key` handler — stdin goes to cbreak and is read via the event loop (no extra thread), redrawing immediately on each press so there's no lag. A no-op when stdin isn't a terminal, so non-interactive runs are unaffected. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 3 potential issues.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Want reviews to match your repository better? Bugbot Learning can learn team-specific rules from PR activity. A team admin can enable Learning in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 8a43f69. Configure here.
ApprovabilityVerdict: Approved Self-contained CLI UX enhancement adding arrow key pagination to the eval dashboard. Changes are isolated to display logic, don't affect eval processing, and the author is the original maintainer of this dashboard code. You can customize Macroscope's approvability policy. Learn more. |
- _key_reader now buffers a partial escape across reads: cbreak can split a key's 3 bytes over separate os.read callbacks (common over SSH), which the per-chunk scan dropped. Unconsumed tail bytes carry to the next read. - setcbreak moved inside the try/finally so the terminal is always restored, even if setcbreak or add_reader raises after it (previously it could leave stdin in cbreak with echo off). - Pager arrows are now inert until there's more than one page: it tracks the page count (set each render by _paginate) and ignores presses while a single page fits, so a stray arrow before rollouts overflow can't disable auto-advance or offset the starting page once paging begins. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

Summary
--richdashboard, the left/right arrow keys now page through them.Pagertracks the page count (set each render by_paginate) and ignores presses while a single page fits, so a stray arrow before rollouts overflow can't disable auto-advance or offset the starting page once paging begins.live_viewengine (dashboard/base.py) behind an optionalon_keyhandler: stdin is put in cbreak mode and read via the asyncio event loop (no extra thread), buffering a partial escape across reads (cbreak can split a key's 3 bytes over callbacks). Each press redraws immediately (rather than waiting for the next 0.25s refresh tick) so there's no lag. Because updates go through the samelive.update(..., refresh=True)path as the timer, there's no extra flicker.setcbreakruns inside thetry, so the terminal is always restored on exit even if setup raises.validate_dashboard, which shareslive_view, is untouched (it passes noon_key).◄ ►hint ((page 2/6 ◄ ►)) so the controls are discoverable.Verification
Drove the real
dashboard/live_viewpipeline inside a pseudo-terminal (real cbreak, real asyncioadd_reader, real arrow-sequence parsing,Pager+_paginate, richLive) with real arrow-key bytes:manual=False), page rotates on the timer→read within 0.12s (< the 0.25s tick): page already advanced — confirms the immediate redraw (no lag)→ →,←: step correctly through pages, continuing from the on-screen auto page←×9 and→×20: clamp at page 1 and the last page (no wrap, no out-of-range)ESCand[Csent in separate writes with a 0.35s gap (past a refresh tick) — still pagesmanual=Falseand the page at 1/1add_readerto raise aftersetcbreakin a real pty — ICANON and ECHO are restored afterward/dev/null(non-tty): key reader no-ops, auto-advance still runs, clean exit — no crashruff check,ruff format, andty check verifiersall pass.🤖 Generated with Claude Code
Note
Add left/right arrow key pagination to the
evalrich dashboardPagerclass in eval.py that tracks pagination state: auto-advances pages every_PAGE_SECONDSuntil the user presses an arrow key, after which it follows manual input and clamps within bounds._key_readercontext manager in base.py that, on POSIX TTY stdin, usescbreakmode and an asyncio reader to detect left/right arrow escape sequences and dispatch them to anon_keycallback with an immediate redraw.(page X/Y ◄ ►)when pagination is active.on_keyis not provided,termiosis unavailable, or stdin is not a TTY, so non-interactive environments are unaffected.Macroscope summarized 54acea6.