advanced⏱60 minLección 1 de 5
Desarrollo de Plugins desde Cero
Construye plugins personalizados de OpenCode desde cero. Aprende la arquitectura de plugins, eventos del ciclo de vida, superficie de API y cómo crear plugins que extiendan las capacidades de OpenCode.
Desarrollo de Plugins desde Cero
Arquitectura de Plugins
Los plugins son paquetes de Node.js que extienden la funcionalidad de OpenCode:
.opencode/plugins/my-plugin/
├── package.json
├── src/
│ └── index.ts
├── assets/
├── examples/
├── references/
└── scripts/
Ciclo de Vida del Plugin
| Fase | Descripción |
|---|---|
| Carga | El plugin es descubierto y cargado |
| Inicializar | El plugin configura recursos |
| Registrar | Los handlers de eventos son registrados |
| Activo | El plugin escucha eventos |
| Apagado | Limpieza y liberación de recursos |
Creando un Plugin
Paso 1: Inicializar Paquete
bash
mkdir -p .opencode/plugins/code-metrics
cd .opencode/plugins/code-metrics
npm init -yPaso 2: Crear Entrada del Plugin
Crear src/index.ts:
typescript
import { Plugin, PluginContext } from "opencode";
export default class CodeMetricsPlugin implements Plugin {
name = "code-metrics";
version = "1.0.0";
async initialize(context: PluginContext) {
console.log("Plugin de Métricas de Código inicializado");
}
async onFileWrite(filePath: string, content: string) {
const lines = content.split("\n").length;
const bytes = Buffer.byteLength(content);
console.log(`Archivo escrito: ${filePath}`);
console.log(` Líneas: ${lines}`);
console.log(` Bytes: ${bytes}`);
return { lines, bytes };
}
async onToolExecute(tool: string, args: any, result: any) {
// Registrar métricas de uso de herramientas
return {
tool,
timestamp: Date.now(),
success: !result.error
};
}
async shutdown() {
console.log("Plugin de Métricas de Código apagándose");
}
}Paso 3: Registrar Plugin
Agregar a opencode.json:
json
{
"plugins": {
"code-metrics": {
"path": ".opencode/plugins/code-metrics",
"enabled": true
}
}
}Superficie de API del Plugin
Eventos Disponibles
| Evento | Parámetros | Retorno |
|---|---|---|
session.start | sessionId | void |
session.end | sessionId | void |
file.read | path, content | content |
file.write | path, content | content |
file.edit | path, old, new | new |
tool.execute.before | tool, args | args |
tool.execute.after | tool, args, result | result |
agent.route | request, agent | agent |
Métodos de Contexto
typescript
context.log(message: string, level: "info" | "warn" | "error");
context.getConfig(key: string): any;
context.setConfig(key: string, value: any): void;
context.getMemory(key: string): any;
context.setMemory(key: string, value: any): void;Ejemplo: Plugin de Escáner de Seguridad
typescript
import { Plugin, PluginContext } from "opencode";
const DANGEROUS_PATTERNS = [
/eval\s*\(/,
/new\s+Function\s*\(/,
/process\.exit/,
/require\s*\(\s*['"]child_process['"]\s*\)/,
];
export default class SecurityScannerPlugin implements Plugin {
name = "security-scanner";
version = "1.0.0";
async onFileWrite(path: string, content: string) {
const warnings: string[] = [];
for (const pattern of DANGEROUS_PATTERNS) {
if (pattern.test(content)) {
warnings.push(`Patrón potencialmente peligroso: ${pattern.source}`);
}
}
if (warnings.length > 0) {
console.warn(`Advertencias de seguridad para ${path}:`);
warnings.forEach(w => console.warn(` - ${w}`));
}
return { warnings };
}
}Probando Plugins
Pruebas Unitarias
typescript
import CodeMetricsPlugin from "../src/index";
describe("CodeMetricsPlugin", () => {
let plugin: CodeMetricsPlugin;
beforeEach(() => {
plugin = new CodeMetricsPlugin();
});
it("debería contar líneas correctamente", async () => {
const result = await plugin.onFileWrite("test.ts", "line1\nline2\nline3");
expect(result.lines).toBe(3);
});
it("debería contar bytes correctamente", async () => {
const result = await plugin.onFileWrite("test.ts", "hello");
expect(result.bytes).toBe(5);
});
});Pruebas de Integración
bash
npm testMejores Prácticas
| Práctica | Razón |
|---|---|
| Responsabilidad única | Un plugin, un propósito |
| Manejo de errores | Degradación elegante |
| Rendimiento | No bloquear el hilo principal |
| Registro | Información de depuración útil |
| Configuración | Hacer el comportamiento ajustable |
Practice Questions
Practice Question
¿Cuál es la primera fase en el ciclo de vida del plugin?
Practice Question
¿Qué evento se dispara antes de que se escriba un archivo?
Practice Question
¿Dónde se deben registrar los plugins?
Practice Question
¿Qué debe hacer un plugin durante el apagado?
Practice Question
¿Cómo acceden los plugins a la configuración?
Success
Key Takeaways
- Los plugins son paquetes de Node.js que extienden la funcionalidad de OpenCode
- El ciclo de vida incluye fases de Carga, Inicializar, Registrar, Activo y Apagado
- Usa el evento file.write para validar o transformar contenido antes de guardar
- Registra plugins en opencode.json bajo la clave plugins
- Sigue el principio de responsabilidad única para el diseño de plugins
- Siempre limpia recursos durante el apagado
- Prueba plugins con pruebas unitarias y de integración
Progreso20%