SLOPSHOPPER

polimento-visual

Pill de contexto sob o prompt, borda laranja nas suas mensagens e ícones coloridos por tipo de execução

newspinnerrows
v0.1.0no licenseupdated 2026-10-26DiogoHSM/claude-mods/polimento-visual
A shopper browsing a rack in a slop shop
Preview · a replayed session in a sandbox
claude · ~/work/app · polimento-visual
╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │ ⟨Claude Code's own drawing⟩ │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ⏺ Read(src/auth.ts) ⎿ Read 6 lines ✎ ⟨Claude Code's own drawing⟩ ⏺ Bash(bun test) ⎿ 3 pass, 1 fail ● Done. refresh now rejects expired claims and logs an audit event. ✻ Worked for 42s · done 4:20 PM ────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── › ⟨Claude Code's own drawing⟩ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │ ● 97k / 200k · 49% │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯

Draws

Prompt hint
⟨Claude Code's own drawing⟩ ╭─────────────────────────────────────────────────────────────────────── │ ● 97k / 200k · 49% ╰───────────────────────────────────────────────────────────────────────
Your message
╭──────────────────────────────────────────────────────────────────────────────────────────────────╮ │ ⟨Claude Code's own drawing⟩ │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────╯
Tool row
✎ ⟨Claude Code's own drawing⟩
README

claude-mods

Mods pessoais para Claude Code (terminal e aba Code do app desktop).

Mods

ModO que faz
agentes-pixelPainel lateral com pixel art de cada subagent (modelo, status, tempo, tokens, resumo), bolinhas de status das tarefas e barra do plano acima do prompt. /agentes reabre o painel.
polimento-visualPill de contexto usado/total abaixo do prompt, borda laranja nas suas mensagens e ícones coloridos por tipo de ferramenta.

Instalação

claude plugin marketplace add DiogoHSM/claude-mods
claude plugin install agentes-pixel@diogo-mods --scope user
claude plugin install polimento-visual@diogo-mods --scope user

Ou, no prompt do Claude Code:

/plugin install agentes-pixel --marketplace DiogoHSM/claude-mods
/plugin install polimento-visual --marketplace DiogoHSM/claude-mods

No app desktop: + ao lado do prompt → Plugins → Add marketplace com DiogoHSM/claude-mods → Add plugin.

Desenvolvimento local

claude plugin marketplace add ~/Developer/Github/claude-mods
claude plugin install agentes-pixel@diogo-mods --scope user

Depois de editar um mod, rode /reload-plugins.

Validação

claude plugin validate agentes-pixel
claude plugin test agentes-pixel
Source 2 files
hooks/register.tsx 216 lines
1import { atom, read, update } from 'claude-code'
2import type { EngineInterface, Register } from 'claude-code'
3
4const context = atom({ plugin: 'polimento-visual', key: 'context' } as const, null)
5
6const PERSON = new Set(['composer', 'bridge', 'sdk'])
7
8type Kind = 'read' | 'search' | 'edit' | 'shell' | 'web' | 'agent' | 'plan' | 'skill' | 'mcp' | 'other'
9
10const COLOR: Record<Kind, string> = {
11  read: '#378ADD',
12  search: '#378ADD',
13  edit: '#D4537E',
14  shell: '#888780',
15  web: '#1D9E75',
16  agent: '#7F77DD',
17  plan: '#639922',
18  skill: '#D85A30',
19  mcp: '#BA7517',
20  other: '#888780',
21}
22
23const GLYPH: Record<Kind, string> = {
24  read: '▤',
25  search: '⌕',
26  edit: '✎',
27  shell: '›_',
28  web: '◍',
29  agent: '◉',
30  plan: '☰',
31  skill: '✦',
32  mcp: '⧉',
33  other: '•',
34}
35
36const PATHS: Record<Kind, string> = {
37  read: '<path d="M5 2.5h4.5L12 5v8.5H5z"/><path d="M9.5 2.5V5H12M7 8h3M7 10.5h3"/>',
38  search: '<circle cx="7.5" cy="7.5" r="3.5"/><path d="M10 10l3 3"/>',
39  edit: '<path d="M3.5 12.5l1-3 6-6 2 2-6 6z"/><path d="M9.5 4.5l2 2"/>',
40  shell: '<path d="M3.5 5l3 3-3 3M8 11.5h4.5"/>',
41  web: '<circle cx="8" cy="8" r="5"/><path d="M3 8h10M8 3c-2 2.5-2 7.5 0 10M8 3c2 2.5 2 7.5 0 10"/>',
42  agent: '<rect x="3.5" y="5" width="9" height="7" rx="2"/><path d="M8 2.5V5M6.5 8.5v.5M9.5 8.5v.5"/>',
43  plan: '<path d="M3 4.5l1 1 1.5-2M3 9.5l1 1 1.5-2M7.5 4.5h5.5M7.5 9.5h5.5M7.5 13h5.5"/>',
44  skill: '<path d="M8 2.5l1.5 4 4 1.5-4 1.5-1.5 4-1.5-4-4-1.5 4-1.5z"/>',
45  mcp: '<path d="M6 2.5v3M10 2.5v3M4.5 5.5h7v2a3.5 3.5 0 0 1-7 0zM8 11v2.5"/>',
46  other: '<circle cx="8" cy="8" r="2"/>',
47}
48
49function kindOf(tool: string): Kind {
50  if (['Read', 'NotebookRead', 'LS'].includes(tool)) return 'read'
51  if (['Grep', 'Glob', 'ToolSearch', 'LSP'].includes(tool)) return 'search'
52  if (['Edit', 'Write', 'MultiEdit', 'NotebookEdit'].includes(tool)) return 'edit'
53  if (['Bash', 'BashOutput', 'KillShell', 'Monitor'].includes(tool)) return 'shell'
54  if (['WebFetch', 'WebSearch'].includes(tool) || /^mcp__(Claude_Browser|claude-in-chrome|plugin_playwright|plugin_chrome-devtools)/.test(tool)) {
55    return 'web'
56  }
57  if (['Agent', 'Task', 'SendMessage', 'Workflow', 'TaskStop'].includes(tool)) return 'agent'
58  if (['TaskCreate', 'TaskUpdate', 'TaskList', 'TaskGet', 'TodoWrite', 'EnterPlanMode', 'ExitPlanMode'].includes(tool) || tool.startsWith('mcp__ccd_turn__')) {
59    return 'plan'
60  }
61  if (tool === 'Skill') return 'skill'
62  if (tool.startsWith('mcp__')) return 'mcp'
63
64  return 'other'
65}
66
67function icon(kind: Kind, color = COLOR[kind]): string {
68
69  return `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="18" height="18"><rect x="0" y="0" width="16" height="16" rx="4" fill="${color}" fill-opacity="0.16"/><g fill="none" stroke="${color}" stroke-width="1.4" stroke-linecap="round" stroke-linejoin="round">${PATHS[kind]}</g></svg>`
70}
71
72function short(n: number): string {
73  if (n < 1000) return `${n}`
74  if (n < 1_000_000) return `${Math.round(n / 1000)}k`
75
76  return `${(n / 1_000_000).toFixed(n % 1_000_000 === 0 ? 0 : 1)}M`
77}
78
79async function refreshContext($: EngineInterface) {
80  const usage = await $.session.usage()
81  const { tokens, window } = usage.context
82  if (tokens === undefined || !window) return
83  const percent = usage.context.percent ?? (tokens / window) * 100
84  await update($, context, () => ({ tokens, window, percent }))
85}
86
87export const register: Register = on => {
88  on('session.start', async ($, e, next) => {
89    const started = await next(e)
90    void refreshContext($)
91
92    return started
93  })
94
95  on('turn.step', async function* ($, e, next) {
96    const step = yield* next(e)
97    if (e.agentId === undefined) void refreshContext($)
98
99    return step
100  })
101
102  on('turn.complete', async ($, e, next) => {
103    const done = await next(e)
104    if (e.agentId === undefined) void refreshContext($)
105
106    return done
107  })
108
109  on('ui.render', { component: 'PromptHint' }, async ($, e, next) => {
110    const use = await read($, context)
111    const own = await next(e)
112    if (!use) return own
113    const { Box, Text } = $.ui.resolve(e)
114    const tone = use.percent < 50 ? 'success' : use.percent < 80 ? 'warning' : 'error'
115
116    return (
117      <Box flexDirection="row" justifyContent="space-between" alignItems="center" gap={1}>
118        <Box flexShrink={1}>
119          {own}
120        </Box>
121        <Box borderStyle="round" borderColor="subtle" paddingX={1} flexShrink={0}>
122          <Text size="caption" tabular>
123            <Text color={tone}>●</Text>{' '}
124            <Text dimColor>{`${short(use.tokens)} / ${short(use.window)} · ${Math.round(use.percent)}%`}</Text>
125          </Text>
126        </Box>
127      </Box>
128    )
129  })
130
131  on('ui.render', { component: 'UserMessage' }, async ($, e, next) => {
132    const own = await next(e)
133    if (!PERSON.has(e.props.origin.kind) || e.props.from !== undefined) return own
134    const { Box, Text } = $.ui.resolve(e)
135    if (e.surface === 'terminal') {
136      return (
137        <Box borderStyle="round" borderColor="claude" paddingX={1}>
138          {own}
139        </Box>
140      )
141    }
142
143    return (
144      <Box flexDirection="row" marginY={1}>
145        <Box flexShrink={1} borderStyle="round" borderColor="claude" paddingX={1}>
146          <Text>{e.props.text}</Text>
147        </Box>
148      </Box>
149    )
150  })
151
152  on('ui.render', { component: 'AssistantMessage' }, async ($, e, next) => {
153    const own = await next(e)
154    if (!e.props.isFirstOfReply) return own
155    const { Box, Text } = $.ui.resolve(e)
156    const Svg = e.surface === 'terminal' ? undefined : $.ui.resolve(e).Svg
157
158    return (
159      <Box flexDirection="row" gap={1} alignItems="flex-start">
160        {Svg ? (
161          <Svg source={icon('skill')} alt="Resposta do Claude" width={18} height={18} />
162        ) : (
163          <Text color="claude">{GLYPH.skill}</Text>
164        )}
165        <Box flexGrow={1} flexShrink={1}>
166          {own}
167        </Box>
168      </Box>
169    )
170  })
171
172  on('ui.render', { component: 'ToolUse' }, async ($, e, next) => {
173    const own = await next(e)
174    if (e.props.tool === 'mcp__ccd_turn__update_plan') return own
175    const kind = kindOf(e.props.tool)
176    const color = e.props.isErrored ? '#E24B4A' : COLOR[kind]
177    const { Box, Text } = $.ui.resolve(e)
178    const Svg = e.surface === 'terminal' ? undefined : $.ui.resolve(e).Svg
179
180    return (
181      <Box flexDirection="row" gap={1} alignItems="flex-start">
182        {Svg ? (
183          <Svg source={icon(kind, color)} alt={e.props.tool} width={18} height={18} />
184        ) : (
185          <Text color={color}>{GLYPH[kind]}</Text>
186        )}
187        <Box flexGrow={1} flexShrink={1}>
188          {own}
189        </Box>
190      </Box>
191    )
192  })
193
194  on('ui.render', { component: 'ToolGroup' }, async ($, e, next) => {
195    const own = await next(e)
196    const first = e.props.calls[0]
197    if (!first) return own
198    const kind = kindOf(first.tool)
199    const { Box, Text } = $.ui.resolve(e)
200    const Svg = e.surface === 'terminal' ? undefined : $.ui.resolve(e).Svg
201
202    return (
203      <Box flexDirection="row" gap={1} alignItems="flex-start">
204        {Svg ? (
205          <Svg source={icon(kind)} alt={first.tool} width={18} height={18} />
206        ) : (
207          <Text color={COLOR[kind]}>{GLYPH[kind]}</Text>
208        )}
209        <Box flexGrow={1} flexShrink={1}>
210          {own}
211        </Box>
212      </Box>
213    )
214  })
215}
216
types/index.d.ts 8 lines
1export type ContextUse = { tokens: number; window: number; percent: number }
2
3declare module 'claude-code' {
4  interface PluginState {
5    'polimento-visual': { context: ContextUse | null }
6  }
7}
8