Previsão do tempo da janela de contexto, numa linha acima do prompt.

Mods do Claude Code, em português.
| Mod | O que faz |
|---|---|
previsao-do-contexto | Previsão do tempo da janela de contexto: ícone e palavra por faixa de uso (🌞 Limpo, ⛅ Nublado, ☔ Chuva, ⚡ Tempestade, 🔥 Compacta logo), porcentagem e tokens, mini gráfico dos últimos 12 turnos e quanto o último turno somou. |
u (pasta task-progress) | Barra da tarefa: etapas E x/y, progresso T, tempo decorrido e estimado, e uso das janelas de 5 horas e semanal na linha de status. |
recomendar-perguntas | Ao fazer uma recomendação, o Claude abre uma janela com 3 a 5 perguntas (ou mais), com opções, antes de seguir. |
Com u e previsao-do-contexto instalados, a barra da tarefa e a previsão aparecem na mesma linha, as tarefas primeiro. O previsao-do-contexto funciona sozinho; sem o u, mostra só a previsão.
No prompt de uma sessão do Claude Code no terminal (aceite com y adicionar o marketplace e escolha o escopo user):
/plugin install previsao-do-contexto --marketplace dandevddqm/automatizacoes
/plugin install u --marketplace dandevddqm/automatizacoes
/plugin install recomendar-perguntas --marketplace dandevddqm/automatizacoes
Depois de instalado no terminal, no escopo de usuário, o mod também carrega no Claude Code desktop dessa máquina. O comando /plugin install não funciona dentro do desktop.
Os mods ficam em arquivos locais de cada computador: instale em cada máquina onde quiser usá-los.
Ao mudar um mod, suba a versão no plugin.json dele; sem isso o Claude Code continua usando a cópia em cache.
claude plugin marketplace update automatizacoes
claude plugin update previsao-do-contexto@automatizacoes --scope user
claude plugin validate previsao-do-contexto
claude plugin test previsao-do-contextohooks/register.tsx 68 lines1import { atom, read, update } from 'claude-code'
2import type { Register } from 'claude-code'
3
4import type { Previsao } from '../types'
5import { juntar } from './faixa'
6import { barrinhas, clima, formatarTokens, textoDelta } from './clima'
7
8const previsao = atom({ plugin: 'previsao-do-contexto', key: 'previsao' } as const, null)
9
10const TURNOS = 12
11
12export const register: Register = on => {
13 on('turn.complete', async ($, e, next) => {
14 // Só a conversa principal; subagentes têm a própria janela.
15 if (e.agentId === undefined) {
16 const { context } = await $.session.usage()
17 const tokens = context.tokens ?? 0
18 const percentual = Math.round(context.percent ?? (context.window > 0 ? (tokens / context.window) * 100 : 0))
19
20 await update($, previsao, (anterior: Previsao | null): Previsao => ({
21 tokens,
22 janela: context.window,
23 percentual,
24 delta: tokens - (anterior?.tokens ?? 0),
25 historico: [...(anterior?.historico ?? []), percentual].slice(-TURNOS),
26 }))
27 }
28
29 return next(e)
30 })
31
32 on('ui.render', { component: 'AbovePrompt' }, async ($, e, next) => {
33 // A faixa acima do prompt é uma só e este hook é o mais externo: o que outro
34 // mod desenha abaixo (a barra de tarefas do task-progress, por exemplo) vem
35 // em `next` e é mantido, na mesma linha, antes da previsão.
36 const abaixo = await next(e)
37 const atual = await read($, previsao)
38
39 if (e.props.hasSurvey || atual === null) {
40 return abaixo
41 }
42
43 const { Box, Text } = $.ui.resolve(e)
44 const { simbolo, palavra, cor } = clima(atual.percentual)
45
46 const linha = (
47 <Box>
48 <Text color={cor} bold>
49 {simbolo} {palavra}
50 </Text>
51 <Text dimColor>
52 {' '}
53 {atual.percentual}% · {formatarTokens(atual.tokens)} / {formatarTokens(atual.janela)}
54 {' '}
55 </Text>
56 <Text color={cor}>{barrinhas(atual.historico)}</Text>
57 <Text dimColor>
58 {' '}
59 {textoDelta(atual.delta)}
60 </Text>
61 </Box>
62 )
63
64 // As tarefas do outro mod ficam sempre em primeiro lugar, na mesma linha da previsão.
65 return abaixo ? (juntar(abaixo, linha) as typeof linha) : linha
66 })
67}
68hooks/faixa.ts 32 lines1type No = { type?: string; props?: Record<string, string | number | boolean>; children?: unknown[] }
2
3const isNo = (x: unknown): x is No => typeof x === 'object' && x !== null
4
5/**
6 * Junta, numa só linha, o que outro mod desenhou na faixa (`abaixo`) com a previsão (`linha`):
7 * a barra do outro mod vem primeiro, a previsão depois, e o botão de fechar dele, se houver,
8 * continua no fim. Se o desenho do outro mod não for um Box com botão no final, os dois ficam
9 * lado a lado do mesmo jeito.
10 */
11export const juntar = (abaixo: unknown, linha: unknown): No => {
12 const grupo = (filhos: unknown[]): No => ({
13 type: 'Box',
14 props: { flexDirection: 'row', flexShrink: 1, overflow: 'hidden', gap: 2 },
15 children: filhos,
16 })
17
18 if (isNo(abaixo) && abaixo.type === 'Box' && Array.isArray(abaixo.children) && abaixo.children.length > 0) {
19 const ultimo = abaixo.children[abaixo.children.length - 1]
20
21 if (isNo(ultimo) && ultimo.type === 'Button') {
22 return {
23 type: 'Box',
24 props: abaixo.props,
25 children: [grupo([...abaixo.children.slice(0, -1), linha]), ultimo],
26 }
27 }
28 }
29
30 return { type: 'Box', props: { flexDirection: 'row', gap: 2, overflow: 'hidden' }, children: [abaixo, linha] }
31}
32hooks/clima.ts 27 lines1const BARRAS = ['▁', '▂', '▃', '▄', '▅', '▆', '▇', '█']
2
3export type Clima = { simbolo: string; palavra: string; cor: string }
4
5export const clima = (percentual: number): Clima => {
6 if (percentual >= 90) return { simbolo: '🔥', palavra: 'Compacta logo', cor: 'red' }
7 if (percentual >= 75) return { simbolo: '⚡', palavra: 'Tempestade', cor: 'magenta' }
8 if (percentual >= 50) return { simbolo: '☔', palavra: 'Chuva', cor: 'blue' }
9 if (percentual >= 25) return { simbolo: '⛅', palavra: 'Nublado', cor: 'cyan' }
10 return { simbolo: '🌞', palavra: 'Limpo', cor: 'yellow' }
11}
12
13export const formatarTokens = (n: number): string => {
14 const abs = Math.abs(n)
15 if (abs >= 1_000_000) return `${(abs / 1_000_000).toFixed(abs % 1_000_000 === 0 ? 0 : 1)}M`
16 if (abs >= 1_000) return `${Math.round(abs / 1_000)}k`
17 return String(abs)
18}
19
20export const barrinhas = (historico: readonly number[]): string =>
21 historico
22 .map(p => BARRAS[Math.min(BARRAS.length - 1, Math.max(0, Math.floor((p / 100) * BARRAS.length)))])
23 .join('')
24
25export const textoDelta = (delta: number): string =>
26 `${delta < 0 ? '-' : '+'}${formatarTokens(delta)} no último turno`
27types/index.d.ts 19 lines1export type Previsao = {
2 /** Tokens usados na janela ao fim do último turno. */
3 tokens: number
4 /** Tamanho da janela de contexto do modelo. */
5 janela: number
6 /** Percentual usado, 0 a 100. */
7 percentual: number
8 /** Quanto o último turno somou (negativo após compactar ou limpar). */
9 delta: number
10 /** Percentual usado ao fim de cada um dos últimos 12 turnos. */
11 historico: number[]
12}
13
14declare module 'claude-code' {
15 interface PluginState {
16 'previsao-do-contexto': { previsao: Previsao | null }
17 }
18}
19