Sistema de plugins: instalación y Galería
Cómo instala, actualiza y quita NOPAL un plugin, y qué hace falta para que aparezca en la Galería.
El catálogo curado
La Galería muestra los plugins de backend/plugin_catalog.json, un archivo curado por el proyecto que vive en el core. Cada entrada describe un plugin para la Galería y apunta a su repositorio:
| Campo | Uso |
|---|---|
id | Identificador; es el nombre de la carpeta plugins/<id>/ |
name, description, long_description, publisher, category | Textos de la tarjeta |
icon, accent, banner_image | Aspecto de la tarjeta |
compatibility, permissions | Etiquetas y permisos mostrados |
version | Versión anunciada. Para un plugin ya instalado manda la del manifiesto |
python_requires | Opcional. Permite saber el requisito antes de clonar |
availability | available (instalable) o coming_soon (no instalable) |
pricing | {"type": "free"}. Un tipo distinto de free se rechaza |
repo_url | Repositorio de git que se clona |
featured, size | Destacado y tamaño mostrado |
Los textos de la Galería pueden traducirse con claves pluginCatalog_<id>_<campo> (los guiones del id pasan a guiones bajos, por ejemplo pluginCatalog_matriz_led_name) en los archivos de traducción del core; si no existe la clave, se usa el texto del catálogo.
Dos entradas figuran como coming_soon (gcode-optimizer, material-library). Son anuncios, no plugins instalables.
Instalar (solo administradores)
POST /api/plugins/{id}/install. NOPAL comprueba, en este orden:
- Que el plugin esté en el catálogo. Si no, responde 404.
- Que
availabilityseaavailable. Si no, 409. - Que
pricing.typeseafree. Los plugins de pago responden 501: todavía no existe el servidor de licencias. - Que haya
repo_url. - Que el Python del servidor cumpla
python_requiresdel catálogo (409 si no). - Que el plugin no esté ya instalado (409).
Después ejecuta git clone --depth 1 <repo_url> plugins/<id> (con un límite de 60 s) y:
- Si el repositorio no tiene un
nopal-plugin.jsonválido en la raíz, borra lo clonado y falla. No deja carpetas a medio instalar. - Si el manifiesto exige más Python que el servidor, elimina el plugin y falla.
- Si todo va bien, anota el plugin en
data/plugins/installed.jsoncon su versión,enabled: truey la fecha.
Actualizar (solo administradores)
POST /api/plugins/{id}/update ejecuta git fetch y git pull --ff-only sobre la rama actual del plugin, y compara el SHA antes y después.
- Si
ff-onlyfalla (cambios locales o historial divergente), no se actualiza. - Si cambió algo dentro de
backend/, la respuesta llevabackend_changed: truey la interfaz avisa de que hay que reiniciar NOPAL para cargar el código nuevo. - Si solo cambió el frontend, la interfaz recarga la página.
Desinstalar (solo administradores)
DELETE /api/plugins/{id} borra la entrada de installed.json y la carpeta plugins/<id>/. La interfaz ejecuta además el unmount() del plugin y quita su script y su estilo.
El estado que el plugin guardó (por ejemplo camera_registry.json o data/accessories/…) no se borra.
Instalación manual para desarrollar
Para probar un plugin sin pasar por la Galería:
- Copia (o clona) tu plugin en
plugins/<id>/, en la carpeta de NOPAL. - Añade su entrada a
data/plugins/installed.json:
{
"mi-plugin": {
"version": "0.1.0",
"enabled": true,
"installed_at": "2026-01-01T00:00:00+00:00"
}
}
- Reinicia NOPAL. El backend se carga al arrancar.
El backend se carga a partir de installed.json. Pero la lista que reparte la interfaz de los plugins sale del catálogo: un plugin sin entrada en plugin_catalog.json no recibe su frontend. Para desarrollarlo en local, añade temporalmente una entrada al catálogo con su mismo id.
Publicar un plugin en la Galería
Hoy no existe un mecanismo de publicación para terceros. Para que un plugin aparezca en la Galería es necesario que su entrada se añada a backend/plugin_catalog.json del core, es decir, un cambio aceptado por el proyecto. Un sistema de publicación abierto y los plugins de pago (que requieren un servidor de licencias) son propuestas, no funciones existentes.
Requisitos prácticos para que un plugin sea instalable:
- Un repositorio de git accesible, con
nopal-plugin.jsonen la raíz. availability: "available"ypricing.type: "free".- Compatibilidad con la versión mínima de Python del core (3.9), o un
python_requiresque lo declare.
Comprobación de compatibilidad en CI
El trabajo plugins-compat del CI del core clona la punta de la rama por defecto de cada plugin del catálogo, ejecuta sus pruebas con Python 3.9 y comprueba que su backend carga con el cargador real. Un plugin con python_requires incompatible con ese Python se marca N/A.