Skip to main content
Un mod può disegnare la propria interfaccia in Claude Code e modificare parti dell’interfaccia che Claude Code già disegna. Ogni posizione in cui un mod può disegnare è chiamata punto di rendering, ad esempio un riquadro, la fascia sopra il prompt o lo spinner. Claude Code attiva l’evento ui.render ogni volta che sta per disegnare un punto di rendering, e il tuo hook per quell’evento restituisce cosa disegnare lì. Questa mappa mostra dove un mod può disegnare in una sessione del terminale: Mappa di una sessione del terminale di Claude Code con il rendering a schermo intero. Un mod può aggiungere un riquadro come barra laterale a destra, un toast in alto a destra della trascrizione, una riga di log nella trascrizione, una fascia sopra il prompt e una riga di stato sotto il prompt. Un mod può ridisegnare i messaggi, le righe delle chiamate agli strumenti e lo spinner. Il prompt appartiene a Claude Code. Mappa di una sessione del terminale di Claude Code con il rendering a schermo intero. Un mod può aggiungere un riquadro come barra laterale a destra, un toast in alto a destra della trascrizione, una riga di log nella trascrizione, una fascia sopra il prompt e una riga di stato sotto il prompt. Un mod può ridisegnare i messaggi, le righe delle chiamate agli strumenti e lo spinner. Il prompt appartiene a Claude Code. In un terminale più stretto, il riquadro si trova sopra il prompt anziché accanto alla trascrizione. Crea il tuo primo mod prima di iniziare da qui. Comincia con l’esempio pratico, che crea un riquadro con due schede e un contatore, poi leggi la sezione relativa a ciascun elemento che vuoi modificare.
Per consultare una singola prop o un limite, vedi il riferimento.

Crea un pannello con schede

In questa sezione crei un mod che aggiunge un comando /hello-tabs, e il comando apre un pannello. Un pannello è una barra laterale accanto alla trascrizione in un terminale ampio a schermo intero, oppure un’area incorniciata sopra il prompt negli altri casi. Questo pannello mostra due schede, e la seconda scheda ha un pulsante che aggiunge uno a un contatore. Il conteggio è ancora lì dopo che riavvii Claude Code. Il mod finito ha questo aspetto. La registrazione apre il pannello, passa alla seconda scheda, preme il pulsante alcune volte e torna alla prima scheda:
Le schede sono due pulsanti in fila. Il mod tiene traccia di quale sia attiva e disegna il contenuto di quella scheda sotto la fila.
1

Crea il plugin

Un mod è un plugin con un manifest, un hooks.json che punta al tuo codice, e il file di codice. Crea un mod spiega ciascuno di essi. Crea una directory chiamata hello-tabs con le directory .claude-plugin e hooks al suo interno, poi salva i primi due file.Salva il manifest come hello-tabs/.claude-plugin/plugin.json:
hello-tabs/.claude-plugin/plugin.json
Indica il tuo punto di ingresso in hello-tabs/hooks/hooks.json:
hello-tabs/hooks/hooks.json
2

Scrivi il codice

Questo elenco indica cosa fa ciascun hook, nell’ordine in cui compaiono nel codice:
  • Aggiunge il comando /hello-tabs e carica il conteggio salvato da una sessione precedente
  • Apre il pannello quando esegui quel comando
  • Disegna il contenuto del pannello: la fila di schede e il corpo della scheda aperta
Due variabili a livello di modulo, tab e count, contengono lo stato del pannello.Salva questo come hello-tabs/hooks/register.js:
hello-tabs/hooks/register.js
Ogni hook fa anche qualcosa che il codice non rende esplicito:
  • session.start legge anche il conteggio salvato da $.store, un archivio chiave-valore che persiste tra le sessioni.
  • command.run comunica soltanto a Claude Code che il pannello esiste. Aprire un pannello di per sé non disegna nulla: Claude Code attiva poi ui.render per chiedere cosa inserirvi.
  • ui.render restituisce l’albero degli elementi, un Box che contiene altri box, testo e pulsanti, e lo ricostruisce a partire da tab e count ogni volta che viene eseguito.
Premere un pulsante esegue la sua callback onPress, che modifica una variabile e chiama redraw. Claude Code esegue quindi di nuovo l’hook ui.render, e l’hook costruisce un nuovo albero a partire dai nuovi valori. Ogni disegno interattivo usa questo ciclo di rendering: una callback modifica lo stato, e l’hook esegue di nuovo il rendering a partire dal nuovo stato.
3

Apri il pannello

Nella tua shell, avvia Claude Code con claude --plugin-dir ./hello-tabs. Nel prompt di Claude Code, esegui /hello-tabs. Si apre un pannello con 1: One e 2: Two nella parte superiore. Premi 2, poi premi a, il tasto di scelta rapida per Add one, alcune volte. Il conteggio sale.
4

Verifica che il conteggio sia stato salvato

Premi Esc per chiudere il pannello, poi esci dalla sessione. Nella tua shell, avvia di nuovo Claude Code con lo stesso comando claude --plugin-dir ./hello-tabs, e nel prompt di Claude Code esegui /hello-tabs. Il conteggio è dove l’avevi lasciato.Per azzerare il conteggio, fai chiamare al mod $.store.delete('count'). Mantieni lo stato spiega quanto dura ciascun tipo di valore.

Scegli dove disegnare

Un hook ui.render viene eseguito per ogni punto di rendering, a meno che tu non lo limiti a quello in cui vuoi disegnare. Per scegliere il punto di rendering, passa un filtro, chiamato matcher, come secondo argomento di on. { component: 'Pane' } esegue l’hook solo per i pannelli. Nell’hook, e.component indica il punto, e.surface indica quale app sta disegnando e e.props contiene i dati propri del punto. Per un pannello, e.requestId è l’id con cui lo hai aperto. Il pannello e la banda sono vuoti finché un mod non li riempie. Seleziona una scheda per vedere cos’è ciascuno e come disegnarci:
Un pannello è una barra laterale accanto alla trascrizione in un terminale a schermo intero ampio, oppure, negli altri casi, un’area incorniciata sopra il prompt. Con più pannelli aperti, ognuno ha una scheda che ne mostra il titolo.Un pannello compare quando il tuo mod chiama $.ui.open con un id a tua scelta, come in $.ui.open({ id: 'hello-tabs' }). Apri un pannello al momento giusto descrive gli altri campi e quando un pannello attende un terminale più ampio.Per disegnare nel tuo pannello, filtra su { component: 'Pane' } e verifica che e.requestId sia il tuo id.

Modifica ciò che Claude Code già disegna

Claude Code disegna da sé la maggior parte della propria interfaccia: messaggi, righe delle chiamate agli strumenti, lo spinner e altro. Ognuna di queste parti è anch’essa un punto di rendering, quindi un mod può cambiarne lo stile o sostituirla. Per modificarne una, filtra il tuo hook ui.render sul suo nome preso da questa tabella: Pane, AskUserQuestion, Spinner, UserMessage, AssistantMessage e i punti delle chiamate agli strumenti funzionano nel terminale, nell’app Desktop e nell’estensione VS Code. La tabella dei punti di rendering indica dove viene generato ciascuno degli altri. In un punto che Claude Code già disegna, il tuo hook può modificare un dettaglio, sostituire il disegno o lasciarlo com’è. Seleziona una scheda per vedere ciascuna opzione applicata allo spinner. Gli esempi leggono una variabile calls che un altro hook incrementa, come nel mod del tutorial.
Per mantenere il disegno di Claude Code e modificarne una parte, passa a next una copia dell’evento con props modificate. Questo hook modifica il testo dopo la parola dello spinner:
Lo spinner mantiene la sua animazione e la sua parola, e il tuo testo segue la parola:
In questi punti, next(e) restituisce un riferimento al disegno di Claude Code, { type: 'engine', ref }, a meno che un mod eseguito dopo il tuo non abbia restituito un proprio albero. Per modificare il contenuto di quel disegno, passa a next una copia dell’evento con prop diverse, come fa la scheda Modifica un dettaglio. Puoi restituire il riferimento così com’è, oppure inserirlo in un Box accanto a elementi tuoi:
Mentre Claude lavora, lo spinner si anima come prima e under the spinner compare sotto di esso. La richiesta di permesso non è un punto di rendering, quindi un mod non può modificare ciò che mostra. La finestra di dialogo delle domande, AskUserQuestion, lo è, quindi un mod può modificarla. Un albero per la finestra di dialogo deve contenere il riferimento esattamente una volta, con i tuoi elementi sopra di esso. In caso contrario, Claude Code disegna la propria finestra di dialogo.

Apri un pannello al momento giusto

Un pannello compare solo quando il tuo mod lo apre. Come e quando lo apri determina se riceve il focus della tastiera, quanto spazio richiede e se viene mostrato o meno in un terminale stretto. Per aprire un pannello, chiama $.ui.open con un id a tua scelta. L’id è il nome del pannello: il tuo hook ui.render lo verifica, e lo passi di nuovo per chiudere il pannello.
Per chiudere il pannello, chiama $.ui.close con l’id con cui lo hai aperto:
Oltre a id, $.ui.open accetta questi campi facoltativi: L’estensione VS Code ignora rows e columns e dimensiona il pannello da sé. focus, closeOnEscape e holdToasts sono facoltativi e accettano solo true. Per non usarne uno, omettilo. Passare false genera un errore come ui.open: focus is true or left out. Per impostarne uno in modo condizionale, aggiungi il campo solo quando la condizione è soddisfatta. Questa chiamata richiede il focus della tastiera solo quando items non è vuoto:
Per consentire a un comando di aprire il pannello mentre Claude sta lavorando, aggiungi immediate: true quando registri il comando. Senza di esso, un comando digitato durante un turno attende la fine del turno.

Trattieni i toast dietro una finestra di dialogo

Passa holdToasts: true a $.ui.open quando il pannello è una finestra di dialogo a cui l’utente risponde e che poi lascia, così i toast non compaiono mentre decide. Nel terminale, la trattenuta dura finché è quel pannello a essere mostrato, e un toast generato in quel lasso di tempo attende la fine della trattenuta. Claude Code trattiene i toast degli altri mod e le proprie notifiche di breve durata, oltre a quelli che il tuo mod genera con $.ui.toast. Ometti il campo in un pannello che resta aperto, così l’utente continua a vederli.

Quando un pannello attende un terminale più ampio

Un pannello che il tuo mod apre senza che gli sia stato chiesto non compare in un terminale stretto, così non può occupare uno schermo piccolo. Se compare o meno dipende da cosa lo ha aperto:
  • Aperto da un’azione dell’utente, come un comando eseguito o un pulsante premuto, il pannello compare a qualsiasi larghezza
  • Aperto dal tuo mod di propria iniziativa, ad esempio da un timer o da un hook turn.start, il pannello compare solo in un terminale largo almeno 144 colonne. Dopo che l’utente ha aperto quel pannello almeno una volta di persona, bastano 110 colonne.
Quando il pannello compare, $.ui.open si risolve in { isPlaced: true }. Quando il pannello è in attesa, isPlaced è false e reason è una stringa che ne spiega il motivo. Un pannello in attesa compare quando l’utente lo apre o allarga il terminale. Per segnalare che qualcosa è disponibile senza aprire un pannello, chiama $.ui.toast('Your message'), che mostra una notifica toast.

Disegna nell’estensione VS Code

Nell’estensione VS Code, ciò che un mod disegna compare nel pannello della chat con la versione dell’estensione 2.1.299 o successiva, in una sessione che recupera i feature flag. In un hook ui.render per il pannello della chat, e.surface è vscode. Per verificare quali punti ed elementi disegna il pannello della chat e quali prop ignora, consulta le tabelle dei punti di rendering e degli elementi. Per far funzionare un mod nel pannello della chat oltre che nel terminale, tieni conto di queste differenze:
  • Pannelli: in un pannello della chat largo 800 pixel o più, i pannelli si agganciano accanto alla conversazione, e.props.placement è 'dock' ed e.viewport.isFullscreen è true. In un pannello della chat più stretto, i pannelli vengono disegnati sopra la casella del prompt, placement è 'inline' e un pannello mostra 12 righe prima di scorrere.
  • Toast e righe di stato: si trovano in un’unica pila direttamente sopra la casella del prompt, insieme ai pannelli quando il pannello della chat è stretto, con una riga di stato per mod. La pila è nascosta mentre viene mostrata una richiesta di permesso o una finestra di dialogo.
  • Etichette: il pannello della chat incornicia ciò che un mod disegna o riscrive e lo etichetta con il nome del plugin, come in From the token-chart plugin o Edited by the token-chart plugin.
  • Tastiera: i pulsanti non hanno tasti di scelta rapida, quindi l’utente fa clic su un pulsante o preme Invio su di esso quando ha il focus.
  • Focus della tastiera: il pannello della chat accoglie la richiesta focus: true di un pannello solo quando il pannello della chat ha il focus, Claude è inattivo senza domande in attesa e la casella del prompt è vuota.
  • La finestra di dialogo delle domande: in AskUserQuestion, il pannello della chat mantiene la propria scheda della domanda e disegna i tuoi elementi sopra di essa. Le prop che passi a next non modificano la scheda.
  • Suggerimenti per il prompt: $.prompt.suggest si risolve con isShown: false e non mostra nulla, perché il pannello della chat riserva il testo di suggerimento attenuato della casella del prompt ai suggerimenti di Claude.
  • Limiti del testo: il pannello della chat tronca una riga di stato a 200 caratteri o due righe, e un toast a 500 caratteri.

Creare un albero a partire dagli elementi

Ciò che un hook ui.render restituisce è un albero di elementi: una descrizione di cosa disegnare, composta da box, testo e controlli annidati l’uno nell’altro. Tu descrivi il disegno e Claude Code lo renderizza in qualunque app l’utente abbia aperta: il terminale, l’app Desktop o l’estensione VS Code. Per ottenere gli elementi, chiama $.ui.resolve(e) nel tuo hook, come in const { Box, Text, Button } = $.ui.resolve(e). Ogni elemento è una funzione. Le passi delle prop e inserisci in children gli elementi e le stringhe che vanno al suo interno. Seleziona una scheda per vedere ciascuno degli elementi più comuni e come il terminale lo disegna:
Text disegna una stringa, con uno stile facoltativo come bold e color:
La galleria dell’interfaccia contiene esempi e screenshot della maggior parte degli elementi. Questa tabella elenca tutti gli elementi: Se il tuo modulo è un file .tsx o .jsx, puoi scrivere l’albero in JSX. Prima destruttura gli elementi da $.ui.resolve(e). Se un albero usa un elemento che l’app non ha, una prop che un elemento non accetta o un figlio dove non è previsto, Claude Code disegna la propria versione di quel punto. In una sessione avviata con --plugin-dir, una riga della trascrizione lo segnala, ad esempio ui.render (Pane) refused: Text prop "bogusProp" is not allowed; the engine drew its own. Il log di debug lo registra come ui.render (Pane): a hook returned a tree that does not validate con lo stesso motivo. Nient’altro compare nella sessione, quindi quando un disegno non viene visualizzato, controlla quella riga o il log. Nell’app Desktop e nell’estensione VS Code, un Link viene disegnato come testo semplice a meno che il suo href non soddisfi questi requisiti:
  • Schema e host: un URL https: o un URL http://localhost come http://localhost:3000
  • Nessuna @: scrivi una @ nel percorso o nella query come %40
  • Grafia: ciò che restituisce new URL(href).href, a parte una / mancante dopo l’host. Questo esclude un host in maiuscolo, uno spazio e :443 in un URL https:.
Nel terminale, questi requisiti non si applicano.

Quando un Client non riesce

Nel terminale, quando il file eseguito da un Client non riesce, una riga attenuata come my-mod: Client client/spinner.js: boom prende il posto del Client, e il resto del tuo disegno continua a essere visualizzato. Se il tuo mod gestisce ui.fault, Claude Code quindi disegna di nuovo quel punto.

Disegnare una griglia di celle colorate

Per una mappa di calore, una sparkline o un tabellone di gioco nel terminale, disegna un unico Raster e non un Box per ogni cella. Un Raster accetta una key, le sue dimensioni in columns e rows, e cells, una stringa base64 che racchiude tutte le celle. Ogni cella è composta da tre numeri: il code point del carattere, il suo colore e il suo colore di sfondo. Un colore è un valore RGB a 24 bit in esadecimale, come 0xc62828 per un rosso. Il valore 0x01000000, uno sopra quell’intervallo, indica il colore predefinito del terminale. Le app diverse dal terminale non hanno Raster, quindi controlla e.surface e lì disegna del testo. Questo corpo del pannello disegna una mappa di calore tre per due:
Nel terminale, il pannello mostra la griglia: Un pannello nel terminale che contiene una piccola griglia di blocchi colorati, due righe da tre. La riga superiore è verde, ambra e rossa. La riga inferiore è verde, verde e ambra. L’array rows è la parte da modificare, e cellsOf lo trasforma nella stringa compatta. L’hook disegna solo in un pannello il cui id è heat, quindi aprine uno con $.ui.open({ id: 'heat' }) da un comando, come l’esempio hello-tabs apre il suo pannello. Ogni carattere deve essere largo una cella. Per animare un Raster già presente sullo schermo, chiama $.ui.blit con l’id del pannello come requestId, la key del Raster, le stesse dimensioni e le nuove celle. Per questo esempio, è $.ui.blit({ requestId: 'heat', key: 'grid', columns: 3, rows: 2, cells: cellsOf(newRows) }). Ridisegna solo quell’elemento senza eseguire di nuovo il tuo hook ui.render.

Rispondere a pressioni e digitazione

Quando l’utente preme un pulsante, digita in un campo o sceglie da un elenco disegnato dal tuo mod, Claude Code chiama la callback di quel controllo, che viene eseguita nel tuo modulo. Ogni controllo accetta le proprie callback:
  • Button: accetta onPress(e), dove e.surface è l’app da cui proviene la pressione
  • Input: accetta onSubmit(value) e onInput(value)
  • Select: accetta onSelect(value) con le sue scelte in options, un elenco di almeno una scelta con valori univoci, come [{ value: 'sm', label: 'Small' }, { value: 'lg', label: 'Large' }]
Un test preme o digita in un controllo tramite la sua key, quindi assegnane una a ciascun controllo. Ogni uso di un controllo attiva anche ui.press, ui.input o ui.select con la key in e.element, e un altro mod può gestire quegli eventi. Il suo hook viene eseguito prima della tua callback, quindi vede ciò che l’utente digita nel tuo Input e può modificarlo o rispondere al posto della tua callback. L’API dei mod non ha alcun metodo che prema il pulsante di un altro mod.

Focus della tastiera e tasti di scelta rapida

Il tuo mod non legge mai direttamente la tastiera. L’utente preme un tasto, Claude Code decide a quale dei tuoi controlli è destinato e viene eseguita la callback di quel controllo. A parte un tasto di scelta rapida numerico sulla banda, questo accade solo mentre il tuo pannello o la tua banda ha il focus della tastiera. Il resto del tempo, i tasti vanno al prompt. Nell’estensione VS Code, i pulsanti non hanno tasti di scelta rapida: l’utente fa clic su un pulsante o preme Invio su di esso, e digita nei campi.

Come un pannello ottiene il focus della tastiera

Un pannello ottiene il focus della tastiera quando:
  • Il tuo mod lo apre con focus: true da un comando o da una pressione
  • L’utente preme Ctrl+X e poi Tab
  • L’utente ci fa clic sopra
Claude Code concede focus: true solo mentre il prompt è vuoto e nient’altro ha il focus della tastiera. Un pannello che si apre mentre l’utente sta digitando non ne intercetta i tasti premuti.

Cosa fa ogni tasto

Questa tabella elenca cosa fa un tasto mentre il tuo pannello o la tua banda ha il focus della tastiera: Un mod non può associare Tab o i tasti freccia a nient’altro, quindi un gioco si controlla con w, a, s e d.

Impostare un tasto di scelta rapida e il focus iniziale

  • hotkey: per consentire all’utente di premere un Button con un solo tasto, assegnagli una hotkey composta da una cifra o da una lettera minuscola, come in hotkey: 'a'
  • autoFocus: per scegliere quale controllo ha il focus all’apertura del pannello, aggiungi autoFocus: true a quel controllo. Nell’estensione VS Code, autoFocus non ha alcun effetto: il controllo viene disegnato come se lo avessi omesso, e non devi modificare nulla. La prop accetta solo true, quindi omettila sugli altri controlli.
Il modo in cui viene mostrato un tasto di scelta rapida dipende dal pulsante e dall’app: Nel terminale, indica il tasto nell’etichetta di un pulsante con parentesi quadre, oppure usa plain: true, in modo che l’utente possa vedere cosa premere. Il riferimento degli elementi contiene le altre regole di Button: action, i tasti di scelta rapida numerici sulla banda e due pulsanti sullo stesso tasto di scelta rapida.

Ricevere input digitato e disegnare una riga per ogni elemento

Molti pannelli sono un campo di testo con un elenco sotto. L’esempio in questa sezione è un pannello di note: digiti una nota e premi Invio per aggiungerla, e ogni nota ha un pulsante x che la elimina. Con due note aggiunte, il terminale disegna il pannello in questo modo:
Il simbolo ✕ sul bordo superiore è il segno proprio di Claude Code per chiudere il pannello. L’esempio usa queste tecniche:
  • Ricevere input digitato: un Input chiama onSubmit(value) con il testo del campo quando l’utente preme Invio, e onInput(value) a ogni modifica
  • Disegnare un elenco: mappa i tuoi dati su una riga ciascuno e assegna al pulsante di ogni riga una propria key
Questo hook disegna il contenuto del pannello:
Per provare il pannello:
  • Aggiungi una nota: digita una riga e premi Invio. La riga appare come una nuova riga dell’elenco e il campo si svuota.
  • Elimina una nota: premi Tab finché il pulsante x della nota non ha il focus, poi premi Invio. La x è l’etichetta del pulsante e non un tasto di scelta rapida, quindi digitare la lettera non lo preme.
Ogni modifica segue lo stesso ciclo di rendering di hello-tabs: la callback modifica notes, chiama redraw e salva l’elenco in $.store. Il campo si svuota dopo ogni invio grazie alla sua prop value. value è il testo che il campo contiene quando viene disegnato, e ciò che l’utente digita lo sostituisce finché il tuo hook non disegna di nuovo il campo. L’esempio disegna sempre il campo con ''. L’esempio salva le note ma non le carica. Per ripristinarle nella sessione successiva, leggile in un hook session.start, nello stesso modo in cui hello-tabs legge count. Queste prop compongono la riga del campo, Note: Type a note and press Enter ⏎ add: L’invio di un Input non avvia un turno a meno che la tua callback non chiami $.prompt.submit.

Ridisegnare un sito

Un disegno è un’istantanea: mostra ciò che il tuo hook ui.render ha restituito l’ultima volta che l’hook è stato eseguito. Per mostrare qualcosa di nuovo, l’hook deve essere eseguito di nuovo. Claude Code lo riesegue per alcune modifiche, e il tuo mod lo richiede per le altre.

Quando Claude Code ridisegna senza che venga richiesto

Claude Code esegue di nuovo il tuo hook ui.render quando cambiano le prop del sito o quando cambia la larghezza del terminale. Quando un Client nel sito fallisce e il tuo mod gestisce ui.fault, Claude Code esegue l’hook ancora una volta dopo che i tuoi hook ui.fault hanno restituito il risultato, così il tuo hook ui.render può escludere il Client. Non esegue l’hook in base a un timer, e non può sapere quando cambia una variabile nel tuo modulo.

Ridisegnare quando i tuoi dati cambiano

Per far ridisegnare i tuoi siti dopo che i tuoi dati sono cambiati, chiama $.ui.invalidate('ui.render'). Questo pannello conta le pressioni. La callback del pulsante modifica count, poi richiede un nuovo disegno:
Ogni pressione incrementa il numero nel pannello. L’esempio hello-tabs racchiude la stessa chiamata nella sua funzione redraw. Un valore che conservi in $.state non ha bisogno della chiamata, perché scrivere il valore ridisegna i siti che lo leggono.

Ridisegnare in base a un timer

Per mantenere aggiornati un orologio, un conto alla rovescia o un valore esterno alla sessione, ridisegna secondo una pianificazione. Avvia un timer nell’hook session.start del modulo. Se il modulo ne ha già uno, come nel caso di hello-tabs, aggiungi a esso la riga $.clock.every:
Ora Claude Code esegue il tuo hook ui.render una volta al secondo. Il timer si arresta quando il modulo viene ricaricato, e la nuova istanza del modulo avvia il proprio.

Con quale frequenza un sito può essere ridisegnato

Claude Code limita la frequenza dei ridisegni di un sito, quindi il tuo mod può chiamare $.ui.invalidate tutte le volte che i suoi dati cambiano. Per sapere con quale frequenza ciascun sito può essere ridisegnato, consulta la tabella dei limiti. Le chiamate che arrivano più velocemente del limite vengono accorpate in un unico ridisegno. Quel ridisegno esegue il tuo hook una sola volta, e l’hook legge i tuoi dati così come sono in quel momento, quindi viene mostrato il valore più recente e non quelli intermedi. Un’animazione non può essere eseguita più velocemente del limite.

Mantenere lo stato

Il punto in cui un mod conserva un valore determina quanto a lungo il valore dura: fino al ricaricamento del modulo, fino alla fine della sessione, oppure da una sessione all’altra. Scegli in base a quanto a lungo il valore deve durare: $.store.get(key) si risolve nel valore o in undefined, e $.store.set(key, value) accetta qualsiasi valore JSON.

Conservare un valore in $.state

$.state conserva i valori per la durata di una sessione e ridisegna al posto tuo. È uno stato reattivo: un hook ui.render che legge un valore si sottoscrive a esso, quindi Claude Code ridisegna quel punto ogni volta che scrivi il valore, e non devi chiamare $.ui.invalidate. Un valore in $.state sopravvive inoltre a un ricaricamento del modulo, cosa che una variabile non fa. Per configurarlo, dichiara i tuoi valori, fai puntare il manifest alla dichiarazione, poi definisci e usa ciascun valore. Gli esempi spostano il count di hello-tabs in $.state.

Dichiarare i valori

Dichiara i valori in un file di dichiarazione dei tipi. La chiave esterna è il nome del tuo plugin, e ogni voce sotto di essa è un valore con il suo tipo. Salva questo come hello-tabs/types/index.d.ts:
hello-tabs/types/index.d.ts

Far puntare il manifest alla dichiarazione

Per consentire a claude plugin validate di verificare il tuo codice rispetto a quel file, aggiungi al manifest un campo types con il suo percorso:
hello-tabs/.claude-plugin/plugin.json

Definire, leggere e scrivere un valore

Nel tuo modulo, definisci ciascun valore con un valore predefinito, leggilo durante il disegno e scrivilo da una callback. atom assegna un nome a un valore e al suo valore predefinito, read lo restituisce e update lo scrive. I tre helper chiamano $.state.get e $.state.set al posto tuo:
Poiché l’hook ui.render ha letto count, Claude Code esegue di nuovo l’hook ogni volta che il pulsante lo scrive. Al codice si applicano queste regole:
  • Scrivi plugin e key come stringhe letterali: claude plugin validate li legge dal tuo codice sorgente
  • Conserva il risultato di ogni chiamata ad atom in una const: se dichiari count con let, la validazione fallisce con takes a source the scan can read
  • Dichiara ogni valore nel file di dichiarazione dei tipi: altrimenti la validazione fallisce con hello-tabs.count is not declared
  • Scrivi da una callback o dall’hook di un altro evento: un hook ui.render può leggere lo stato ma non può scriverlo, quindi scrivi da onPress, onSubmit o da un hook per un altro evento

Modificare hello-tabs per usare $.state

Per spostare count di hello-tabs in $.state, modifica ogni riga che lo usa:
  • In cima al modulo: aggiungi la riga import e sostituisci let count = 0 con la riga atom
  • Nell’hook ui.render: aggiungi la riga read prima di tabButton e disegna 'Count: ' + n nel Text
  • Nel pulsante Add one: sostituisci onPress con quello in Salvare da più di una sessione, che salva il conteggio oltre a scriverlo
  • Nell’hook session.start: sostituisci le due righe che leggono saved con la chiamata a loadCount da Caricare di nuovo un valore salvato dopo /clear
Mantieni redraw per i pulsanti delle schede, perché tab è ancora una variabile.

Caricare di nuovo un valore salvato dopo /clear

Se il tuo mod copia un valore salvato da $.store in $.state a session.start, deve copiarlo di nuovo dopo /clear, /resume o /branch. Questi comandi reimpostano ogni valore di $.state al suo valore predefinito, e session.start non viene attivato di nuovo. classic.SessionStart invece viene attivato dopo ciascuno di essi, con e.source impostato su clear, resume o fork, quindi copia di nuovo il valore in un hook su di esso. Altrimenti il tuo disegno mostra il valore predefinito, e una callback che salva il valore di $.state scrive il valore predefinito sopra quello che avevi memorizzato. Questo codice carica count da entrambi gli hook. Si basa sulla versione di hello-tabs con $.state, in cui count è un atom e update è importato. Metti loadCount sopra register e aggiungi la chiamata a loadCount all’hook session.start che hai già. classic.SessionStart viene attivato anche all’avvio e dopo la compattazione, che non reimposta $.state, quindi il filtro su source limita l’hook ai tre reset:
Con entrambi gli hook in posizione, il riquadro mostra il conteggio salvato dopo /clear e non 0, e la successiva pressione di Add one si aggiunge al conteggio salvato. loadCount scrive il valore memorizzato sopra quello in $.state, e session.start viene attivato di nuovo ogni volta che il modulo si ricarica. Per evitare che lo store rimanga indietro, salva a ogni modifica, come fa il pulsante Add one. Per verificare il ricaricamento senza una sessione, testa il disegno dopo /clear.

Salvare da più di una sessione

Ogni sessione sulla tua macchina che esegue il tuo mod condivide un unico $.store. Un get seguito da un set non è atomico. Quando due sessioni leggono ciascuna un valore, lo modificano e lo riscrivono, entrano in competizione, e la seconda scrittura sostituisce la prima. Per renderlo meno probabile:
  • Assegna a ogni elemento la propria chiave: un set modifica solo la propria chiave, quindi le sessioni che scrivono chiavi diverse non si sovrascrivono a vicenda
  • Rileggi subito prima di scrivere: per un valore che più sessioni modificano, esegui get sulla chiave nella callback e costruisci il nuovo valore a partire da quello, non da una copia caricata a session.start. La scrittura di un’altra sessione va comunque persa se avviene tra il tuo get e il tuo set.
Questo pulsante aggiunge uno a qualunque valore lo store contenga in quel momento, poi aggiorna il disegno:
Se una seconda sessione ha premuto il proprio pulsante tre volte dall’avvio di questa sessione, questa pressione mostra e salva un conteggio che include quelle tre.

Passaggi successivi