Skip to content

feat/cache-timer - #9

Merged
leeguooooo merged 2 commits into
leeguooooo:mainfrom
Odoo-Ninjas:feat/cache-timer
May 4, 2026
Merged

leeguooooo merged 2 commits into
leeguooooo:mainfrom
Odoo-Ninjas:feat/cache-timer

Conversation

@marcwimmer

Copy link
Copy Markdown
Contributor

feat: Add cache-timer widget to show when 5-minute prompt cache expires

  • Add 'show_cache_age' config toggle (cs config set show_cache_age true)
  • New get_cache_age_text() function reads last assistant message timestamp from JSONL
  • Display formats: '2m14s ago' (cache warm), 'COLD' (>=5m, cache expired)
  • Integrated in all 3 styles: capsule (pill), hairline (text), classic (append)
  • Cache age shown in red when cold, muted/green when warm
  • Helps users keep Claude's prompt cache alive by monitoring time since last request

marcwimmer and others added 2 commits May 3, 2026 12:55
feat: Add cache-timer widget to show when 5-minute prompt cache expires

- Add 'show_cache_age' config toggle (cs config set show_cache_age true)
- New get_cache_age_text() function reads last assistant message timestamp from JSONL
- Display formats: '2m14s ago' (cache warm), 'COLD' (>=5m, cache expired)
- Integrated in all 3 styles: capsule (pill), hairline (text), classic (append)
- Cache age shown in red when cold, muted/green when warm
- Helps users keep Claude's prompt cache alive by monitoring time since last request
feat: add --watch mode for live cache-age updates

- New --watch flag re-renders status bar every 5 seconds
- Clears line before each render for clean display
- Useful for monitoring prompt cache expiration in real-time
- Ctrl+C to stop the watch loop
@leeguooooo
leeguooooo merged commit 0df1058 into leeguooooo:main May 4, 2026
leeguooooo added a commit that referenced this pull request May 4, 2026
- Remove unrelated --watch CLI mode (out of scope; statusline runs on demand)
- Rewrite get_cache_age_text() with reverse-tail JSONL reader (32KB chunks)
  instead of slurping entire transcript into memory; use `with open(...)` to
  fix file-handle leak; translate German comments to English
- Add tests covering show_cache_age config + _last_assistant_age across
  empty / no-assistant / Z-suffix / malformed-line / chunk-boundary cases
@leeguooooo

Copy link
Copy Markdown
Owner

Thanks a lot for this @marcwimmer — really useful idea, and it shipped to main 🎉

For the record, here's everything that landed:

Documented in the README config table now. The one gotcha worth highlighting for users: it needs "refreshInterval": N set in ~/.claude/settings.json statusLine block, otherwise Claude Code only re-renders on activity and the value freezes.

Will go out in the next PyPI release.

leeguooooo added a commit that referenced this pull request May 4, 2026
#20)

The cache_age widget previously showed "cache 30s" meaning "30 seconds
elapsed since last assistant turn". Inconsistent with our other
countdown segments (5h ⏰2h14m, 7d ⏰12h35m) and forced the user to
mentally subtract from the TTL.

Now: "cache 4m30s" means "4 minutes 30 seconds remaining before the
prompt cache expires". Falling number = increasing urgency, which is
the universal direction for time-pressure UX (rocket countdowns,
download ETAs, expiration timers).

Three-level color severity (was binary):
- > 1min remaining: green   (s_ok)        — comfortable
- < 1min remaining: yellow  (s_warn)      — wrap up your prompt
- 0 / COLD:         red     (s_hot)       — next API call pays full price

The "missing m in text" trick lets the styles layer detect sub-minute
remaining without duplicating the time-parsing logic.

Why countdown wins (and why we did elapsed initially): elapsed was the
shape of the original PR #9 from @marcwimmer, and we kept it through
Phase D without rethinking. But the widget exists to answer "should I
send my next prompt before the cache dies?" — a countdown answers
directly. Elapsed forces the user to remember the TTL and subtract.

Tests
-----
- Updated 3 existing assertions for new countdown semantics
- Added test_cache_text_emits_sub_minute_for_warning_state — pins the
  "no m in text" contract that the styles layer relies on for yellow
- 242 tests passing (was 241)

Verified live across all three styles (classic / capsule / hairline)
and all three states (warm green, <1min yellow, COLD red).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants