Écrire des plugins OpenCode
Utilisez cette skill pour implémenter des plugins OpenCode de qualité production. Traitez les types exportés et le runtime du repository comme autoritaires, car les APIs de plugin évoluent et la documentation publique peut être en retard.
Commencer ici
- Décidez quel runtime possède la fonctionnalité.
- Lisez le type public pertinent avant d'écrire du code.
- Trouvez un exemple in-repository ciblé utilisant la même API.
- Implémentez le plus petit module spécifique à la cible.
- Testez le chargement, le comportement, la défaillance et le nettoyage dans le package possédant.
| Besoin | Cible du plugin | Import | Configuration |
|---|---|---|---|
| Hooks, tools, auth, providers, paramètres model, environnement shell | Server | @opencode-ai/plugin |
opencode.json ou .opencode/plugins/*.{ts,js} auto-découvert |
| Commandes, keybindings, routes, dialogs, slots, thèmes, notifications | TUI | @opencode-ai/plugin/tui |
Entrée plugin explicite dans tui.json |
| Les deux | Deux entrypoints cible-only | Les deux imports dans des fichiers séparés | Package exporte ./server et ./tui |
N'exportez jamais server et tui depuis le même module. N'utilisez pas les server event hooks comme substitut aux APIs TUI interactives.
Vérifier le contrat actuel
Lisez ces fichiers avant d'implémenter un comportement méconnu :
packages/plugin/src/index.ts: types de plugin server et hook autoritaires.packages/plugin/src/tool.ts: schema custom tool, contexte, permission, métadonnées, attachments, et types de résultat.packages/plugin/src/tui.ts: API TUI autoritaire et types de module.packages/opencode/specs/tui-plugins.md: chargement TUI, packaging, lifecycle, et sémantique d'API.packages/opencode/src/plugin/shared.ts: validation de cible, IDs, et résolution d'entrypoint.packages/opencode/src/plugin/loader.ts: installation, compatibilité, et comportement d'import.
Si ceux-ci divergent d'exemples ou de docs site, suivez les types exportés et le comportement runtime, puis mettez à jour la documentation obsolète si approprié.
Choisir une forme de module
Préférez l'objet module explicite pour les nouveaux plugins server :
import type { Plugin, PluginModule } from '@opencode-ai/plugin';
const server: Plugin = async ({ client, directory }, options) => ({
dispose: async () => {},
});
export default {
id: 'acme.example',
server,
} satisfies PluginModule & { id: string };
Les plugins server-only locaux hérités peuvent exporter une fonction plugin directement. Dans un module hérité, chaque export nommé distinct est interprété comme un plugin, donc n'exportez pas de constantes non liées. Préférez un objet module par défaut pour le nouveau code.
Les plugins TUI utilisent toujours un objet module par défaut :
/** @jsxImportSource @opentui/solid */
import type { TuiPlugin, TuiPluginModule } from '@opencode-ai/plugin/tui';
const tui: TuiPlugin = async (api) => {
api.ui.toast({ message: 'Plugin loaded' });
};
export default {
id: 'acme.example-tui',
tui,
} satisfies TuiPluginModule & { id: string };
Les plugins fichier nécessitent un id stable et non-vide. Les plugins npm peuvent dériver l'ID du nom du package, mais un ID explicite namespacé rend l'état, les diagnostiques et la gestion des collisions plus clairs.
Règles d'ingénierie
- Utilisez TypeScript et
satisfiescontre le type plugin public. - Parsez et validez
options; elles arrivent commeRecord<string, unknown>non validé. - Namespacez les IDs de plugin, les IDs de commande, les noms de route, les modes, les noms de slot, et les clés KV partagées.
- Utilisez le répertoire fourni par le contexte plugin ou tool, pas
process.cwd(). - Honorez
AbortSignalpour le travail long ou annulable. - Utilisez
client.app.log()pour le logging server structuré au lieu deconsole.log. - Demandez la permission avant un travail custom-tool sensible ou conséquent.
- Gardez les notifications privacy-safe ; n'exposez pas les prompts, secrets, chemins, commandes, ou erreurs brutes.
- Enregistrez seulement les hooks et ressources UI nécessaires. Évitez les large event subscriptions quand un hook spécifique existe.
- Rendez le nettoyage borné, idempotent, et sûr après une initialisation partielle.
- Ne dépendez pas de l'ordre de chargement non documenté pour résoudre les conflits de propriété.
Workflow de test
Les tests de plugin server appartiennent sous packages/opencode/test/plugin/ ou le sous-système propriétaire le plus proche. Les tests runtime TUI appartiennent sous packages/opencode/test/cli/tui/ ; les tests TUI au niveau composant peuvent appartenir à packages/tui.
Testez au minimum :
- le chargement valide et la sélection cible/entrypoint ;
- les options configurées et les options malformées ;
- le comportement observable, pas une duplication de la logique d'implémentation ;
- le comportement d'abort, défaillance, et initialisation partielle ;
- le nettoyage ou la disposition ;
- les IDs dupliqués ou enregistrements en double quand pertinent ;
- le packaging local et npm quand vous publiez.
Exécutez les tests depuis le répertoire du package, jamais depuis la racine du repository. Utilisez bun typecheck depuis le package propriétaire pour la vérification de type.
Checklist de review
- La fonctionnalité est dans le bon runtime server ou TUI.
- La forme du module et le chemin d'import correspondent à la cible.
- Les entrypoints server et TUI sont séparés.
- Les IDs et clés persistantes sont stables et namespacés.
- Les options et données externes sont validées.
- La mutation de sortie des hooks préserve les changements des autres plugins.
- Les tools utilisent correctement le répertoire de contexte, la permission, les métadonnées, et l'abort.
- Les keybindings TUI sont gatés par mode sauf s'intentionnellement globaux.
- Les ressources TUI et effets secondaires custom sont disposés.
- Les exports du package,
engines.opencode, et la cible config sont corrects. - Les tests couvrent le comportement et le lifecycle.
Références
- Server plugins : hooks, custom tools, lifecycle, et exemples.
- TUI plugins : keymaps, routes, dialogs, slots, state, et lifecycle.
- Packaging and testing : config, package exports, compatibilité, et emplacements de test.