A weather-style gauge of the context window, drawn above the prompt.

hooks/register.tsx 71 lines1import { atom, read, update } from 'claude-code'
2import type { Engine, Register } from 'claude-code'
3
4import type { Fill } from '../types'
5
6const percent = atom({ plugin: 'context-weather', key: 'percent' } as const, null)
7
8const CELLS = 20
9
10// Reads the live window's fill into the atom; the write redraws the band.
11// Never throws: a failed read must not hold up the prompt it gates.
12const refresh = async ($: Engine) => {
13 try {
14 const { context } = await $.session.usage()
15 const fill: Fill = context.percent ?? null
16 await update($, percent, () => fill)
17 } catch {
18 // keep the last reading
19 }
20}
21
22const weather = (pct: number) => {
23 if (pct < 50) return { word: 'clear', color: 'success' as const }
24 if (pct < 75) return { word: 'cloudy', color: 'success' as const }
25 if (pct < 90) return { word: 'rain', color: 'warning' as const }
26 return { word: 'storm', color: 'error' as const }
27}
28
29export const register: Register = on => {
30 on('session.start', async ($, e, next) => {
31 await refresh($)
32
33 return next(e)
34 })
35
36 on('prompt.submit', async ($, e, next) => {
37 await refresh($)
38
39 return next(e)
40 })
41
42 on('turn.complete', async ($, e, next) => {
43 await refresh($)
44
45 return next(e)
46 })
47
48 on('ui.render', { component: 'AbovePrompt' }, async ($, e, next) => {
49 const pct = await read($, percent)
50
51 if (e.props.hasSurvey || pct === null) {
52 return next(e)
53 }
54
55 const { Box, Text } = $.ui.resolve(e)
56 const { word, color } = weather(pct)
57 const filled = Math.min(CELLS, Math.round((pct / 100) * CELLS))
58 const bar = '█'.repeat(filled) + '░'.repeat(CELLS - filled)
59
60 return (
61 <Box>
62 <Text color={color}>{bar}</Text>
63 <Text dimColor>
64 {' '}
65 {pct}% context, {word}
66 </Text>
67 </Box>
68 )
69 })
70}
71types/index.d.ts 10 lines1// Context window fill, as a whole percentage (0 to 100), null until the first
2// API response of the live window.
3export type Fill = number | null
4
5declare module 'claude-code' {
6 interface PluginState {
7 'context-weather': { percent: number | null }
8 }
9}
10