Skip to main content
Un mod peut dessiner sa propre interface dans Claude Code et modifier des parties de l’interface que Claude Code dessine déjà. Chaque endroit où un mod peut dessiner s’appelle un site de rendu, comme un volet, la bande au-dessus de l’invite, ou le spinner. Claude Code déclenche l’événement ui.render chaque fois qu’il s’apprête à dessiner un site de rendu, et votre hook pour cet événement retourne ce qu’il faut dessiner là. Cette carte montre où un mod peut dessiner dans une session de terminal : Carte d'une session de terminal Claude Code. Un mod peut ajouter un volet comme barre latérale à droite, un toast en haut à droite de la transcription, une ligne de journal dans la transcription, une bande au-dessus de l'invite, et une ligne d'état sous l'invite. Un mod peut redessiner les messages, les lignes d'appels d'outils, et le spinner. L'invite est celle de Claude Code. Carte d'une session de terminal Claude Code. Un mod peut ajouter un volet comme barre latérale à droite, un toast en haut à droite de la transcription, une ligne de journal dans la transcription, une bande au-dessus de l'invite, et une ligne d'état sous l'invite. Un mod peut redessiner les messages, les lignes d'appels d'outils, et le spinner. L'invite est celle de Claude Code. Dans un terminal plus étroit, le volet se trouve au-dessus de l’invite au lieu de côté de la transcription. Construisez votre premier mod avant de commencer ici. Commencez par l’exemple travaillé, qui construit un volet avec deux onglets et un compteur, puis lisez la section pour chaque élément que vous voulez modifier.
Pour rechercher une prop ou une limite, consultez la référence.

Construire un volet avec des onglets

Dans cette section, vous construisez un mod qui ajoute une commande /hello-tabs, et la commande ouvre un volet. Un volet est une barre latérale à côté de la transcription dans un terminal plein écran large, ou une région encadrée au-dessus de l’invite sinon. Ce volet affiche deux onglets, et le deuxième onglet a un bouton qui ajoute un au compteur. Le compte est toujours là après que vous redémarriez Claude Code. Le mod fini ressemble à ceci. L’enregistrement ouvre le volet, bascule vers le deuxième onglet, appuie sur le bouton quelques fois, et revient au premier onglet :
Claude Code n’a pas d’élément d’onglets intégré, donc les onglets sont deux boutons dans une ligne. Le mod garde la trace de celui qui est actif et dessine le contenu de cet onglet sous la ligne.
1

Créer le plugin

Un mod est un plugin avec un manifeste, un hooks.json qui pointe vers votre code, et le fichier de code. Créer un mod explique chacun. Créez un répertoire nommé hello-tabs avec des répertoires .claude-plugin et hooks à l’intérieur, puis enregistrez les deux premiers fichiers.Enregistrez le manifeste sous hello-tabs/.claude-plugin/plugin.json :
hello-tabs/.claude-plugin/plugin.json
Nommez votre point d’entrée dans hello-tabs/hooks/hooks.json :
hello-tabs/hooks/hooks.json
2

Écrire le code

Le code fait trois choses, une dans chaque hook :
  • Ajoute la commande /hello-tabs
  • Ouvre le volet quand vous exécutez cette commande
  • Dessine le contenu du volet : la ligne d’onglets et le corps de l’onglet ouvert
Deux variables au niveau du module, tab et count, conservent l’état du volet.Enregistrez ceci sous hello-tabs/hooks/register.js :
hello-tabs/hooks/register.js
Chaque hook fait aussi quelque chose que le code ne rend pas évident :
  • session.start lit aussi le compte sauvegardé depuis $.store, un magasin clé-valeur qui persiste entre les sessions.
  • command.run dit seulement à Claude Code que le volet existe. Ouvrir un volet ne dessine rien par lui-même : Claude Code déclenche ensuite ui.render pour demander ce qu’il faut y mettre.
  • ui.render retourne l’arbre d’éléments, une Box qui contient d’autres boîtes, du texte et des boutons, et le construit à nouveau à partir de tab et count chaque fois qu’il s’exécute.
Appuyer sur un bouton exécute son callback onPress, qui change une variable et appelle redraw. Claude Code exécute ensuite le hook ui.render à nouveau, et le hook construit un nouvel arbre à partir des nouvelles valeurs. Chaque dessin interactif utilise ce cycle de rendu : un callback change l’état, et le hook dessine à nouveau à partir du nouvel état.
3

Ouvrir le volet

Dans votre shell, démarrez Claude Code avec claude --plugin-dir ./hello-tabs. À l’invite Claude Code, exécutez /hello-tabs. Un volet s’ouvre avec 1: One et 2: Two en haut. Appuyez sur 2, puis appuyez sur a, la touche de raccourci pour Add one, quelques fois. Le compte augmente.
4

Vérifier que le compte a été sauvegardé

Appuyez sur Esc pour fermer le volet, puis quittez la session. Dans votre shell, démarrez Claude Code à nouveau avec la même commande claude --plugin-dir ./hello-tabs, et à l’invite Claude Code exécutez /hello-tabs. Le compte est où vous l’avez laissé.Pour effacer le compte, faites appeler au mod $.store.delete('count'). Conserver l’état couvre combien de temps chaque type de valeur dure.

Choisir où dessiner

Un hook ui.render s’exécute pour chaque site de rendu sauf si vous le réduisez à celui que vous voulez dessiner. Pour choisir le site de rendu, passez un filtre, appelé un matcher, comme deuxième argument à on. { component: 'Pane' } exécute le hook seulement pour les volets. Dans le hook, e.component nomme le site, e.surface dit quelle application dessine, et e.props contient les données propres du site. Pour un volet, e.requestId est l’id avec lequel vous l’avez ouvert. Deux sites sont vides jusqu’à ce qu’un mod les remplisse, le volet et la bande. Sélectionnez un onglet pour voir ce que chacun est et comment dessiner dedans :
Un volet est une barre latérale à côté de la transcription dans un terminal plein écran large, ou une région encadrée au-dessus de l’invite sinon. Avec plusieurs volets ouverts, chacun obtient un onglet qui affiche son titre.Un volet apparaît quand votre mod appelle $.ui.open avec un id que vous choisissez, comme dans $.ui.open({ id: 'hello-tabs' }). Ouvrir un volet au bon moment couvre les autres champs et quand un volet attend un terminal plus large.Pour dessiner dans votre volet, filtrez sur { component: 'Pane' } et vérifiez que e.requestId est votre id.

Modifier ce que Claude Code dessine déjà

Claude Code dessine la plupart de son interface lui-même : les messages, les lignes d’appels d’outils, le spinner, et plus. Chacune de ces parties est aussi un site de rendu, donc un mod peut le restyler ou le remplacer. Pour en modifier un, filtrez votre hook ui.render sur son nom de ce tableau : À un site que Claude Code dessine déjà, votre hook a trois choix : modifier un détail, remplacer le dessin, ou le laisser tranquille. Sélectionnez un onglet pour voir chacun appliqué au spinner. Les exemples lisent une variable calls qu’un autre hook compte, comme dans le mod tutoriel.
Pour garder le dessin de Claude Code et modifier une partie de celui-ci, passez à next une copie de l’événement avec des props modifiées. Ce hook change le texte après le mot du spinner :
Le spinner garde son animation et son mot, et votre texte suit le mot :
L’invite de permission n’est pas un site de rendu, donc un mod ne peut pas modifier ce qu’il affiche. Le dialogue de question, AskUserQuestion, en est un, donc un mod peut modifier cela. Le terminal et l’application Desktop ne déclenchent pas tous les mêmes sites. Pane, AbovePrompt, Spinner, et les sites de transcription fonctionnent dans les deux. Quelques autres lignes d’état sont déclenchées seulement dans le terminal. Le tableau des sites de rendu liste où chacun est déclenché.

Ouvrir un volet au bon moment

Un volet n’apparaît que quand votre mod l’ouvre. Comment et quand vous l’ouvrez décide s’il prend le focus clavier, combien d’espace il demande, et s’il s’affiche du tout dans un terminal étroit. Pour ouvrir un volet, appelez $.ui.open avec un id que vous choisissez. L’id est le nom du volet : votre hook ui.render le vérifie, et vous le passez à nouveau pour fermer le volet.
Pour fermer le volet, appelez $.ui.close avec l’id avec lequel vous l’avez ouvert :
En plus de id, $.ui.open prend ces champs optionnels : Pour laisser une commande ouvrir le volet pendant que Claude travaille, ajoutez immediate: true quand vous enregistrez la commande. Sans cela, une commande tapée pendant un tour attend la fin du tour.

Quand un volet attend un terminal plus large

Un volet que votre mod ouvre sans être demandé n’apparaît pas dans un terminal étroit, donc il ne peut pas prendre le contrôle d’un petit écran. S’il apparaît dépend de ce qui l’a ouvert :
  • Ouvert par quelque chose que l’utilisateur a fait, comme une commande qu’il a exécutée ou un bouton qu’il a appuyé, le volet apparaît à n’importe quelle largeur
  • Ouvert par votre mod agissant par lui-même, comme à partir d’une minuterie ou d’un hook turn.start, le volet n’apparaît que dans un terminal d’au moins 144 colonnes de large. Après que l’utilisateur ait ouvert ce volet une fois lui-même, 110 colonnes suffisent.
Quand le volet apparaît, $.ui.open se résout en { isPlaced: true }. Quand le volet attend, isPlaced est false et reason est une chaîne qui dit pourquoi. Un volet en attente apparaît quand l’utilisateur l’ouvre ou élargit le terminal. Pour dire que quelque chose est disponible sans ouvrir un volet, appelez $.ui.toast('Your message'), qui affiche un petit avis qui disparaît après quelques secondes.

Construire un arbre à partir d’éléments

Ce qu’un hook ui.render retourne est un arbre d’éléments : une description de ce qu’il faut dessiner, faite de boîtes, de texte et de contrôles imbriqués les uns dans les autres. Vous décrivez le dessin, et Claude Code le rend dans le terminal ou l’application Desktop. Pour obtenir les éléments, appelez $.ui.resolve(e) dans votre hook, comme dans const { Box, Text, Button } = $.ui.resolve(e). Chaque élément est une fonction. Vous lui passez des props, et vous mettez les éléments et les chaînes qui vont à l’intérieur dans children. La plupart des dessins utilisent quatre éléments. Sélectionnez un onglet pour voir chacun et comment le terminal le dessine :
Text dessine une chaîne, avec un style optionnel comme bold et color :
Ce tableau liste chaque élément : Si votre module est un fichier .tsx ou .jsx, vous pouvez écrire l’arbre en JSX. Déstructurez les éléments de $.ui.resolve(e) d’abord, car un module de hooks n’a pas de globals d’éléments. Si un arbre utilise un élément que l’application n’a pas, une prop qu’un élément ne prend pas, ou un enfant où aucun ne va, Claude Code dessine sa propre version du site. Dans une session démarrée avec --plugin-dir, une ligne de transcription le dit, comme ui.render (Pane) refused: Text prop "bogusProp" is not allowed; the engine drew its own. Le journal de débogage l’enregistre comme ui.render (Pane): a hook returned a tree that does not validate avec la même raison. Rien d’autre n’apparaît dans la session, donc quand un dessin ne s’affiche pas, vérifiez cette ligne ou le journal.

Dessiner une grille de cellules colorées

Pour une carte thermique, une sparkline, ou un plateau de jeu dans le terminal, dessinez un Raster et non une Box pour chaque cellule. Un Raster prend une key, sa taille en columns et rows, et cells, qui empaquette chaque cellule dans une chaîne. Chaque cellule est trois nombres : le point de code du caractère, sa couleur et sa couleur de fond. Une couleur est un nombre hexadécimal avec deux chiffres chacun pour le rouge, le vert et le bleu, comme 0xc62828 pour un rouge, ou 0x01000000 pour la valeur par défaut du terminal. L’application Desktop n’a pas de Raster, donc vérifiez e.surface et dessinez du texte là. Ce corps de volet dessine une carte thermique de trois par deux :
Dans le terminal, le volet affiche la grille : Un volet dans le terminal qui contient une petite grille de blocs colorés, deux lignes de trois. La ligne du haut est verte, ambre et rouge. La ligne du bas est verte, verte et ambre. Le tableau rows est la partie que vous changeriez, et cellsOf la transforme en chaîne empaquetée. Le hook dessine seulement dans un volet dont l’id est heat, donc ouvrez-en un avec $.ui.open({ id: 'heat' }) à partir d’une commande, comme l’exemple hello-tabs ouvre son volet. Chaque caractère doit être large d’une cellule. Pour animer un Raster qui est déjà à l’écran, appelez $.ui.blit avec l’id du volet comme requestId, la key du Raster, la même taille, et de nouvelles cellules. Pour cet exemple, c’est $.ui.blit({ requestId: 'heat', key: 'grid', columns: 3, rows: 2, cells: cellsOf(newRows) }). Il repeint cet élément sans exécuter votre hook ui.render à nouveau.

Répondre aux appuis et à la saisie

Quand l’utilisateur appuie sur un bouton, tape dans un champ, ou choisit dans une liste que votre mod a dessinée, Claude Code appelle la fonction que vous avez donnée à ce contrôle, et elle s’exécute dans votre module. Chaque contrôle prend ses propres callbacks :
  • Button : prend onPress(e), où e.surface est l’application d’où vient l’appui
  • Input : prend onSubmit(value) et onInput(value)
  • Select : prend onSelect(value) avec ses choix dans options, une liste d’au moins un choix avec des valeurs uniques, comme [{ value: 'sm', label: 'Small' }, { value: 'lg', label: 'Large' }]
Un test appuie ou tape dans un contrôle par sa key, donc donnez-en un à chaque contrôle. Chaque utilisation d’un contrôle déclenche aussi ui.press, ui.input, ou ui.select avec la key dans e.element, et un autre mod peut accrocher ces événements. Son hook s’exécute avant votre callback, donc il voit ce que l’utilisateur tape dans votre Input et peut le modifier ou répondre à la place de votre callback. L’API des mods n’a pas de méthode qui appuie sur le bouton d’un autre mod.

Focus clavier et touches de raccourci

Votre mod ne lit jamais le clavier lui-même. L’utilisateur appuie sur une touche, Claude Code décide lequel de vos contrôles c’est, et le callback de ce contrôle s’exécute. À part une touche de raccourci numérique sur la bande, cela ne se produit que pendant que votre volet ou bande a le focus clavier. Le reste du temps, les touches vont à l’invite.

Comment un volet obtient le focus clavier

Un volet obtient le focus clavier de l’une de trois façons :
  • Votre mod l’ouvre avec focus: true à partir d’une commande ou d’un appui
  • L’utilisateur appuie sur Ctrl+X puis Tab
  • L’utilisateur clique dessus
Claude Code accorde focus: true seulement pendant que l’invite est vide et rien d’autre n’a le focus clavier. Un volet qui s’ouvre pendant que l’utilisateur tape ne prend pas ses frappes.

Ce que chaque touche fait

Ce tableau liste ce qu’une touche fait pendant que votre volet ou bande a le focus clavier : Un mod ne peut pas lier Tab ou les touches fléchées à autre chose, donc un jeu se dirige avec w, a, s, et d.

Définir une touche de raccourci et le premier focus

Deux props sur un contrôle décident comment le clavier l’atteint :
  • hotkey : pour laisser l’utilisateur appuyer sur un Button avec une touche, donnez-lui une hotkey d’un chiffre ou une lettre minuscule, comme dans hotkey: 'a'
  • autoFocus : pour choisir quel contrôle a le focus quand le volet s’ouvre, ajoutez autoFocus: true à celui-ci. Laissez la prop de côté sur les autres, car Claude Code refuse autoFocus: false.
Comment une touche de raccourci s’affiche dépend du bouton et de l’application : Dans le terminal, nommez la touche dans l’étiquette d’un bouton entre crochets, ou utilisez plain: true, pour que l’utilisateur puisse voir ce qu’il faut appuyer. La référence des éléments a les autres règles de Button : action, les touches de raccourci numériques sur la bande, et deux boutons sur une touche de raccourci.

Prendre l’entrée tapée et dessiner une ligne pour chaque élément

De nombreux volets sont un champ de texte avec une liste en dessous. L’exemple de cette section est un volet de notes : vous tapez une note et appuyez sur Entrée pour l’ajouter, et chaque note a un bouton x qui la supprime. Avec deux notes ajoutées, le terminal dessine le volet de cette façon :
L’exemple utilise deux techniques :
  • Prendre l’entrée tapée : un Input appelle onSubmit(value) avec le texte du champ quand l’utilisateur appuie sur Entrée, et onInput(value) à chaque changement
  • Dessiner une liste : mappez vos données à une ligne chacune, et donnez à chaque bouton de ligne sa propre key
Ce hook dessine le contenu du volet :
Pour essayer le volet :
  • Ajouter une note : tapez une ligne et appuyez sur Entrée. La ligne apparaît comme une nouvelle ligne, et le champ se vide.
  • Supprimer une note : appuyez sur Tab jusqu’à ce que le bouton x de la note ait le focus, puis appuyez sur Entrée. Le x est l’étiquette du bouton et non une touche de raccourci, donc taper la lettre ne l’appuie pas.
Chaque changement suit le même cycle de rendu que hello-tabs : le callback change notes, appelle redraw, et enregistre la liste dans $.store. Le champ se vide après chaque soumission à cause de sa prop value. value est le texte que le champ contient quand il est dessiné, et la saisie de l’utilisateur le remplace jusqu’à ce que votre hook dessine le champ à nouveau. L’exemple dessine toujours le champ avec ''. L’exemple enregistre les notes et ne les charge pas. Pour les ramener dans la session suivante, lisez-les dans un hook session.start, de la même façon que hello-tabs lit count. Trois props composent la ligne du champ, Note: Type a note and press Enter ⏎ add : Soumettre un Input ne démarre pas un tour sauf si votre callback appelle $.prompt.submit.

Redessiner un site

Un dessin est un instantané : il affiche ce que votre hook ui.render a retourné la dernière fois que le hook s’est exécuté. Pour afficher quelque chose de nouveau, le hook doit s’exécuter à nouveau. Claude Code l’exécute à nouveau pour certains changements, et votre mod demande le reste.

Quand Claude Code redessine sans être demandé

Claude Code exécute votre hook ui.render à nouveau quand les props du site changent ou la largeur du terminal change. Il n’exécute pas le hook sur une minuterie, et il ne peut pas dire quand une variable dans votre module change.

Redessiner quand vos données changent

Pour avoir vos sites dessinés à nouveau après que vos propres données changent, appelez $.ui.invalidate('ui.render'). Ce volet compte les appuis. Le callback du bouton change count, puis demande un redessin :
Chaque appui augmente le nombre dans le volet. L’exemple hello-tabs enveloppe le même appel dans sa fonction redraw. Une valeur que vous gardez dans $.state n’a pas besoin de l’appel, car écrire la valeur redessine les sites qui la lisent.

Redessiner sur une minuterie

Pour garder une horloge, un compte à rebours, ou une valeur de l’extérieur de la session actuelle, redessinez selon un calendrier. Démarrez une minuterie dans le hook session.start du module. Si le module en a déjà une, comme hello-tabs le fait, ajoutez la ligne $.clock.every à celle-ci :
Claude Code exécute maintenant votre hook ui.render une fois par seconde. La minuterie s’arrête quand le module se recharge, et la nouvelle copie du module démarre la sienne.

À quelle fréquence un site peut redessiner

Claude Code limite la fréquence à laquelle il redessine un site, donc votre mod peut appeler $.ui.invalidate aussi souvent que ses données changent. Le volet visible et la bande ont une limite plus élevée que les autres sites, et le tableau des limites contient les chiffres. Les appels qui viennent plus vite que la limite sont combinés en un redessin. Ce redessin exécute votre hook une fois, et le hook lit vos données telles qu’elles sont à ce moment, donc la valeur la plus récente s’affiche et les valeurs entre les deux ne s’affichent pas. Une animation ne peut pas s’exécuter plus vite que la limite.

Conserver l’état

Un mod a trois endroits pour garder une valeur, et ils diffèrent dans la durée pendant laquelle la valeur dure : jusqu’à ce que le module se recharge, jusqu’à ce que la session se termine, ou d’une session à l’autre. Choisissez selon la durée pendant laquelle la valeur doit durer : $.store.get(key) se résout en la valeur ou undefined, et $.store.set(key, value) prend n’importe quelle valeur JSON.

Garder une valeur dans $.state

$.state contient des valeurs pour la durée d’une session, et il redessine pour vous. C’est un état réactif : un hook ui.render qui lit une valeur s’y abonne, donc Claude Code redessine ce site chaque fois que vous écrivez la valeur, et vous n’appelez pas $.ui.invalidate. Une valeur dans $.state survit aussi à un rechargement du module, ce qu’une variable ne fait pas. Pour le configurer, déclarez vos valeurs, pointez votre manifeste vers la déclaration, puis définissez et utilisez chaque valeur. Les exemples déplacent le count de hello-tabs dans $.state.

Déclarer les valeurs

Déclarez les valeurs dans un fichier de types. La clé externe est le nom de votre plugin, et chaque entrée en dessous est une valeur et son type. Enregistrez ceci sous hello-tabs/types/index.d.ts :
hello-tabs/types/index.d.ts

Pointer le manifeste vers la déclaration

Pour laisser claude plugin validate vérifier votre code par rapport à ce fichier, ajoutez un champ types au manifeste avec son chemin :
hello-tabs/.claude-plugin/plugin.json

Définir, lire et écrire une valeur

Dans votre module, définissez chaque valeur avec une valeur par défaut, lisez-la pendant le dessin, et écrivez-la à partir d’un callback. atom nomme une valeur et sa valeur par défaut, read la retourne, et update l’écrit. Les trois aides appellent $.state.get et $.state.set pour vous :
Parce que le hook ui.render a lu count, Claude Code exécute le hook à nouveau chaque fois que le bouton l’écrit. Trois règles s’appliquent au code :
  • Écrivez plugin et key comme des chaînes littérales : claude plugin validate les lit de votre source
  • Déclarez chaque valeur dans le fichier de types : sinon la validation échoue avec hello-tabs.count is not declared
  • Écrivez à partir d’un callback ou du hook d’un autre événement : un hook ui.render peut lire l’état et ne peut pas l’écrire, donc écrivez à partir de onPress, onSubmit, ou un hook pour un autre événement

Modifier hello-tabs pour utiliser $.state

Pour déplacer count dans hello-tabs dans $.state, modifiez chaque ligne qui l’utilise : Gardez redraw pour les boutons d’onglets, car tab est toujours une variable.

Charger une valeur sauvegardée à nouveau après /clear

Si votre mod copie une valeur sauvegardée de $.store dans $.state à session.start, il doit la copier à nouveau après /clear, /resume, ou /branch. Ces commandes remettent chaque valeur $.state à sa valeur par défaut, et session.start ne se déclenche pas à nouveau. classic.SessionStart se déclenche après chacune d’elles, avec e.source défini sur clear, resume, ou fork, donc copiez la valeur à nouveau dans un hook dessus. Sinon votre dessin affiche la valeur par défaut, et un callback qui enregistre la valeur $.state écrit la valeur par défaut sur ce que vous avez stocké. Ce code charge count à partir des deux hooks. Il s’appuie sur la version $.state de hello-tabs, où count est un atome et update est importé. Mettez loadCount au-dessus de register, et ajoutez l’appel loadCount au hook session.start que vous avez déjà. classic.SessionStart se déclenche aussi au démarrage et après compaction, ce qui ne réinitialise pas $.state, donc le filtre sur source garde le hook aux trois réinitialisations :
Avec les deux hooks en place, le volet affiche le compte sauvegardé après /clear et non 0, et le prochain appui sur Add one ajoute au compte sauvegardé. loadCount écrit la valeur stockée sur celle dans $.state, et session.start se déclenche à nouveau chaque fois que le module se recharge. Pour garder le magasin de prendre du retard, enregistrez à chaque changement, comme le bouton Add one le fait. Pour vérifier le rechargement sans une session, testez le dessin après /clear.

Enregistrer à partir de plus d’une session

Chaque session sur votre machine qui exécute votre mod partage un $.store. Un get suivi d’un set n’est pas atomique. Quand deux sessions lisent chacune une valeur, la modifient et l’écrivent, elles font la course, et la deuxième écriture remplace la première. Deux choix rendent cela moins probable :
  • Donnez à chaque élément sa propre clé : un set change seulement sa propre clé, donc les sessions qui écrivent des clés différentes ne s’écrasent pas mutuellement
  • Lisez à nouveau juste avant d’écrire : pour une valeur que plusieurs sessions changent, get la clé dans le callback et construisez la nouvelle valeur à partir de cela, pas à partir d’une copie que vous avez chargée à session.start. L’écriture d’une autre session est toujours perdue si elle atterrit entre votre get et votre set.
Ce bouton ajoute un à ce que le magasin contient maintenant, puis met à jour le dessin :
Si une deuxième session a appuyé sur son propre bouton trois fois depuis le démarrage de cette session, cet appui affiche et enregistre un compte qui inclut ces trois.

Prochaines étapes