Status line: model, context window, 5-hour and weekly limits with reset times, warning past 90%. Hungarian or English.

Saját Claude Code mod-ok (function hook pluginek) egy pluginpiacon.
claude plugin marketplace add Szotasz/claude-mods
claude plugin install usage-band@claude-mods
claude plugin install usage-header@claude-mods
claude plugin install project-pane@claude-mods
claude plugin install focus-mode@claude-mods
claude plugin install tool-hub@claude-mods
claude plugin install snake-pane@claude-mods
claude plugin install supabase-guard@claude-mods
claude plugin install public-repo-guard@claude-mods
claude plugin install decision-popup@claude-mods
Frissítés: claude plugin update usage-band@claude-mods, majd /reload-plugins (vagy új session).
A státuszsorba (a prompt alá) írja:
🤖 Opus 5.5 │ Ctx ███░░░░░ 42% 420k/1M │ 5h ███░░░░░ 34% → 16:20 │ Hét ███████░ 93% ⚠ → Cs 10:00
/model váltáskor és turn végén frissül)Nyelv / Language: /config → usage-band.language, vagy a settings.json-ban:
"pluginConfigs": { "usage-band": { "language": "en" } }
auto (alapértelmezett): magyar, ha a rendszer nyelve (LANG) magyar, különben angolhu: magyar (Hét, Cs 10:00)en: English (Week, Thu 10:00)Követelmény: Claude Code 2.1.289 körüli verzió. A mod-API early access, kiadásról kiadásra változhat.
Sáv a prompt fölött: a kontextusablak kategóriánként színezve, alatta az 5 órás és a heti limit.
Kontextus ██▓▓▓▓▓▓████████████▒▒▒▒▒▒▒▒▒░░░░░░░░░░░░░░ 42% 84k/200k
■ Rendszerprompt 3k ■ Eszközök 12k ■ Memória 400 ■ Üzenetek 69k ▒ Tömörítési tartalék 33k ░ Szabad 83k
Limitek 5 óra ███████░░░░░░░░░░░░░ 34% → 16:20 Hét ███████████████████░ 93% ⚠ → Cs 10:00
/context saját színével látszik (rendszerprompt, eszközök, MCP, memóriafájlok, skillek, ágensek, üzenetek), utána a tömörítési tartalék és a szabad hely halványan; alatta jelmagyarázat tokenszámmal. Az igény szerint betöltött (halasztott) eszközsémák kimaradnak, mert nincsenek az ablakban.$.session.usage({ breakdown: 'summary' })), API-hívás nélkül; minden turn végén és limitmozduláskor frissül./hasznalat kapcsolja, /hasznalat be|ki beállítja; az állapotot sessionök között megőrzi. Az eszköztárban (/eszkozok) is kapcsolható.Beállítás (/config): usage-header.language (auto/hu/en).
Oldalpanel az aktuális git repóhoz. Magától megnyílik, ha a session git repóban indul és a terminál legalább 144 oszlop széles (miután egyszer /project-tel megnyitottad, 110 is elég); keskenyebb ablaknál egy toast szól, hogy vár. Bármikor: /project.
acme/shop ↻ most [ Frissítés ]
GIT
🌿 develop ↑0 ↓0 · 7 módosított fájl
utolsó commit: 57704fe · 7 hónapja — Fix checkout flow
⚠ a main 13 committal előrébb jár, te a develop branch-en vagy
Előbb commitold a módosításokat, vagy tedd félre őket:
[ Stash + szinkron ]
DEPLOY (Netlify)
✔ ready main 3 perce
PULL REQUESTEK
✔ #142 Stripe webhook retry · approved
CI (GitHub Actions)
✘ netlify-deploy-verify main · 5 napja [ Kérdezd Claude-ot ]
SUPABASE
abcdefghijklmnopqrst · Acme Shop · eu-west-3
18 migráció · utolsó: 018_add_orders_rls.sql
GitHub Netlify Supabase
s): csak fast-forward, soha nem merge-öl, rebase-el vagy töröl.git pull --ff-onlygit switch main + git merge --ff-only origin/maingit stash push -u, vissza: git stash popr): 60 mp-enként és minden turn végén; git fetch 5 percenként.a): a legutóbbi elbukott CI-futásról kérdést tesz a promptba.Adatforrások (a CLI-k saját bejelentkezésével, a plugin tokent nem olvas):
| Szekció | Forrás | Ha hiányzik |
|---|---|---|
| Git | git | — |
| PR, CI | gh (gh auth login) | tipp a panelen |
| Deploy | netlify CLI + .netlify/state.json | npm i -g netlify-cli && netlify login |
| Supabase | supabase/.temp/project-ref, supabase/migrations, supabase projects list | supabase login az állapothoz |
Beállítás (/config): project-pane.language (auto/hu/en), project-pane.autoOpen (alapból be).
Fókusz mód: a transcriptből eltűnnek az eszközhívások és eredményeik, a köztes szövegek, a saját promptjaid és a parancsok kimenete. Csak két dolog marad: a prompt fölötti sávban a részfeladatok listája állapotsávval és pipával, alatta a turn végső válasza.
✔ Meglévő mod-repo áttekintése
◐ Játék-mod megírása ██████░░░░ 60%
○ Felvétel az eszközök közé
/fokusz kapcsolja, /fokusz be / /fokusz ki beállítja; az állapotot sessionök között megőrzi.mcp__focus-mode__plan eszközzel; a rendszerprompt bekapcsolt állapotban erre utasítja (minden több lépéses kérésnél előbb a részfeladatok, aztán frissítés indításkor, haladáskor és befejezéskor).Beállítás (/config): focus-mode.language (auto/hu/en).
Eszköztár: egy helyről kapcsolhatók a fenti modok. A prompt alatti lábléc jobb oldalán lévő ⚙ Eszközök gomb (vagy /eszkozok) a prompt fölötti sávban nyitja meg:
⚙ Szabolcs eszközei kattintás, vagy ctrl+x tab után szám [ Bezár ]
1. Fókusz mód ● BE [ Kikapcsol ] · Csak a részfeladatok listája és a végső válasz látszik
2. Limitsáv ○ KI [ Bekapcsol ] · Alsó sáv: 5 órás és heti limit, kontextusablak
3. Használati sáv ● BE [ Kikapcsol ] · Prompt fölött: kontextus kategóriánként színezve, 5 órás és heti limit
4. Projektpanel ● BE [ Kikapcsol ] · GitHub, CI, Netlify és Supabase állapot oldalt
5. Kígyó játék ● BE [ Kikapcsol ] · Oldalt nyílik promptküldéskor, amíg Claude dolgozik
ctrl+x tab után az 1–5 számbillentyűvel is./fokusz, /limitsav, /hasznalat, /project, /jatek (mind be|ki argumentummal).Új mod felvétele az eszköztárba: a mod írja a saját isOn állapotát, adjon /<parancs> be|ki-t, és hookolja a state.set-et { plugin: 'tool-hub', key: 'request' }-re; a hubban egy sor a TOOLS listába, egy ág a stateOf-ba és a kulcs a types/index.d.ts-be.
Beállítás (/config): tool-hub.language (auto/hu/en).
Kígyó játék az oldalpanelben, amíg Claude dolgozik.
⏳ Claude dolgozik…
Pont: 4 Rekord: 17
╭──────────────────────────────────────╮
│ │
│ ████████ │
│ ██ ● │
╰──────────────────────────────────────╯
p: szünet · r: újra
w: ↑ a: ← s: ↓ d: → p: szünet r: új
/jatek mindig nyitja). /jatek ki kikapcsolja, az eszköztárban (/eszkozok) is kapcsolható.wasd / hjkl, szóköz vagy p szünet, r új játék. Vagy ctrl+x tab a panelre, és a w a s d p r gombok.Client surface modul), nem terheli a sessiont.Supabase-őr: megállítja a Supabase-hívást, ha nem az aktuális mappa projektjére menne, és egygombos felugróban rákérdez.
supabase/.temp/project-ref, a .env* fájlok https://<ref>.supabase.co címei és a CLAUDE.md (ha egyetlen projekt-ID-t említ) adják, plusz amit a felugróban „Ez a mappa projektje” gombbal megerősítettél.execute_sql, apply_migration, deploy_edge_function, branch-műveletek, illetve supabase db push --project-ref …): kérdez — Megtiltom / Engedélyezem / Ez a mappa projektje.DROP, TRUNCATE, DELETE FROM, WHERE nélküli UPDATE, REVOKE, RLS kikapcsolása, reset_branch, delete_branch, pause_project, supabase db reset --linked./supaor be|ki, vagy az eszköztárban.Push-őr: nyilvános GitHub-repóba push előtt (és gh repo edit --visibility public / gh repo create --public előtt) átnézi, mi menne ki.
git push origin forrás:cél alakot is.project_id, táblázatsor), JWT / Supabase-kulcs, Stripe/Anthropic/OpenAI/GitHub/AWS/Google/Slack/Resend/Telegram/ElevenLabs kulcsok, privát kulcs, e-mail-cím (a saját git e-mail és a noreply/példa címek kivételével), helyi /Users/<te>/ útvonal, privát repóid nevei (gh repo list --visibility private), .env fájlok, és amit /pushor figyel <szöveg>-gel felvettél.gh CLI (bejelentkezve). /pushor be|ki.Döntési felugró: a döntések egygombos kérdésként jönnek.
/dontes be|ki, vagy az eszköztárban.project-pane bővítése:
vercel ls)Státuszsor bővítése (usage-band):
/compact$.session.usage().cost)userConfig)Új mod-ok:
.env, kulcsfájlok, supabase/.temp szerkesztésének tiltása (tool.call → deny)turn.complete, $.audio.play)/quote — a kijelölt szöveget idézetként a promptba teszi ($.ui.selection)prompt.compose)Egy plugin mappája közvetlenül is betölthető:
claude --plugin-dir ./plugins/usage-band
Ellenőrzés:
claude plugin validate plugins/usage-band
claude plugin test plugins/usage-bandhooks/register.tsx 182 lines1import { atom, read, update } from 'claude-code'
2import type { EngineInterface, Register, SessionContextUsage } from 'claude-code'
3
4import type { Context, Limit } from '../types'
5
6const limits = atom({ plugin: 'usage-band', key: 'limits' } as const, [])
7// Ablak + reset párosok, amikre már szóltunk: így egy ablakra resetenként egyszer jön toast.
8const warned = atom({ plugin: 'usage-band', key: 'warned' } as const, [])
9const context = atom({ plugin: 'usage-band', key: 'context' } as const, null)
10const model = atom({ plugin: 'usage-band', key: 'model' } as const, null)
11// Kikapcsolva üres a státuszsor; az eszköztár (tool-hub) is ezt olvassa.
12const isOn = atom({ plugin: 'usage-band', key: 'isOn' } as const, true)
13
14const WARN_AT = 90
15
16type Strings = { labels: Record<string, string>; days: string[]; limit: string; command: string; on: string; off: string; usage: string }
17
18const STRINGS: Record<'hu' | 'en', Strings> = {
19 hu: {
20 labels: { five_hour: '5h', seven_day: 'Hét' },
21 days: ['V', 'H', 'K', 'Sze', 'Cs', 'P', 'Szo'],
22 limit: 'limit',
23 command: 'Limit- és kontextussáv be/ki',
24 on: 'Limitsáv bekapcsolva.',
25 off: 'Limitsáv kikapcsolva.',
26 usage: 'Használat: /limitsav [be|ki]',
27 },
28 en: {
29 labels: { five_hour: '5h', seven_day: 'Week' },
30 days: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'],
31 limit: 'limit',
32 command: 'Usage and context bar on/off',
33 on: 'Usage bar on.',
34 off: 'Usage bar off.',
35 usage: 'Usage: /limitsav [on|off]',
36 },
37}
38
39// A modul minden beállításváltáskor újratöltődik, így elég egyszer, induláskor eldönteni.
40let t: Strings = STRINGS.en
41const LABELS = (): Record<string, string> => t.labels
42const WIDTH = 8
43
44function bar(percent: number): string {
45 const filled = Math.min(WIDTH, Math.round((percent / 100) * WIDTH))
46 return '█'.repeat(filled) + '░'.repeat(WIDTH - filled)
47}
48
49const warnMark = (percent: number) => (percent >= WARN_AT ? ' ⚠' : '')
50
51function resetText(kind: string, resetsAt?: string): string {
52 if (resetsAt === undefined) return ''
53 const at = new Date(resetsAt)
54 const hhmm = `${String(at.getHours()).padStart(2, '0')}:${String(at.getMinutes()).padStart(2, '0')}`
55 if (kind === 'five_hour') return ` → ${hhmm}`
56 return ` → ${t.days[at.getDay()]} ${hhmm}`
57}
58
59function tokens(n: number): string {
60 if (n >= 1_000_000) return `${Number((n / 1_000_000).toFixed(1))}M`
61 return n >= 1000 ? `${Math.round(n / 1000)}k` : String(n)
62}
63
64// Csak akkor van mit mutatni, ha már jött válasz, amiből a telítettség kiderül.
65function toContext(usage: SessionContextUsage): Context | null {
66 if (usage.percent === undefined) return null
67 return { percent: usage.percent, tokens: usage.tokens, window: usage.window }
68}
69
70async function refreshModel($: EngineInterface): Promise<void> {
71 const current = await $.session.model()
72 await update($, model, () => current)
73}
74
75// A státuszsor sima szöveg (színt nem visz): a 90% fölötti értéket ⚠ jelzi.
76async function pushStatus($: EngineInterface): Promise<void> {
77 if (!(await read($, isOn))) {
78 $.ui.status(undefined)
79 return
80 }
81 const name = await read($, model)
82 const ctx = await read($, context)
83 const shown = (await read($, limits)).filter(l => l.kind in LABELS())
84
85 const parts: string[] = []
86 if (name !== null) parts.push(`🤖 ${name}`)
87 if (ctx !== null) {
88 const used = ctx.tokens === undefined ? '' : ` ${tokens(ctx.tokens)}/${tokens(ctx.window)}`
89 parts.push(`Ctx ${bar(ctx.percent)} ${ctx.percent}%${used}${warnMark(ctx.percent)}`)
90 }
91 for (const l of shown) {
92 const pct = Math.round(l.percentUsed)
93 parts.push(`${LABELS()[l.kind]} ${bar(l.percentUsed)} ${pct}%${warnMark(l.percentUsed)}${resetText(l.kind, l.resetsAt)}`)
94 }
95 $.ui.status(parts.length === 0 ? undefined : parts.join(' │ '))
96}
97
98async function warnPast90($: EngineInterface, current: Limit[]): Promise<void> {
99 const already = await read($, warned)
100 const fresh = current.filter(
101 l => l.kind in LABELS() && l.percentUsed >= WARN_AT && !already.includes(`${l.kind}@${l.resetsAt}`),
102 )
103 if (fresh.length === 0) return
104
105 for (const l of fresh) {
106 $.ui.toast(
107 `⚠ ${LABELS()[l.kind]} ${t.limit}: ${Math.round(l.percentUsed)}%${resetText(l.kind, l.resetsAt)}`,
108 { timeoutMs: 10000 },
109 )
110 }
111 await update($, warned, list => [...list, ...fresh.map(l => `${l.kind}@${l.resetsAt}`)])
112}
113
114async function setOn($: EngineInterface, wanted: boolean): Promise<void> {
115 await update($, isOn, () => wanted)
116 await $.store.set('isOn', wanted)
117 await pushStatus($)
118}
119
120async function pickLanguage($: EngineInterface, setting: unknown): Promise<Strings> {
121 if (setting === 'hu' || setting === 'en') return STRINGS[setting]
122 const locale = (await $.env.get('LC_ALL')) || (await $.env.get('LANG')) || ''
123 return locale.toLowerCase().startsWith('hu') ? STRINGS.hu : STRINGS.en
124}
125
126export const register: Register = (on, options) => {
127 if (options.language === 'hu' || options.language === 'en') t = STRINGS[options.language]
128
129 on('session.start', async ($, e, next) => {
130 t = await pickLanguage($, options.language)
131 const result = await next(e)
132 const saved = (await $.store.get('isOn')) !== false
133 await update($, isOn, () => saved)
134 await $.command.register({ name: 'limitsav', description: t.command, argumentHint: t === STRINGS.hu ? '[be|ki]' : '[on|off]', immediate: true })
135 const usage = await $.session.usage()
136 await update($, limits, () => usage.rateLimits)
137 await update($, context, () => toContext(usage.context))
138 await warnPast90($, usage.rateLimits)
139 await refreshModel($)
140 await pushStatus($)
141 return result
142 })
143
144 on('command.run', { command: 'limitsav' }, async ($, e) => {
145 const arg = e.args.trim().toLowerCase()
146 const wanted = ['be', 'on'].includes(arg) ? true : ['ki', 'off'].includes(arg) ? false : arg === '' ? !(await read($, isOn)) : null
147 if (wanted === null) return { text: t.usage }
148 await setOn($, wanted)
149 return { text: wanted ? t.on : t.off }
150 })
151
152 // Az eszköztár gombja parancs nélkül kapcsol (így nem marad parancssor a transcriptben).
153 on('state.set', { plugin: 'tool-hub', key: 'request' }, async ($, e, next) => {
154 const done = await next(e)
155 if (e.value?.tool === 'limits') await setOn($, e.value.on)
156 return done
157 })
158
159 on('classic.PostModelSwitch', async ($, e, next) => {
160 const result = await next(e)
161 await refreshModel($)
162 await pushStatus($)
163 return result
164 })
165
166 on('session.measure', async ($, e, next) => {
167 if (e.changed.includes('context')) {
168 const current = toContext(e.context)
169 await update($, context, () => current)
170 }
171 // Turn végén is ránézünk: így az automatikus fallback is látszik.
172 await refreshModel($)
173 if (e.changed.includes('rateLimits')) {
174 const current: Limit[] = e.rateLimits
175 await update($, limits, () => current)
176 await warnPast90($, current)
177 }
178 await pushStatus($)
179 return next(e)
180 })
181}
182types/index.d.ts 13 lines1export type Limit = { kind: string; percentUsed: number; resetsAt?: string }
2export type Context = { percent: number; tokens?: number; window: number }
3
4// Az eszköztár (tool-hub) kérése: a kapcsoló gomb ezt írja, a mod a state.set hookjában veszi át.
5export type HubRequest = { tool: string; on: boolean; n: number }
6
7declare module 'claude-code' {
8 interface PluginState {
9 'tool-hub': { request: HubRequest | null }
10 'usage-band': { limits: Limit[]; warned: string[]; context: Context | null; model: string | null; isOn: boolean }
11 }
12}
13