Personal collection of Claude Code skills: commit, code-review, security-scan, implement, dep-triage, okf-init, analyse-external-repo (with the read-only…

hooks/register.ts 75 lines1import type { EngineInterface as Engine, Register } from 'claude-code'
2
3import { formatUsage } from './format'
4
5const ENABLED_KEY = 'enabled'
6const DEFAULT_INTERVAL_SECONDS = 30
7const MIN_INTERVAL_SECONDS = 5
8
9// The running refresh timer's cancel, while the overlay is on.
10let cancel: (() => void) | undefined
11
12// The overlay is a toast: the engine's only layer that floats over the
13// transcript's top-right corner. Each refresh posts a toast that lives for one
14// interval, so the next one takes its place instead of stacking under it.
15async function show($: Engine, intervalMs: number) {
16 const usage = await $.session.usage()
17 const now = await $.clock.now()
18 $.ui.toast(formatUsage(usage, now), { timeoutMs: intervalMs })
19}
20
21async function start($: Engine, intervalMs: number) {
22 if (cancel) {
23 return
24 }
25 const timer = $.clock.every(intervalMs, () => void show($, intervalMs))
26 cancel = () => timer.cancel()
27 await show($, intervalMs)
28}
29
30function stop() {
31 cancel?.()
32 cancel = undefined
33}
34
35async function isEnabled($: Engine) {
36 return (await $.store.get(ENABLED_KEY)) !== false
37}
38
39export const register: Register = (on, options) => {
40 const configured = Number(options.intervalSeconds ?? DEFAULT_INTERVAL_SECONDS)
41 const seconds = Number.isFinite(configured) ? configured : DEFAULT_INTERVAL_SECONDS
42 const intervalMs = Math.max(MIN_INTERVAL_SECONDS, seconds) * 1000
43
44 on('session.start', async ($, e, next) => {
45 await $.command.register({
46 name: 'usage-overlay',
47 description: 'Toggle the usage overlay in the top-right corner (on, off, or now)',
48 })
49 if (await isEnabled($)) {
50 await start($, intervalMs)
51 }
52
53 return next(e)
54 })
55
56 on('command.run', { command: 'usage-overlay' }, async ($, e) => {
57 const arg = e.args.trim().toLowerCase()
58
59 if (arg === 'now') {
60 await show($, intervalMs)
61 return { text: 'Usage overlay refreshed.' }
62 }
63
64 const enable = arg === 'on' ? true : arg === 'off' ? false : !(await isEnabled($))
65 await $.store.set(ENABLED_KEY, enable)
66 if (enable) {
67 await start($, intervalMs)
68 return { text: `Usage overlay on, refreshing every ${intervalMs / 1000}s.` }
69 }
70 stop()
71
72 return { text: 'Usage overlay off.' }
73 })
74}
75hooks/format.ts 65 lines1import type { SessionUsage } from 'claude-code'
2
3const WINDOW_LABELS: Record<string, string> = {
4 five_hour: '5h',
5 seven_day: '7d',
6 spend_limit: 'spend',
7}
8
9// Formats a duration in milliseconds as "2h10m", "45m" or "3d4h".
10export const formatDuration = (ms: number): string => {
11 const minutes = Math.max(0, Math.round(ms / 60_000))
12 const days = Math.floor(minutes / 1440)
13 const hours = Math.floor((minutes % 1440) / 60)
14 const mins = minutes % 60
15
16 if (days > 0) {
17 return `${days}d${hours}h`
18 }
19 if (hours > 0) {
20 return `${hours}h${String(mins).padStart(2, '0')}m`
21 }
22
23 return `${mins}m`
24}
25
26// Formats a token count as "850", "45k" or "1.2M".
27export const formatTokens = (tokens: number): string => {
28 if (tokens >= 1_000_000) {
29 return `${(tokens / 1_000_000).toFixed(1)}M`
30 }
31 if (tokens >= 1_000) {
32 return `${Math.round(tokens / 1_000)}k`
33 }
34
35 return String(tokens)
36}
37
38// Builds the one line the overlay shows, e.g.
39// "5h 23% ↻2h10m · 7d 41% ↻3d4h · ctx 45k 23% · $1.23".
40export const formatUsage = (usage: SessionUsage, now: number): string => {
41 const parts: string[] = []
42
43 for (const limit of usage.rateLimits) {
44 const label = WINDOW_LABELS[limit.kind] ?? limit.kind
45 let part = `${label} ${Math.round(limit.percentUsed)}%`
46 const resetsAt = limit.resetsAt ? Date.parse(limit.resetsAt) : NaN
47 if (!Number.isNaN(resetsAt) && resetsAt > now) {
48 part += ` ↻${formatDuration(resetsAt - now)}`
49 }
50 parts.push(part)
51 }
52
53 const { context } = usage
54 if (context.tokens !== undefined) {
55 const percent = context.percent !== undefined ? ` ${context.percent}%` : ''
56 parts.push(`ctx ${formatTokens(context.tokens)}${percent}`)
57 }
58
59 if (usage.cost) {
60 parts.push(`$${usage.cost.usd.toFixed(2)}`)
61 }
62
63 return parts.length > 0 ? parts.join(' · ') : 'no usage yet'
64}
65