Skip to main content
Ein Mod kann seine eigene Benutzeroberfläche in Claude Code zeichnen und Teile der Benutzeroberfläche ändern, die Claude Code bereits zeichnet. Jeder Ort, an dem ein Mod zeichnen kann, wird als Render-Site bezeichnet, z. B. ein Pane, das Band über der Eingabeaufforderung oder der Spinner. Claude Code löst das ui.render Ereignis jedes Mal aus, wenn es eine Render-Site zeichnen möchte, und Ihr Hook für dieses Ereignis gibt zurück, was dort gezeichnet werden soll. Diese Karte zeigt, wo ein Mod in einer Terminal-Sitzung zeichnen kann: Karte einer Claude Code Terminal-Sitzung. Ein Mod kann ein Pane als Seitenleiste auf der rechten Seite hinzufügen, einen Toast oben rechts im Transkript, eine Protokollzeile im Transkript, ein Band über der Eingabeaufforderung und eine Statuszeile unter der Eingabeaufforderung. Ein Mod kann Nachrichten, Tool-Call-Zeilen und den Spinner neu zeichnen. Die Eingabeaufforderung ist Claude Codes eigene. Karte einer Claude Code Terminal-Sitzung. Ein Mod kann ein Pane als Seitenleiste auf der rechten Seite hinzufügen, einen Toast oben rechts im Transkript, eine Protokollzeile im Transkript, ein Band über der Eingabeaufforderung und eine Statuszeile unter der Eingabeaufforderung. Ein Mod kann Nachrichten, Tool-Call-Zeilen und den Spinner neu zeichnen. Die Eingabeaufforderung ist Claude Codes eigene. In einem schmaleren Terminal sitzt das Pane über der Eingabeaufforderung statt neben dem Transkript. Erstellen Sie Ihren ersten Mod, bevor Sie hier beginnen. Beginnen Sie mit dem durchgearbeiteten Beispiel, das ein Pane mit zwei Registerkarten und einem Zähler erstellt, lesen Sie dann den Abschnitt für jeden Teil, den Sie ändern möchten.
Um eine Eigenschaft oder ein Limit nachzuschlagen, siehe die Referenz.

Erstellen Sie ein Pane mit Registerkarten

In diesem Abschnitt erstellen Sie einen Mod, der einen /hello-tabs Befehl hinzufügt, und der Befehl öffnet ein Pane. Ein Pane ist eine Seitenleiste neben dem Transkript in einem breiten Vollbildterminal oder eine gerahmte Region über der Eingabeaufforderung. Dieses Pane zeigt zwei Registerkarten, und die zweite Registerkarte hat eine Schaltfläche, die eins zu einem Zähler addiert. Die Anzahl ist immer noch da, nachdem Sie Claude Code neu starten. Der fertige Mod sieht so aus. Die Aufzeichnung öffnet das Pane, wechselt zur zweiten Registerkarte, drückt die Schaltfläche ein paar Mal und kehrt zur ersten Registerkarte zurück:
Claude Code hat kein integriertes Registerkarten-Element, daher sind die Registerkarten zwei Schaltflächen in einer Reihe. Der Mod verfolgt, welche aktiv ist, und zeichnet den Inhalt dieser Registerkarte unter der Reihe.
1

Erstellen Sie das Plugin

Ein Mod ist ein Plugin mit einem Manifest, einer hooks.json, die auf Ihren Code verweist, und der Codedatei. Erstellen Sie einen Mod erklärt jeden. Erstellen Sie ein Verzeichnis namens hello-tabs mit .claude-plugin und hooks Verzeichnissen darin, speichern Sie dann die ersten zwei Dateien.Speichern Sie das Manifest als hello-tabs/.claude-plugin/plugin.json:
hello-tabs/.claude-plugin/plugin.json
Benennen Sie Ihren Einstiegspunkt in hello-tabs/hooks/hooks.json:
hello-tabs/hooks/hooks.json
2

Schreiben Sie den Code

Der Code führt drei Aufgaben aus, eine in jedem Hook:
  • Fügt den /hello-tabs Befehl hinzu
  • Öffnet das Pane, wenn Sie diesen Befehl ausführen
  • Zeichnet den Inhalt des Pane: die Reihe von Registerkarten und den Hauptteil der offenen Registerkarte
Zwei Variablen auf Modulebene, tab und count, halten den Status des Pane.Speichern Sie dies als hello-tabs/hooks/register.js:
hello-tabs/hooks/register.js
Jeder Hook führt auch etwas aus, das der Code nicht deutlich macht:
  • session.start liest auch die gespeicherte Anzahl aus $.store, einem Schlüssel-Wert-Speicher, der zwischen Sitzungen bestehen bleibt.
  • command.run teilt Claude Code nur mit, dass das Pane existiert. Das Öffnen eines Pane zeichnet nichts von selbst: Claude Code löst dann ui.render aus, um zu fragen, was darin geht.
  • ui.render gibt den Element-Baum zurück, ein Box, das andere Boxen, Text und Schaltflächen enthält, und erstellt ihn jedes Mal aus tab und count neu.
Das Drücken einer Schaltfläche führt ihren onPress Callback aus, der eine Variable ändert und redraw aufruft. Claude Code führt dann den ui.render Hook erneut aus, und der Hook erstellt einen neuen Baum aus den neuen Werten. Jede interaktive Zeichnung verwendet diesen Render-Zyklus: Ein Callback ändert den Status, und der Hook zeichnet aus dem neuen Status neu.
3

Öffnen Sie das Pane

Starten Sie Claude Code in Ihrer Shell mit claude --plugin-dir ./hello-tabs. Führen Sie an der Claude Code Eingabeaufforderung /hello-tabs aus. Ein Pane öffnet sich mit 1: One und 2: Two oben. Drücken Sie 2, dann drücken Sie a, die Hotkey für Add one, ein paar Mal. Die Anzahl steigt.
4

Überprüfen Sie, dass die Anzahl gespeichert wurde

Drücken Sie Esc, um das Pane zu schließen, und beenden Sie dann die Sitzung. Starten Sie Claude Code in Ihrer Shell erneut mit dem gleichen claude --plugin-dir ./hello-tabs Befehl, und führen Sie an der Claude Code Eingabeaufforderung /hello-tabs aus. Die Anzahl ist dort, wo Sie sie gelassen haben.Um die Anzahl zu löschen, lassen Sie den Mod $.store.delete('count') aufrufen. Behalten Sie den Status behandelt, wie lange jede Art von Wert dauert.

Wählen Sie, wo Sie zeichnen möchten

Ein ui.render Hook läuft für jede Render-Site, es sei denn, Sie grenzen ihn auf die gewünschte ein. Um die Render-Site auszuwählen, übergeben Sie einen Filter, genannt Matcher, als zweites Argument an on. { component: 'Pane' } führt den Hook nur für Panes aus. Im Hook benennt e.component die Site, e.surface sagt, welche App zeichnet, und e.props enthält die eigenen Daten der Site. Für ein Pane ist e.requestId die id, mit der Sie es geöffnet haben. Zwei Sites sind leer, bis ein Mod sie ausfüllt, das Pane und das Band. Wählen Sie eine Registerkarte, um zu sehen, was jede ist und wie man darin zeichnet:
Ein Pane ist eine Seitenleiste neben dem Transkript in einem breiten Vollbildterminal oder eine gerahmte Region über der Eingabeaufforderung. Mit mehreren offenen Panes erhält jedes eine Registerkarte, die seinen Titel anzeigt.Ein Pane erscheint, wenn Ihr Mod $.ui.open mit einer id aufruft, die Sie wählen, wie in $.ui.open({ id: 'hello-tabs' }). Öffnen Sie ein Pane zum richtigen Zeitpunkt behandelt die anderen Felder und wann ein Pane auf ein breiteres Terminal wartet.Um in Ihrem Pane zu zeichnen, filtern Sie auf { component: 'Pane' } und überprüfen Sie, dass e.requestId Ihre id ist.

Ändern Sie, was Claude Code bereits zeichnet

Claude Code zeichnet den Großteil seiner Benutzeroberfläche selbst: Nachrichten, Tool-Call-Zeilen, den Spinner und mehr. Jeder dieser Teile ist auch eine Render-Site, daher kann ein Mod ihn umgestalten oder ersetzen. Um einen zu ändern, filtern Sie Ihren ui.render Hook auf seinen Namen aus dieser Tabelle: An einer Site, die Claude Code bereits zeichnet, hat Ihr Hook drei Möglichkeiten: ein Detail ändern, die Zeichnung ersetzen oder sie allein lassen. Wählen Sie eine Registerkarte, um jede auf den Spinner angewendet zu sehen. Die Beispiele lesen eine calls Variable, die ein anderer Hook zählt, wie im Tutorial-Mod.
Um Claude Codes Zeichnung zu behalten und einen Teil davon zu ändern, übergeben Sie next eine Kopie des Ereignisses mit geänderten props. Dieser Hook ändert den Text nach dem Wort des Spinners:
Der Spinner behält seine Animation und sein Wort, und Ihr Text folgt dem Wort:
Die Berechtigungsaufforderung ist keine Render-Site, daher kann ein Mod nicht ändern, was sie zeigt. Der Frage-Dialog, AskUserQuestion, ist einer, daher kann ein Mod diesen ändern. Das Terminal und die Desktop-App lösen nicht alle gleichen Sites aus. Pane, AbovePrompt, Spinner und die Transkript-Sites funktionieren in beiden. Ein paar andere Statuszeilen werden nur im Terminal ausgelöst. Die Render-Sites-Tabelle listet auf, wo jede ausgelöst wird.

Öffnen Sie ein Pane zum richtigen Zeitpunkt

Ein Pane erscheint nur, wenn Ihr Mod es öffnet. Wie und wann Sie es öffnen, entscheidet, ob es den Tastaturfokus erhält, wie viel Platz es anfordert und ob es überhaupt in einem schmalen Terminal angezeigt wird. Um ein Pane zu öffnen, rufen Sie $.ui.open mit einer id auf, die Sie wählen. Die id ist der Name des Pane: Ihr ui.render Hook überprüft sie, und Sie übergeben sie erneut, um das Pane zu schließen.
Um das Pane zu schließen, rufen Sie $.ui.close mit der id auf, mit der Sie es geöffnet haben:
Neben id nimmt $.ui.open diese optionalen Felder: Um einem Befehl zu ermöglichen, das Pane zu öffnen, während Claude arbeitet, fügen Sie immediate: true hinzu, wenn Sie den Befehl registrieren. Ohne ihn wartet ein Befehl, der während eines Turns eingegeben wird, bis der Turn endet.

Wenn ein Pane auf ein breiteres Terminal wartet

Ein Pane, das Ihr Mod öffnet, ohne gefragt zu werden, erscheint nicht in einem schmalen Terminal, daher kann es einen kleinen Bildschirm nicht übernehmen. Ob es erscheint, hängt davon ab, was es geöffnet hat:
  • Geöffnet durch etwas, das der Benutzer getan hat, z. B. ein Befehl, den er ausgeführt hat, oder eine Schaltfläche, die er gedrückt hat, das Pane erscheint bei jeder Breite
  • Geöffnet durch Ihren Mod, der von selbst handelt, z. B. von einem Timer oder einem turn.start Hook, das Pane erscheint nur in einem Terminal mit mindestens 144 Spalten Breite. Nachdem der Benutzer dieses Pane einmal selbst geöffnet hat, reichen 110 Spalten aus.
Wenn das Pane erscheint, wird $.ui.open zu { isPlaced: true } aufgelöst. Wenn das Pane wartet, ist isPlaced false und reason ist ein String, der sagt, warum. Ein wartendes Pane erscheint, wenn der Benutzer es öffnet oder das Terminal verbreitert. Um zu sagen, dass etwas verfügbar ist, ohne ein Pane zu öffnen, rufen Sie $.ui.toast('Your message') auf, das eine kleine Mitteilung zeigt, die nach ein paar Sekunden verschwindet.

Erstellen Sie einen Baum aus Elementen

Was ein ui.render Hook zurückgibt, ist ein Element-Baum: eine Beschreibung dessen, was zu zeichnen ist, bestehend aus Boxen, Text und Steuerelementen, die ineinander verschachtelt sind. Sie beschreiben die Zeichnung, und Claude Code rendert sie im Terminal oder der Desktop-App. Um die Elemente zu erhalten, rufen Sie $.ui.resolve(e) in Ihrem Hook auf, wie in const { Box, Text, Button } = $.ui.resolve(e). Jedes Element ist eine Funktion. Sie übergeben ihr Props, und Sie setzen die Elemente und Strings, die darin gehen, in children. Die meisten Zeichnungen verwenden vier Elemente. Wählen Sie eine Registerkarte, um jedes zu sehen und wie das Terminal es zeichnet:
Text zeichnet einen String mit optionalem Styling wie bold und color:
Diese Tabelle listet jedes Element auf: Wenn Ihr Modul eine .tsx oder .jsx Datei ist, können Sie den Baum als JSX schreiben. Destrukturieren Sie die Elemente zuerst aus $.ui.resolve(e), da ein Hooks-Modul keine Element-Globals hat. Wenn ein Baum ein Element verwendet, das die App nicht hat, ein Prop, das ein Element nicht nimmt, oder ein Kind, wo keines geht, zeichnet Claude Code seine eigene Version der Site. In einer Sitzung, die mit --plugin-dir gestartet wurde, sagt eine Transkriptzeile so, wie ui.render (Pane) refused: Text prop "bogusProp" is not allowed; the engine drew its own. Das Debug-Protokoll zeichnet es als ui.render (Pane): a hook returned a tree that does not validate mit dem gleichen Grund auf. Nichts anderes erscheint in der Sitzung, also wenn eine Zeichnung nicht angezeigt wird, überprüfen Sie diese Zeile oder das Protokoll.

Zeichnen Sie ein Gitter von farbigen Zellen

Für eine Wärmekarte, eine Sparkline oder ein Spielbrett im Terminal zeichnen Sie ein Raster und nicht ein Box für jede Zelle. Ein Raster nimmt einen key, seine Größe in columns und rows und cells, die jede Zelle in einen String packt. Jede Zelle sind drei Zahlen: der Code-Punkt des Zeichens, seine Farbe und seine Hintergrundfarbe. Eine Farbe ist eine Hexadezimalzahl mit zwei Ziffern jeweils für Rot, Grün und Blau, wie 0xc62828 für ein Rot oder 0x01000000 für das Standard des Terminals. Die Desktop-App hat kein Raster, also überprüfen Sie e.surface und zeichnen Sie dort Text. Dieser Pane-Hauptteil zeichnet eine drei mal zwei Wärmekarte:
Im Terminal zeigt das Pane das Gitter: Ein Pane im Terminal, das ein kleines Gitter von farbigen Blöcken enthält, zwei Reihen von drei. Die obere Reihe ist grün, bernsteinfarben und rot. Die untere Reihe ist grün, grün und bernsteinfarben. Das rows Array ist der Teil, den Sie ändern würden, und cellsOf verwandelt es in den gepackten String. Der Hook zeichnet nur in einem Pane, dessen id heat ist, also öffnen Sie eines mit $.ui.open({ id: 'heat' }) von einem Befehl, wie das hello-tabs Beispiel sein Pane öffnet. Jedes Zeichen muss eine Zelle breit sein. Um ein Raster, das bereits auf dem Bildschirm ist, zu animieren, rufen Sie $.ui.blit mit der id des Pane als requestId, dem key des Raster, der gleichen Größe und neuen Zellen auf. Für dieses Beispiel ist das $.ui.blit({ requestId: 'heat', key: 'grid', columns: 3, rows: 2, cells: cellsOf(newRows) }). Es malt dieses eine Element neu, ohne Ihren ui.render Hook erneut auszuführen.

Reagieren Sie auf Drücke und Eingaben

Wenn der Benutzer eine Schaltfläche drückt, in ein Feld tippt oder aus einer Liste auswählt, die Ihr Mod gezeichnet hat, ruft Claude Code die Funktion auf, die Sie diesem Steuerelement gegeben haben, und sie läuft in Ihrem Modul. Jedes Steuerelement nimmt seine eigenen Callbacks:
  • Button: nimmt onPress(e), wobei e.surface die App ist, von der der Druck kam
  • Input: nimmt onSubmit(value) und onInput(value)
  • Select: nimmt onSelect(value) mit seinen Auswahlmöglichkeiten in options, eine Liste von mindestens einer Auswahlmöglichkeit mit eindeutigen Werten, wie [{ value: 'sm', label: 'Small' }, { value: 'lg', label: 'Large' }]
Ein Test drückt oder tippt in ein Steuerelement nach seinem key, also geben Sie jedem einen. Jede Verwendung eines Steuerelements löst auch ui.press, ui.input oder ui.select mit dem key in e.element aus, und ein anderer Mod kann diese Ereignisse hooken. Sein Hook läuft vor Ihrem Callback, daher sieht er, was der Benutzer in Ihren Input tippt und kann es ändern oder an Stelle Ihres Callbacks antworten. Die Mods API hat keine Methode, die die Schaltfläche eines anderen Mods drückt.

Tastaturfokus und Hotkeys

Ihr Mod liest die Tastatur nie selbst. Der Benutzer drückt eine Taste, Claude Code entscheidet, welches Ihrer Steuerelemente es ist, und der Callback dieses Steuerelements läuft. Abgesehen von einer Ziffern-Hotkey auf dem Band passiert das nur, während Ihr Pane oder Band den Tastaturfokus hat. Der Rest der Zeit gehen Tasten zur Eingabeaufforderung.

Wie ein Pane den Tastaturfokus erhält

Ein Pane erhält den Tastaturfokus auf eine von drei Arten:
  • Ihr Mod öffnet es mit focus: true von einem Befehl oder einem Druck
  • Der Benutzer drückt Ctrl+X dann Tab
  • Der Benutzer klickt darauf
Claude Code gewährt focus: true nur, während die Eingabeaufforderung leer ist und nichts anderes den Tastaturfokus hat. Ein Pane, das sich öffnet, während der Benutzer tippt, nimmt seine Tastenanschläge nicht.

Was jede Taste tut

Diese Tabelle listet auf, was eine Taste tut, während Ihr Pane oder Band den Tastaturfokus hat: Ein Mod kann Tab oder die Pfeiltasten nicht an etwas anderes binden, daher steuert ein Spiel mit w, a, s und d.

Setzen Sie eine Hotkey und den ersten Fokus

Zwei Props auf einem Steuerelement entscheiden, wie die Tastatur es erreicht:
  • hotkey: um dem Benutzer zu ermöglichen, eine Button mit einer Taste zu drücken, geben Sie ihr eine hotkey von einer Ziffer oder einem Kleinbuchstaben, wie in hotkey: 'a'
  • autoFocus: um zu wählen, welches Steuerelement den Fokus hat, wenn das Pane sich öffnet, fügen Sie autoFocus: true hinzu. Lassen Sie das Prop bei den anderen weg, da Claude Code autoFocus: false ablehnt.
Wie eine Hotkey angezeigt wird, hängt von der Schaltfläche und der App ab: Im Terminal benennen Sie die Taste im Label einer geklammerten Schaltfläche oder verwenden Sie plain: true, damit der Benutzer sehen kann, was zu drücken ist. Die Elements-Referenz hat die anderen Button Regeln: action, Ziffern-Hotkeys auf dem Band und zwei Schaltflächen auf einer Hotkey.

Nehmen Sie eingegebenen Text und zeichnen Sie eine Reihe für jedes Element

Viele Panes sind ein Textfeld mit einer Liste darunter. Das Beispiel in diesem Abschnitt ist ein Notizen-Pane: Sie tippen eine Notiz und drücken Enter, um sie hinzuzufügen, und jede Notiz hat eine x Schaltfläche, die sie löscht. Mit zwei hinzugefügten Notizen zeichnet das Terminal das Pane so:
Das Beispiel verwendet zwei Techniken:
  • Nehmen Sie eingegebenen Text: ein Input ruft onSubmit(value) mit dem Text des Feldes auf, wenn der Benutzer Enter drückt, und onInput(value) bei jeder Änderung
  • Zeichnen Sie eine Liste: ordnen Sie Ihre Daten einer Reihe jeweils zu, und geben Sie jedem key der Reihe seine eigene
Dieser Hook zeichnet den Inhalt des Pane:
Um das Pane zu versuchen:
  • Fügen Sie eine Notiz hinzu: tippen Sie eine Zeile und drücken Sie Enter. Die Zeile erscheint als neue Reihe, und das Feld leert sich.
  • Löschen Sie eine Notiz: drücken Sie Tab, bis die x Schaltfläche der Notiz den Fokus hat, dann drücken Sie Enter. Das x ist das Label der Schaltfläche und keine Hotkey, daher drückt das Tippen des Buchstabens es nicht.
Jede Änderung folgt dem gleichen Render-Zyklus wie hello-tabs: Der Callback ändert notes, ruft redraw auf und speichert die Liste in $.store. Das Feld leert sich nach jedem Submit wegen seines value Props. value ist der Text, den das Feld hält, wenn es gezeichnet wird, und das Tippen des Benutzers ersetzt ihn, bis Ihr Hook das Feld erneut zeichnet. Das Beispiel zeichnet das Feld immer mit ''. Das Beispiel speichert die Notizen und lädt sie nicht. Um sie in der nächsten Sitzung zurückzubringen, lesen Sie sie in einem session.start Hook, wie hello-tabs count liest. Drei Props machen die Zeile des Feldes aus, Note: Type a note and press Enter ⏎ add: Das Absenden eines Input startet keinen Turn, es sei denn, Ihr Callback ruft $.prompt.submit auf.

Zeichnen Sie eine Site neu

Eine Zeichnung ist ein Schnappschuss: Sie zeigt, was Ihr ui.render Hook das letzte Mal zurückgegeben hat, als der Hook lief. Um etwas Neues zu zeigen, muss der Hook erneut laufen. Claude Code führt ihn für einige Änderungen erneut aus, und Ihr Mod fragt nach dem Rest.

Wenn Claude Code ohne Aufforderung neu zeichnet

Claude Code führt Ihren ui.render Hook erneut aus, wenn sich die Props der Site ändern oder die Breite des Terminals ändert. Es führt den Hook nicht auf einem Timer aus, und es kann nicht sagen, wenn sich eine Variable in Ihrem Modul ändert.

Zeichnen Sie neu, wenn sich Ihre Daten ändern

Um Ihre Sites nach Ihren eigenen Datenänderungen erneut zu zeichnen, rufen Sie $.ui.invalidate('ui.render') auf. Dieses Pane zählt Drücke. Der Callback der Schaltfläche ändert count und fragt dann nach einem Neuzeichnen:
Jeder Druck erhöht die Zahl im Pane. Das hello-tabs Beispiel wickelt den gleichen Aufruf in seine redraw Funktion. Ein Wert, den Sie in $.state halten, braucht den Aufruf nicht, da das Schreiben des Wertes die Sites neu zeichnet, die ihn lesen.

Zeichnen Sie auf einem Timer neu

Um eine Uhr, einen Countdown oder einen Wert von außerhalb der Sitzung aktuell zu halten, zeichnen Sie nach einem Zeitplan neu. Starten Sie einen Timer im session.start Hook des Moduls. Wenn das Modul bereits einen hat, wie hello-tabs, fügen Sie die $.clock.every Zeile hinzu:
Claude Code führt jetzt Ihren ui.render Hook einmal pro Sekunde aus. Der Timer stoppt, wenn das Modul neu geladen wird, und die neue Kopie des Moduls startet ihren eigenen.

Wie oft eine Site neu gezeichnet werden kann

Claude Code begrenzt, wie oft es neu zeichnet, daher kann Ihr Mod $.ui.invalidate so oft aufrufen, wie sich seine Daten ändern. Das sichtbare Pane und das Band haben ein höheres Limit als andere Sites, und die Limits-Tabelle hat die Zahlen. Aufrufe, die schneller als das Limit kommen, werden in einem Neuzeichnen kombiniert. Dieses Neuzeichnen führt Ihren Hook einmal aus, und der Hook liest Ihre Daten, wie sie in diesem Moment sind, daher zeigt der neueste Wert und die Werte dazwischen nicht. Eine Animation kann nicht schneller als das Limit laufen.

Behalten Sie den Status

Ein Mod hat drei Orte, um einen Wert zu halten, und sie unterscheiden sich darin, wie lange der Wert dauert: bis das Modul neu geladen wird, bis die Sitzung endet oder von einer Sitzung zur nächsten. Wählen Sie danach, wie lange der Wert dauern muss: $.store.get(key) wird zu dem Wert oder undefined aufgelöst, und $.store.set(key, value) nimmt jeden JSON-Wert.

Behalten Sie einen Wert in $.state

$.state hält Werte für die Länge einer Sitzung, und es zeichnet für Sie neu. Es ist reaktiver Status: ein ui.render Hook, der einen Wert liest, abonniert ihn, daher zeichnet Claude Code diese Site jedes Mal neu, wenn Sie den Wert schreiben, und Sie rufen $.ui.invalidate nicht auf. Ein Wert in $.state überlebt auch ein Reload des Moduls, das eine Variable nicht tut. Um es einzurichten, deklarieren Sie Ihre Werte, zeigen Sie Ihr Manifest auf die Deklaration, dann definieren und verwenden Sie jeden Wert. Die Beispiele verschieben den count aus hello-tabs in $.state.

Deklarieren Sie die Werte

Deklarieren Sie die Werte in einer Typendatei. Der äußere Schlüssel ist der Name Ihres Plugins, und jeder Eintrag darunter ist ein Wert und sein Typ. Speichern Sie dies als hello-tabs/types/index.d.ts:
hello-tabs/types/index.d.ts

Zeigen Sie das Manifest auf die Deklaration

Um claude plugin validate zu lassen, Ihren Code gegen diese Datei zu überprüfen, fügen Sie ein types Feld zum Manifest mit seinem Pfad hinzu:
hello-tabs/.claude-plugin/plugin.json

Definieren, lesen und schreiben Sie einen Wert

In Ihrem Modul definieren Sie jeden Wert mit einem Standard, lesen ihn beim Zeichnen und schreiben ihn von einem Callback. atom benennt einen Wert und seinen Standard, read gibt ihn zurück, und update schreibt ihn. Die drei Helfer rufen $.state.get und $.state.set für Sie auf:
Da der ui.render Hook count gelesen hat, führt Claude Code den Hook jedes Mal erneut aus, wenn die Schaltfläche ihn schreibt. Drei Regeln gelten für den Code:
  • Schreiben Sie plugin und key als Literal-Strings: claude plugin validate liest sie aus Ihrer Quelle
  • Deklarieren Sie jeden Wert in der Typendatei: sonst schlägt die Validierung mit hello-tabs.count is not declared fehl
  • Schreiben Sie von einem Callback oder einem anderen Ereignis-Hook: ein ui.render Hook kann Status lesen und kann ihn nicht schreiben, daher schreiben Sie von onPress, onSubmit oder einem Hook für ein anderes Ereignis

Ändern Sie hello-tabs, um $.state zu verwenden

Um count in hello-tabs in $.state zu verschieben, ändern Sie jede Zeile, die ihn verwendet:
  • Am Anfang des Moduls: fügen Sie die import Zeile hinzu, und ersetzen Sie let count = 0 mit der atom Zeile
  • Im ui.render Hook: fügen Sie die read Zeile vor tabButton hinzu, und zeichnen Sie 'Count: ' + n im Text
  • Im Add one Button: ersetzen Sie onPress mit dem aus Speichern Sie aus mehr als einer Sitzung, das die Anzahl speichert sowie schreibt
  • Im session.start Hook: ersetzen Sie die zwei Zeilen, die saved lesen, mit dem loadCount Aufruf aus Laden Sie einen gespeicherten Wert erneut nach /clear
Behalten Sie redraw für die Tab-Schaltflächen, da tab immer noch eine Variable ist.

Laden Sie einen gespeicherten Wert erneut nach /clear

Wenn Ihr Mod einen gespeicherten Wert aus $.store in $.state bei session.start kopiert, muss er ihn nach /clear, /resume oder /branch erneut kopieren. Diese Befehle setzen jeden $.state Wert auf seinen Standard zurück, und session.start wird nicht erneut ausgelöst. classic.SessionStart wird nach jedem ausgelöst, mit e.source auf clear, resume oder fork gesetzt, daher kopieren Sie den Wert erneut in einem Hook darauf. Sonst zeigt Ihre Zeichnung den Standard, und ein Callback, der den $.state Wert speichert, schreibt den Standard über das, was Sie gespeichert haben. Dieser Code lädt count aus beiden Hooks. Es baut auf der $.state Version von hello-tabs auf, wo count ein Atom ist und update importiert wird. Setzen Sie loadCount über register, und fügen Sie den loadCount Aufruf zum session.start Hook hinzu, den Sie bereits haben. classic.SessionStart wird auch beim Start und nach Verdichtung ausgelöst, was $.state nicht zurückgesetzt, daher hält der Filter auf source den Hook zu den drei Resets:
Mit beiden Hooks an Ort und Stelle zeigt das Pane die gespeicherte Anzahl nach /clear und nicht 0, und der nächste Druck von Add one addiert zur gespeicherten Anzahl. loadCount schreibt den gespeicherten Wert über den in $.state, und session.start wird jedes Mal ausgelöst, wenn das Modul neu geladen wird. Um den Store nicht hinter sich zu lassen, speichern Sie bei jeder Änderung, wie die Add one Schaltfläche tut. Um den Reload ohne eine Sitzung zu überprüfen, testen Sie die Zeichnung nach /clear.

Speichern Sie aus mehr als einer Sitzung

Jede Sitzung auf Ihrem Computer, die Ihren Mod ausführt, teilt einen $.store. Ein get gefolgt von einem set ist nicht atomar. Wenn zwei Sitzungen jeweils einen Wert lesen, ihn ändern und zurückschreiben, rennen sie, und der zweite Schreib ersetzt den ersten. Zwei Auswahlmöglichkeiten machen das weniger wahrscheinlich:
  • Geben Sie jedem Element seinen eigenen Schlüssel: ein set ändert nur seinen eigenen Schlüssel, daher überschreiben Sitzungen, die verschiedene Schlüssel schreiben, sich nicht gegenseitig
  • Lesen Sie erneut direkt vor dem Schreiben: für einen Wert, den mehrere Sitzungen ändern, get den Schlüssel im Callback und erstellen Sie den neuen Wert daraus, nicht aus einer Kopie, die Sie bei session.start geladen haben. Ein Schreib einer anderen Sitzung geht immer noch verloren, wenn er zwischen Ihrem get und Ihrem set landet.
Diese Schaltfläche addiert eins zu dem, was der Store jetzt hält, dann aktualisiert die Zeichnung:
Wenn eine zweite Sitzung ihre eigene Schaltfläche drei Mal gedrückt hat, seit diese Sitzung gestartet wurde, zeigt dieser Druck und speichert eine Anzahl, die diese drei enthält.

Nächste Schritte