SLOPSHOPPER

cache-meter

Barra sopra il prompt che si svuota col tempo: quanto resta dell'ora di prompt cache dall'ultima richiesta

newbandtimer
★ 2v0.2.0MITupdated 2026-10-03DarioFontanel/claude-code-mods/cache-meter
A shopper browsing a rack in a slop shop
Preview · a replayed session in a sandbox
claude · ~/work/app · cache-meter
› fix the failing auth test and add an audit log call ⏺ Read(src/auth.ts) ⎿ Read 6 lines ⏺ Update(src/auth.ts) ⎿ Added 2 lines, removed 1 line ⏺ 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 cache · in attesa della prima richiesta ⟨Claude Code's own drawing⟩ ────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── › ? for shortcuts

Draws

Band
cache · in attesa della prima richiesta ⟨Claude Code's own drawing⟩
README

claude-code-mods

License: MIT Claude Code Mods

claude-code-mods è un marketplace di mod per Claude Code che ti permette di aggiungere all'interfaccia una barra della prompt cache, i prossimi passi a fine turno, un pannello di bottoni rapidi e il replay delle modifiche. Ogni mod è un plugin indipendente, installabile singolarmente con un comando.


Le quattro mod

⏳ cache-meter — una riga sopra il prompt con una barra che si svuota nel tempo: indica quanto resta dell'ora di prompt cache dall'ultima richiesta della conversazione principale. Verde oltre i 20 minuti, gialla oltre i 5, rossa sotto; allo scadere segnala che la richiesta successiva riscriverà la cache. Le richieste dei subagent non rinnovano la barra, perché usano una cache separata.

➡️ next-steps — a fine turno propone sopra il prompt due bottoni con i prossimi passi più naturali della conversazione, più un terzo bottone Replay. Premendo un passo, il prompt corrispondente viene inviato come se lo avessi scritto tu. I passi sono generati con una richiesta al modello a ogni fine turno, che consuma token.

🎛️ quick-buttons — un pannello laterale con un bottone per ogni comando ricorrente. Alla prima sessione dopo l'installazione la mod ti chiede quali skill e comandi vuoi come bottoni, elencando quelli presenti nella tua sessione; la scelta resta salvata tra le sessioni e puoi modificarla in qualsiasi momento.

⏪ replay-theater — registra le modifiche ai file dell'ultimo turno e le mostra in un pannello, un diff alla volta. È una variante della mod di esempio pubblicata da Anthropic in claude-code-playground, distribuita con licenza Apache-2.0; le differenze sono descritte in replay-theater/README.md.


Prerequisiti

  • Claude Code 2.1.287 o successivo — le mod sono attive di default da questa versione. Verifica con claude --version.
  • Terminale o tab Code dell'app Desktop — le sessioni WSL nell'app Desktop non eseguono le mod.

Una mod è codice eseguito con i tuoi permessi: può leggere e scrivere file, avviare processi e vedere prompt e tool call della sessione. Il sorgente di ogni mod è in hooks/, poche decine di righe: leggilo prima dell'installazione.


Installazione

  1. Aggiungi il marketplace a Claude Code:
   claude plugin marketplace add DarioFontanel/claude-code-mods
  1. Installa le mod che ti interessano, una per comando:
   claude plugin install cache-meter@dario-mods
   claude plugin install next-steps@dario-mods
   claude plugin install quick-buttons@dario-mods
   claude plugin install replay-theater@dario-mods

next-steps dichiara replay-theater come dipendenza: installandola, replay-theater viene installata automaticamente.

  1. Avvia una nuova sessione con claude.

Verifica: apri /plugin — sotto i tab compare la riga con le mod attive, ad esempio 4 mods active.

Gli stessi comandi sono disponibili dall'interno di una sessione come /plugin marketplace add e /plugin install. Per provare una mod in una sola sessione senza installarla, clona la repo e avvia claude --plugin-dir ./claude-code-mods/cache-meter.

Per disattivare una mod, disabilitala o disinstallala dal tab Installed di /plugin.


Comandi disponibili

  • /replay — apre il pannello di replay sull'ultimo turno che ha modificato file. Nel pannello: n passo successivo, p passo precedente, c o Esc chiusura.
  • /azioni — apre il pannello di quick-buttons. Su un terminale di almeno 144 colonne il pannello si apre da solo all'avvio della sessione. Ogni bottone ha come tasto rapido la prima lettera libera del nome del comando.
  • /azioni config — riapre la scelta dei bottoni. Nel pannello di scelta: scrivi nel campo Cerca per filtrare l'elenco, spostati con le frecce, Invio aggiunge o toglie un comando, s salva, n e p cambiano pagina. Puoi scegliere fino a 9 comandi.
  • ctrl+x poi Tab — sposta il focus sulla banda sopra il prompt. Da lì 1 e 2 inviano i passi proposti da next-steps, 3 apre il replay.

Personalizzazione

Bottoni di quick-buttons — si scelgono dal pannello, con /azioni config, senza modificare il codice. L'elenco propone skill, comandi personalizzati e comandi di altri plugin; i comandi integrati di Claude Code sono esclusi. Un comando scelto che una sessione non ha non viene mostrato in quella sessione.

Durata della cache in cache-meter — la costante TTL_MS in cache-meter/hooks/register.js vale un'ora, la durata della prompt cache negli abbonamenti Claude. Se la tua cache dura 5 minuti, imposta 5 * 60 * 1000.

Lingua di next-steps — la richiesta al modello è la costante ASK in next-steps/hooks/register.tsx. I prompt proposti seguono la lingua della conversazione.

Per modificare una mod, clona la repo e caricala con claude --plugin-dir: ogni salvataggio ricarica il modulo nella sessione aperta.


Struttura del progetto

claude-code-mods/
├── .claude-plugin/marketplace.json   # elenco delle mod installabili
├── cache-meter/
├── next-steps/
├── quick-buttons/
└── replay-theater/                   # Apache-2.0, con LICENSE propria

Ogni cartella è un plugin completo:

  • .claude-plugin/plugin.json — nome, versione e descrizione.
  • hooks/hooks.json — il modulo da caricare.
  • hooks/register.* — gli hook della mod.
  • tests/ — i test, eseguibili con claude plugin test ./<mod>.

claude plugin validate ./<mod> elenca gli eventi intercettati e le chiamate al motore di ciascuna mod.


Designed by Dario Fontanel, PhD

Aiuto PMI italiane ad integrare l'intelligenza artificiale per automatizzare i lavori ripetitivi, abbattere i costi e guadagnare tempo per crescere.

Sito YouTube Instagram LinkedIn TikTok AI Academy

Licenza: MIT — replay-theater è distribuita con licenza Apache-2.0.

Source 1 files
hooks/register.js 79 lines
1// Quanto dura la prompt cache dall'ultima richiesta che l'ha letta o scritta
2const TTL_MS = 60 * 60 * 1000
3// Ogni quanto la barra si ridisegna da sola
4const TICK_MS = 30 * 1000
5
6// L'istante dell'ultima richiesta della conversazione principale: da lì riparte l'ora
7let lastAt = null
8// L'ora letta all'ultimo tick o all'ultima richiesta
9let now = 0
10// Il timer che fa scorrere la barra, avviato alla prima richiesta
11let ticking = null
12
13// Verde finché c'è margine, rosso quando la cache sta per scadere
14function leftColor(minutes) {
15  if (minutes > 20) return 'green'
16  if (minutes > 5) return 'yellow'
17  return 'red'
18}
19
20export function register(on) {
21  // Una richiesta al modello rinnova la cache: l'ora riparte dal suo risultato
22  on('turn.step', async function* ($, e, next) {
23    const result = yield* next(e)
24    // Solo la conversazione principale: i subagent hanno una cache loro
25    if (!e.agentId && result.usage) {
26      lastAt = now = await $.clock.now()
27      ticking ??= $.clock.every(TICK_MS, async () => {
28        now = await $.clock.now()
29        $.ui.invalidate('ui.render')
30      })
31      $.ui.invalidate('ui.render')
32    }
33    return result
34  })
35
36  on('ui.render', { component: 'AbovePrompt' }, async ($, e, next) => {
37    // Quello che disegnano le altre mod nella banda resta sotto la nostra riga
38    const theirs = await next(e)
39    const { Box, Text } = $.ui.resolve(e)
40    const dim = (text) => Text({ dimColor: true, children: [text] })
41    const withTheirs = (line) => (theirs ? Box({ flexDirection: 'column', children: [line, theirs] }) : line)
42
43    if (lastAt === null) return withTheirs(dim('cache · in attesa della prima richiesta'))
44
45    const width = e.props.bodyColumns >= 110 ? 24 : 12
46    const leftMs = Math.max(0, TTL_MS - (now - lastAt))
47
48    if (leftMs === 0) {
49      return withTheirs(
50        Box({
51          flexDirection: 'row',
52          children: [
53            dim('cache  ' + '░'.repeat(width) + '  '),
54            Text({ color: 'red', children: ['scaduta'] }),
55            dim(' · la prossima richiesta la riscrive'),
56          ],
57        }),
58      )
59    }
60
61    // La parte piena è il tempo che resta: la barra si svuota da destra
62    const minutes = Math.ceil(leftMs / 60000)
63    const full = Math.ceil((leftMs / TTL_MS) * width)
64    const color = leftColor(minutes)
65    return withTheirs(
66      Box({
67        flexDirection: 'row',
68        children: [
69          dim('cache  '),
70          Text({ color, children: ['█'.repeat(full)] }),
71          dim('░'.repeat(width - full) + '  '),
72          Text({ color, children: [minutes + ' min rimasti'] }),
73          dim(' · ' + (60 - minutes) + ' min dall\'ultima richiesta'),
74        ],
75      }),
76    )
77  })
78}
79