Shows 5-hour and weekly usage in the status line and alerts when either reaches 90%

hooks/register.tsx 70 lines1import { atom, read, update } from 'claude-code'
2import type { Register } from 'claude-code'
3
4import type { Limit } from '../types'
5
6const THRESHOLD = 90
7
8const limits = atom({ plugin: 'usage-alert', key: 'limits' } as const, [] as Limit[])
9
10const LABELS: Record<string, string> = {
11 five_hour: '5-hour',
12 seven_day: 'weekly',
13}
14
15const label = (kind: string) => LABELS[kind] ?? kind
16
17export const register: Register = on => {
18 // Windows already alerted on; cleared when a window drops below the threshold.
19 const alerted = new Set<string>()
20
21 on('session.measure', async ($, e, next) => {
22 const current: Limit[] = e.rateLimits.map(r => ({
23 kind: r.kind,
24 percentUsed: r.percentUsed,
25 }))
26 await update($, limits, () => current)
27
28 const hot = current.filter(r => r.percentUsed >= THRESHOLD)
29
30 for (const r of current) {
31 if (r.percentUsed < THRESHOLD) {
32 alerted.delete(r.kind)
33 }
34 }
35
36 for (const r of hot) {
37 if (!alerted.has(r.kind)) {
38 alerted.add(r.kind)
39 $.ui.toast(`⚠️ ${label(r.kind)} limit at ${Math.round(r.percentUsed)}%`)
40 }
41 }
42
43 const summary = current
44 .map(r => `${label(r.kind)} ${Math.round(r.percentUsed)}%`)
45 .join(' · ')
46 const alert = hot.length > 0 ? '⚠️ ' : ''
47 $.ui.status(summary === '' ? undefined : `${alert}${summary}`)
48
49 return next(e)
50 })
51
52 on('ui.render', { component: 'AbovePrompt' }, async ($, e, next) => {
53 const hot = (await read($, limits)).filter(r => r.percentUsed >= THRESHOLD)
54
55 if (hot.length === 0) {
56 return next(e)
57 }
58
59 const { Box, Text } = $.ui.resolve(e)
60
61 return (
62 <Box>
63 <Text color="red" bold>
64 ⚠️ {hot.map(r => `${label(r.kind)} ${Math.round(r.percentUsed)}%`).join(' · ')}
65 </Text>
66 </Box>
67 )
68 })
69}
70types/index.d.ts 8 lines1export type Limit = { kind: string; percentUsed: number }
2
3declare module 'claude-code' {
4 interface PluginState {
5 'usage-alert': { limits: Limit[] }
6 }
7}
8