Documentation du développeur de plugins
Créez des plugins pour l'application de bureau AnBoWork : ajoutez de nouveaux outils pour l'IA, ancrez votre propre panneau à côté d'une session, envoyez des notifications système, analysez de nouveaux formats de fichiers. Un manifest.json plus un script d’entrée suffisent pour commencer.
01Aperçu
Un plugin AnBoWork est un simple programme Node.js. Après l'installation, l'application le transforme en processus enfant autonome (noeud pur, pas d'API Electron) et lui parle via des messages inter-processus. Aucun package SDK n’est requis ; tout ce dont vous avez besoin est process.on('message') et process.send().
Tout ce qu'un plugin peut faire est déclaré statiquement dans manifest.json : la page de consentement de pré-installation et l'examen du marché peuvent indiquer quels outils il ajoute et de quelles autorisations il a besoin sans exécuter de code de plugin. Toute l'interface utilisateur (icônes de la barre d'outils, paramètres, palette de commandes, menus contextuels) est restituée par l'hôte à partir de la déclaration ; le code du plugin ne s'exécute jamais dans la fenêtre principale. Seules les vues ancrées et les panneaux flottants constituent votre propre code HTML et s'exécutent dans des pages isolées en mode bac à sable.
Capacités en un coup d'oeil
| Champ manifeste | Capacité | Où les utilisateurs le voient |
|---|---|---|
tools | Ajouter des outils appelables pour l'IA | L'IA les appelle automatiquement en conversation ; les appels d'outils sont affichés dans la session |
views | Vue persistante ancrée dans la barre latérale droite de la session | Une icône supplémentaire dans la barre d'outils de la session ouvre votre page à droite |
ui | Fenêtre flottante autonome | Ouvert depuis le menu "⋯" dans la liste des plugins |
sessionAction | Icône d'action persistante dans la barre d'outils de la session | Un clic exécute l'outil que vous spécifiez |
configuration | Entrées sur la page des paramètres | Paramètres → Configuration du plugin ; les valeurs sont transmises à chaque appel |
commands | Entrées de la palette de commandes Ctrl/Cmd+K | Palette de commandes |
keybindings | Raccourcis clavier globaux | Une combinaison de touches déclenche une commande |
menus | Éléments du menu contextuel de la session | Le menu "⋯" / clic droit sur une ligne de session |
documentParsers | Analyser les fichiers déposés dans la zone de saisie | Appelé automatiquement lorsque l'utilisateur dépose un fichier correspondant |
activationEvents | Commencez avec l'application | Invisible; pour les plugins qui nécessitent des minuteries d'arrière-plan |
permissions | Déclarer les autorisations requises | Page de consentement de préinstallation |
02Démarrage rapide
Un plugin minimal n'a besoin que de deux fichiers.
1. Écrivez manifest.json
2. Écrivez le script d'entrée
3. Installez dans l'application
Ouvrez AnBoWork → barre supérieure "Outils" → "Plugins" → "Installer localement" dans le coin supérieur droit, puis choisissez le dossier du plugin (ou un zip de celui-ci). Une page de consentement répertorie les autorisations déclarées et chaque outil avant l'installation ; confirmer pour activer.
4. Essayez-le
Dans n'importe quelle session, dites à l'IA "demandez au plugin de dire bonjour à Alice". Sur la base de la description de l'outil, l'IA décide d'appeler say_hello, et l'appel et son résultat apparaissent dans la session.
03Champs du manifeste
| Champ | Taper | Requis | Description |
|---|---|---|---|
id | string | Oui | Style de domaine inversé, par ex. com.example.my-plugin. Lettres, chiffres, points et traits d'union uniquement. Immuable une fois créé ; l'installation à nouveau du même identifiant est traitée comme une réinstallation. |
name | string | Oui | Nom du plugin. Avec description, il est transmis au modèle comme contexte, l'anglais est donc recommandé. |
version | string | Oui | Version sémantique ; le marché l'utilise pour détecter les mises à jour. |
description | string | Oui | Une phrase décrivant ce que fait le plugin (anglais). |
author | string | Non | Auteur. |
readme | string | Non | La description détaillée affichée sur la page de détails du marché prend en charge Markdown. Les images à l'intérieur doivent être des URL https — les chemins relatifs vers les fichiers regroupés dans le zip ne sont pas pris en charge. |
icon | string | Non | Icône affichée dans la liste du marché et la page de détails : un chemin relatif vers un fichier fourni dans le zip (par exemple icon.png). Doit être PNG, pas SVG, au moins 128×128. |
main | string | Oui | Script d'entrée, relatif au dossier du plugin. .. l'échappement du dossier n'est pas autorisé. |
permissions | string[] | Oui | network / filesystem / notifications ; peut être un tableau vide. Voir « Modèle d'autorisation ». |
tools | object[] | Oui | Déclarations d'outils ; peut être un tableau vide. Voir « Outils et protocole d'appel ». |
documentParsers | object[] | Non | Capacité d'analyse de fichiers. |
ui | object | Non | Panneau flottant :{ entry, title } |
views | object[] | Non | Vues ancrées :{ id, title, icon, entry, width? } |
sessionAction | object | Non | Icône de la barre d'outils, au maximum une par plugin. |
configuration | object[] | Non | Liste des entrées de paramètres. |
commands | object[] | Non | Entrées de la palette de commandes. |
keybindings | object[] | Non | Raccourcis. command doit faire référence au tool d'une entrée dans commands[], sinon l'installation est rejetée. |
menus | object | Non | Seul l'emplacement session/context est disponible pour l'instant. |
activationEvents | string[] | Non | Seulement onStartupFinished pour l'instant. |
Conventions linguistiques pour le texte
Le texte du manifeste a deux publics. Pour le modèle : name, description, tools[].description, tools[].parameters.*.description. Écrivez-les en anglais ; les modèles comprennent les descriptions des outils en anglais et remplissent les paramètres de manière plus fiable. Pour les personnes : tools[].summary (résumé d'une ligne sur la page de consentement), ui.title, views[].title, sessionAction.tooltip, configuration[].label, commands[].title et title à l'intérieur de menus. Écrivez-les dans la langue de vos utilisateurs cibles.
04Modèle d'autorisation
permissions doit refléter honnêtement ce que fait réellement le code. La page de consentement de pré-installation répertorie chacun d'entre eux afin que les utilisateurs puissent décider d'installer ou non ; Marketplace Review vérifie également la déclaration par rapport au code.
| Autorisation | Quand il faut le déclarer | Comment l'hôte le traite |
|---|---|---|
filesystem | Lecture ou écriture de fichiers utilisateur (lecture du code du projet, génération de documents, stockage des données dans le dossier personnel) | Consentement éclairé, montré à l'utilisateur. |
network | Faire toute requête réseau (API tierces, téléchargements) | Consentement éclairé, montré à l'utilisateur. |
notifications | Affichage des notifications système via le RPC inversé show_notification | Enforced : l'appeler sans la déclaration renvoie host_error et aucune notification n'est affichée. |
filesystem et network sont actuellement des déclarations au niveau du consentement, pas un bac à sable d'exécution : l'hôte n'intercepte pas fs ou fetch. C'est exactement pourquoi les déclarations doivent être honnêtes. Les plugins qui sous-déclarent sont rejetés lors de l'examen du marché et perdent la confiance des utilisateurs lorsqu'ils sont découverts. Ne pas non plus trop déclarer (les autorisations inutilisées font hésiter les utilisateurs).Confidentialité et données
context.cwd est le dossier du projet de l'utilisateur et peut contenir du code source et une configuration sensible ; les arguments de l'outil peuvent contenir la conversation de l'utilisateur. N'envoyez pas ces données sur le réseau à moins que la fonctionnalité ne l'exige, et lorsque vous le faites, indiquez en description et summary ce qui est envoyé et à qui. Conservez les données persistantes du plugin dans un fichier sous le dossier personnel de l'utilisateur nommé d'après l'identifiant du plugin, afin qu'il soit facile à trouver lors de la désinstallation.
05Outils et protocole d'appel
Déclaration
| Champ | Description |
|---|---|
name | Nom de l'outil en lettres minuscules et traits de soulignement, unique dans toute l'application (il est enregistré avec le modèle aux côtés des outils intégrés et des outils d'autres plugins). |
description | Description du modèle (anglais). Énoncez trois choses : ce que fait l'outil, ce que dit l'utilisateur quand il doit être appelé et quand il ne doit pas être appelé. Il s’agit du champ le plus important pour savoir si l’IA utilise votre plugin. |
summary | Résumé lisible en une ligne affiché sur la page de consentement. Facultatif mais fortement recommandé ; sinon, une description tronquée est affichée à la place. |
parameters | Objet de schéma JSON standard avec un description sur chaque propriété. Le modèle en remplit les arguments et l'hôte les transmet sans validation supplémentaire, alors vérifiez les champs obligatoires dans votre code. |
renderAs | Facultatif; actuellement seulement checklist : l'hôte restitue le tableau todos à partir des arguments d'appel sous forme de carte de liste de contrôle, voir ci-dessous. |
tools[] — sessionAction.tool, commands[].tool et le champ tool à l'intérieur de menus ne sont vérifiés comme étant des chaînes non vides au moment de l'installation ; l'hôte ne vérifie pas pas que le nom est déclaré en tools[] et envoie toujours un appel sous ce nom lorsque le bouton, le raccourci ou l'élément de menu est déclenché. Ainsi, une action purement déclenchée par l'interface utilisateur peut être gérée entièrement dans votre propre index.js sans jamais apparaître dans tools[] — mais l'IA ne peut alors jamais la voir ou l'appeler. Si vous souhaitez que la même action puisse être déclenchée à la fois en cliquant et par l'IA agissant sur une demande de chat, déclarez également ce même nom dans tools[], afin que les deux points d'entrée partagent un seul gestionnaire ; s'il est censé rester uniquement sur l'interface utilisateur, laissez-le non déclaré : il n'est pas nécessaire d'ajouter une entrée juste pour avoir l'air complet.Protocole de message
L'hôte envoie call_tool ; le plugin doit répondre par un tool_result ou un tool_error portant le même requestId. Un appel sans réponse dans les 30 secondes expire et le modèle reçoit une erreur.
content n'accepte que les blocs text et image (image en base64 data plus mimeType) ; les autres types sont abandonnés. details correspond à des données structurées arbitraires qui ne sont jamais transmises au modèle ; c'est pour le rendu de l'interface utilisateur de l'hôte et vos propres vues ancrées.
Résultats du fichier : fiches de fichiers
Rendu de la liste de contrôle : liste de contrôle renderAs
Rédiger une bonne description
Décrivez le déclencheur à l'impératif (« Appelez ceci lorsque l'utilisateur demande à… ») et indiquez les exclusions (« Ne pas appeler ceci pour… »). Si le résultat est un fichier, demandez au modèle de référencer le lien du fichier renvoyé plutôt que de prétendre qu'il a été généré. Si les arguments sont transmis à une API de génération externe, indiquez dans quelle langue ils doivent être. Évitez les phrases simples comme « gérer les tâches » ; le modèle ne saura pas quand utiliser l’outil.
06Vues ancrées (vues)
Une vue ancrée est une page persistante dans la barre latérale droite de la session : une icône supplémentaire apparaît dans la barre d'outils de la session et votre code HTML s'affiche à droite lorsqu'il est ouvert. L'état de la page (position de défilement, brouillons) survit au changement de session et à la réduction/développement, la même sémantique qu'une vue de la barre latérale VS Code.
| Champ | Description |
|---|---|
id | Unique au sein du plugin. |
title | Texte d'info-bulle pour l'icône (lisible par l'homme). |
icon | Choisissez dans la liste d'autorisation des hôtes : git-branch, checklist. Maintient la cohérence des icônes dans toute l’application ; les images personnalisées ne sont pas acceptées. |
entry | Fichier HTML, relatif au dossier du plugin. |
width | Largeur du panneau par défaut en option en pixels, 240 à 640, 360 par défaut. Les utilisateurs peuvent faire glisser pour redimensionner et la taille est mémorisée. |
Durée d'exécution des pages
La page s'exécute dans un bac à sable (sandbox + contextIsolation, pas de nœud, pas d'accès aux données de l'application hôte) et ne peut communiquer qu'avec son propre processus de plugin via les quelques méthodes sur window.pluginHost. Apportez vos propres styles ; Il est recommandé de suivre le schéma clair/sombre de l'application, comme dans l'exemple ci-dessous.
Modèle recommandé : lors du premier chargement, appelez l'un de vos propres outils de requête avec invoke() et demandez-lui de renvoyer des données structurées dans details ; Ensuite, poussez chaque modification du processus du plugin avec ui_push au lieu de l'interrogation. Lorsque l'IA modifie les données de la conversation, le panneau s'actualise immédiatement.
07Panneau flottant (ui)
ui: { entry, title } déclare une fenêtre flottante autonome (900 × 700) que les utilisateurs ouvrent à partir du menu "⋯" dans la liste des plugins ; il est détruit à la fermeture. L'environnement de la page et l'API window.pluginHost sont identiques aux vues ancrées, et ui_push est fourni à la fois au panneau flottant et aux vues ancrées. Adapté aux grands panneaux ouverts occasionnellement ; utilisez views pour le contenu qui doit rester à côté de la session.
08Icône de la barre d'outils de session (sessionAction)
Au plus une icône persistante par plugin. En cliquant dessus, vous appelez tool avec des arguments vides, de sorte que cet outil doit faire quelque chose de significatif sans paramètres.
| Champ | Description |
|---|---|
tool | Outil pour appeler au clic. |
icon | Nom de l’icône sur liste autorisée. |
tooltip | Survolez le texte. |
visibleTool | Facultatif. Lorsqu'il est défini, il est appelé avec des arguments vides avant le rendu et le booléen details.visible dans le résultat décide si l'icône s'affiche. Utile pour les vérifications d'exécution telles que "le dossier actuel est-il un référentiel git". |
09Paramètres (configuration)
Les entrées déclarées apparaissent sous la configuration du plugin sur la page des paramètres. L'hôte stocke les valeurs modifiées par l'utilisateur et les transmet sous la forme context.config à chaque call_tool (saisi par id, retombant à defaultValue), que l'appel provienne de l'IA, de l'icône de la barre d'outils ou de votre panneau. Vous n’avez jamais besoin de les demander.
| type | Rendu comme | Type de valeur par défaut |
|---|---|---|
select | Liste à choix unique ; les options viennent de optionsTool | string |
boolean | Interrupteur à bascule | boolean |
string | Saisie de texte, engagée sur le flou | string |
number | Saisie du numéro | number |
10Palette de commandes / raccourcis / menu contextuel
Tous les trois sont des points d'entrée différents pour « appeler un outil avec des arguments vides » ; un plugin peut en déclarer plusieurs.
| Champ | Forme | Description |
|---|---|---|
commands | { tool, icon, title }[] | Affiché dans la palette de commandes Ctrl/Cmd+K et déclenché après que l'utilisateur l'a recherché. |
keybindings | { command, key }[] | command doit être égal au tool d'une entrée dans commands[]. key utilise la notation mod+shift+g, où mod est Cmd sur macOS et Ctrl ailleurs. Les conflits avec d'autres raccourcis ne sont pas vérifiés de manière statique, choisissez donc des combinaisons inhabituelles. |
menus | { "session/context": { tool, icon, title }[] } | Ajouté au menu sur une ligne de session. Seul cet emplacement est disponible pour l'instant. |
11Analyseurs de documents (documentParsers)
Lorsque l'utilisateur dépose un fichier dans la zone de saisie, l'hôte recherche les analyseurs déclarés par les plugins activés par type MIME et transmet le contenu du fichier en base64 au toolName correspondant. Ce n'est pas un outil que l'IA décide d'appeler, alors pas répertoriez également l'outil d'analyse sous tools, sinon il sera exposé comme un outil appelable par l'IA.
12RPC inversé (host_request)
Le processus du plugin n'a pas d'API Electron. Lorsqu'il a besoin d'une réelle capacité du système, il envoie host_request à l'hôte, qui répond par host_response ou host_error. Ce canal est totalement indépendant de call_tool ; vous pouvez l'utiliser lors du traitement d'un appel d'outil ou à partir d'un minuteur.
| capability | params | result | Condition préalable |
|---|---|---|---|
show_notification | { title, body?, viewId? } | { shown: true } / { shown: false, reason: "disabled" | "unsupported" } | Nécessite l'autorisation notifications. Renvoie désactivé au lieu d'une erreur lorsque l'utilisateur a désactivé les notifications du bureau dans les paramètres. Lorsque viewId pointe vers l'une de vos vues ancrées, cliquer sur la notification amène l'application au premier plan et développe cette vue. |
render_pdf | { outputPath, title, content } | {} | le contenu est Markdown ; l'hôte restitue un PDF sur OutputPath avec son moteur de rendu intégré. |
13Cycle de vie
| Scène | Comportement |
|---|---|
| Commencer | Paresseux par défaut : non démarré avec l'application, forké au premier appel à l'un de vos outils (IA, icône de la barre d'outils, panneau, commande, analyse de document). Les plugins déclarant activationEvents: ["onStartupFinished"] démarrent juste après la fin du lancement de l'application ; utilisez-le uniquement pour les plugins qui nécessitent des minuteries en arrière-plan (rappels, sondages), pas pour les plugins d'outils ordinaires. |
| Résident | Une fois démarré, le processus reste actif et est réutilisé lors des appels d'outils. Vous pouvez mettre l'état en cache en mémoire, mais supposez qu'il peut être redémarré à tout moment. |
| Accident | Si le processus se termine de manière inattendue, l'hôte le redémarre : immédiatement, puis après 5 et 15 secondes. Après 3 échecs consécutifs, il est marqué « crashé » et n'est plus réessayé ; les utilisateurs voient le statut sur la page du plugin. Les appels en vol renvoient tous des erreurs. |
| Désactiver/désinstaller/réinstaller | Le processus est terminé et les vues ancrées et les panneaux flottants sont détruits ; une réinstallation remplace tout le dossier. |
| Journaux | Vos stdout/stderr sont écrits dans le fichier journal de l'application préfixé par l'identifiant du plugin. Un simple console.log suffit pour le débogage ; voir "Débogage et FAQ". |
ELECTRON_RUN_AS_NODE=1, cwd est le dossier d'installation du plugin et la version Node correspond à l'Electron fourni avec l'application. Ne dépendez d'aucun package installé globalement et ne présumez pas que npx existe.14Emballage et édition
Conditionnement
Zippez le dossier du plugin avec manifest.json à la racine de l'archive. Si vous avez des dépendances tierces, regroupez-les d'abord dans un seul fichier avec esbuild/webpack au lieu d'expédier l'intégralité du node_modules.
Publication sur le marché
AnBoWork → Outils → Plugins → onglet « Marketplace » → « Publier le plugin » dans le coin supérieur droit, puis téléchargez le zip. Les soumissions entrent en révision, qui vérifie que la déclaration du manifeste correspond au code (en particulier les autorisations). Une fois approuvé, d’autres utilisateurs peuvent le trouver et l’installer sur le marché, et l’IA peut installer automatiquement des plugins vérifiés pour les utilisateurs lorsqu’elle le juge nécessaire.
Mises à jour
Cliquez sur version et publiez à nouveau. L'application compare la version installée avec la version du marché et vous invite à effectuer la mise à jour ; la réinstallation conserve l'état activé et les valeurs des paramètres de l'utilisateur.
15Exemple complet : Todo Quadrant
Un vrai plugin fonctionnel (tronqué) : l'IA peut ajouter et supprimer des tâches, la barre latérale droite affiche un tableau qui s'actualise en temps réel et elle peut envoyer des rappels de notification au système. Le chaînage de ces trois éléments couvre le protocole de l'outil, les poussées de vue ancrée et le RPC inversé.
16Débogage et FAQ
| Symptôme | Causer et réparer |
|---|---|
| La validation du manifeste échoue lors de l'installation | Vérifiez chaque champ par rapport au tableau « Champs du manifeste » comme l'indique le message : format d'identifiant, main/entry ne doit pas contenir .., l'icône doit être sur la liste autorisée, la commande keybindings doit pointer vers un outil existant dans les commandes, largeur comprise entre 240 et 640. |
| L'IA n'appelle jamais mon outil | Presque toujours un problème description : le déclencheur n'est pas clair ou il n'est pas écrit en anglais. Voir « Rédiger une bonne description ». Vérifiez également que le nom de l'outil n'entre pas en collision avec un autre outil. |
| Expiration du délai d'appel (30 s) | Le script d'entrée n'a pas répondu par tool_result. Habituellement, requestId n'a pas été renvoyé, le message type est mal orthographié ou le script est lancé au démarrage et s'arrête. Recherchez les lignes préfixées par [plugin:your-id] dans le journal de l'application. |
| L'état du plugin indique "planté" | 3 démarrages ratés consécutifs. Généralement un require d'un paquet manquant ; l'exécution de node index.js dans le dossier du plugin le reproduit. Après la correction, désactivez et réactivez le plugin sur la page du plugin. |
| Le panneau s'ouvre vide | Mauvais chemin entry ou erreur JS sur la page. La page s'exécute dans un bac à sable sans le require de Node ; seul window.pluginHost est disponible. |
| La notification n'apparaît pas | Vérifiez dans l'ordre : le manifeste déclare notifications ; le résultat n'est pas shown:false (l'utilisateur a désactivé les notifications sur le bureau) ; le système d'exploitation autorise les notifications de AnBoWork. |
| Les valeurs des paramètres ne sont pas lisibles | Les valeurs sont en message.context.config[id], pas en params. |
Emplacement du fichier journal
| Système d'exploitation | Chemin |
|---|---|
| macOS | ~/Library/Logs/AnBoWork/main.log |
| Windows | %USERPROFILE%\AppData\Roaming\AnBoWork\logs\main.log |