green-dalii/dsh-plugin-dev-skill

Un conjunto de habilidades que permite a cualquier agente desarrollar plugins para DeepSeek Harness (DSH) de forma correcta, eficiente y conforme a las convenciones oficiales.

¿Qué es dsh-plugin-dev-skill?

Esta habilidad proporciona una guía completa para que los agentes de IA (como Claude Code, Cursor o Codex) desarrollen plugins para DeepSeek Harness (DSH). DSH es un SDK de Agent Harness construido sobre el framework Cordis, donde cada capacidad (herramientas, adaptadores LLM, servicios) es un componente conectado a un contexto compartido. La habilidad cubre desde conceptos fundamentales como efectos reversibles y coefectos reactivos, hasta patrones de implementación detallados para herramientas, servicios, adaptadores LLM y más. Incluye plantillas de código listas para usar, reglas estrictas para la gestión de recursos (todo debe registrarse a través del contexto para una limpieza automática), y ejemplos prácticos para configurar, empaquetar y distribuir plugins. Es útil para cualquier tarea que involucre la creación, modificación o depuración de plugins en el ecosistema DeepSeek Harness.

Compatible con✓Claude Code✓Codex CLI~Cursor
npx skills add green-dalii/dsh-plugin-dev-skill

Installed? Explore more Productividad y colaboración skills: steipete/gemini, steipete/gh-issues, steipete/skill-creator · View all 6 →

Preguntar en tu IA favorita

Abre un nuevo chat con esta habilidad de agente ya precargada.

Documentación

Habilidad de Desarrollo de Plugins para DeepSeek Harness

Permite que cualquier agente desarrolle plugins para DeepSeek Harness (DSH) de forma correcta, eficiente y conforme a las normas oficiales. Esta habilidad es el manual de operación para el desarrollo de plugins DSH: primero se presentan el modelo mental y las reglas de hierro, luego las plantillas de código y el proceso paso a paso que se pueden copiar directamente, y finalmente la lista de verificación. Para profundizar, consulte los documentos resumidos en el directorio References/.


0. Cuándo usar esta habilidad

Esta habilidad debe cargarse cuando la tarea implique cualquiera de los siguientes:

  • Escribir, modificar o depurar plugins (tool, adaptador LLM, proveedor de servicios, hooks, UI, puente de protocolo, etc.) para DeepSeek Harness
  • Escribir o modificar las configuraciones cordis.yml / cordis.patch.yml / dsh.profile / dsh.bundle
  • Usar dsh plugin ... para instalar, eliminar o empaquetar plugins
  • Comprender servicios como ctx.tools, ctx.llm, ctx.agents, ctx.sessions o eventos como tools/*, agent/*, session/event en DSH
  • Investigar cómo funciona el modelo de plugins de DSH (framework Cordis)

Lea primero todo este SKILL.md y luego comience a trabajar. Antes de comenzar, lea los archivos cordis.yml / profile / código fuente relacionados existentes en el proyecto para confirmar las convenciones actuales.


1. Modelo Mental: DSH es un sistema de plugins construido sobre Cordis

En una frase: DeepSeek Harness es un SDK de Agent Harness donde cada capacidad (herramientas, adaptadores LLM, acceso a archivos, el propio bucle del agente) es un plugin (componente) que se monta en un contexto compartido.

Tres conceptos clave (del artículo 'A Programming Paradigm for Spatiotemporal Composability', consulte References/10-spatiotemporal.md):

ConceptoSignificadoManifestación en el código
Efecto reversible (revertible effect)Cada modificación del componente al entorno compartido lleva una operación inversa; el runtime la rastrea y la restaura en orden LIFO cuando se descarga el componentectx.effect(() => () => cleanup); ctx.on(), ctx.tools.register(), etc. son efectos que se deshacen automáticamente al descargarse
Coefecto reactivo (reactive coeffect)El componente declara de qué servicios depende; cuando los servicios aparecen/desaparecen/cambian de implementación, el componente se activa/desactiva/recarga automáticamenteexport const inject = ['tools']; cuando la dependencia desaparece, el plugin se elimina automáticamente; cuando se restaura, se recarga automáticamente
Fiber (instancia de componente)Cada instancia de plugin cargada es un fiber, con una máquina de estados de ciclo de vidaPENDING → LOADING → ACTIVE → UNLOADING → DISPOSED (si apply lanza un error, pasa a FAILED)

Reglas de hierro derivadas:

  1. Todo registro debe realizarse a través de ctx (ctx.on / ctx.tools.register / ctx.effect / ctx.plugin / ctx.provide). Todo lo que se registra a través de ctx se limpia automáticamente al descargarse. Nunca use removeListener / clearInterval manualmente.
  2. Cualquier recurso no gestionado por ctx (conexiones de red, temporizadores propios, manejadores de archivos, watchers) debe encapsularse en ctx.effect(() => { ...; return () => cleanup }).
  3. Las dependencias deben declararse (inject). No use ctx.get() para detectar dependencias obligatorias ni asuma el orden de carga; el orden lo determinan las dependencias, no el orden de las líneas en cordis.yml.
  4. La configuración debe ser configurable: cualquier parámetro que pueda tener un valor diferente en diferentes implementaciones debe ser un campo Config. No debe haber valores codificados (criterio: ¿se puede cambiar este valor en cordis.yml sin cambiar el código?).
  5. Los errores de configuración deben ser evidentes: use el esquema de Schemastery para validar en el momento de la carga. Una configuración no válida debe provocar un error de carga claro y no permitir la ejecución en mal estado.
  6. Los callbacks deben ser reproducibles/recargables en caliente: los callbacks de presentación (output.render, presentCall, presentResult) deben ser funciones puras; los plugins pueden ser descargados y recargados por HMR en cualquier momento, no dependa del estado global a través de las recargas.

2. Entorno y cadena de herramientas

  • Los plugins son módulos TypeScript (también se acepta JavaScript) que se ejecutan en un entorno Node.js ESM.
  • Paquetes de dependencia principales (todos del ámbito @deepseek-ai):
    • @deepseek-ai/cordis — Framework de plugins (contexto, fiber, eventos, registro)
    • @deepseek-ai/schemastery — Validación de esquemas de configuración (implementación de Standard Schema)
    • @deepseek-ai/dsh-tools — defineTool y servicio de registro de herramientas
    • @deepseek-ai/dsh-llm — LlmAdapter, StreamChunk, GenerateOptions, CallId
    • Paquetes de costuras de capacidades: dsh-shell, dsh-session, dsh-agent, dsh-system-prompt, dsh-fs, dsh-jobs, dsh-credentials, etc. (lista completa en References/08-capability-layering.md)
  • Dos puntos de entrada de desarrollo (a elegir):
    • Con el código fuente descargado (recomendado, para tutoriales): clone deepseek-ai/deepseek-harness, pnpm install, inicie la interfaz web con pnpm dsh web --patch <tu-cordis.yml>, ejecute ejemplos de tutoriales de Cordis puro con node --import tsx ../../vendor/cordis/bin.js.
    • Con la CLI instalada: dsh --profile <nombre> ... para iniciar un perfil, dsh plugin --profile <nombre> <argumentos pnpm> para gestionar plugins.

3. La forma mínima de un plugin (aprende esto primero)

Un plugin es un módulo que exporta una función apply:

import type { Context } from '@deepseek-ai/cordis'

export const name = 'my-plugin'   // Opcional, solo para visualización en diagnóstico

export function apply(ctx: Context) {
  // Aquí se registran las capacidades
}

Se monta a través de cordis.yml o patch:

- name: './src/my-plugin.ts'        # Ruta relativa (código fuente/desarrollo) o nombre del paquete npm (después de la instalación)
  id: my-plugin                     # Identificador estable, el cargador lo usa para la conciliación de configuración

Tres formas de plugin

  1. Forma de función (recomendada por defecto):
    export const name = 'greet-tool'
    export const inject = ['tools']
    export function apply(ctx: Context) { /* ... */ }
    
  2. Forma de objeto: export default { name, inject, apply(ctx) {} }
  3. Forma de clase (cuando se necesita proporcionar un servicio): export default class MyService extends Service { constructor(ctx) { super(ctx, 'myService') } }

Hasta que se necesite proporcionar un servicio, use siempre la forma de función.


4. Desarrollo de una Herramienta (la tarea más frecuente)

Las herramientas se registran en ctx.tools usando defineTool. Plantilla (se puede copiar directamente):

import type { Context } from '@deepseek-ai/cordis'
import { defineTool } from '@deepseek-ai/dsh-tools'

export const name = 'my-tool'
export const inject = ['tools']

export function apply(ctx: Context) {
  ctx.tools.register(defineTool({
    name: 'my_tool',                                  // Nombre de la herramienta visto por el modelo (convención snake_case)
    description: 'Una frase sobre lo que hace.',  // Descripción funcional vista por el modelo, debe ser específica y clara sobre cuándo usarla
    parameters: {
      path: { type: 'string', required: true, description: 'Qué significa el parámetro' },
      limit: { type: 'number' },                      // Sin 'required' significa opcional
    },
    output: {
      schema: { type: 'string' },                     // Declara el valor JSON canónico devuelto por execute
      render: (_args, value) => [{ type: 'text', text: value }],  // Convierte el valor a contenido visible para el modelo
    },
    async execute(args, exec) {
      // args ya ha sido validado por el esquema y se han inferido los tipos
      // exec.signal es la señal de cancelación; las tareas largas deben responder a ella
      return `resultado para ${args.path}`
    },
  }))
}

Contrato completo de defineTool (debe cumplirse)

  • parameters: Mapa de esquemas de parámetros; la raíz es un objeto abierto implícito. Cada propiedad puede tener required: true. Soporta string/number/integer/boolean/null/array/object/oneOf; los nodos de objeto explícitos deben declarar additionalProperties: true | false.
  • output.schema: Declara el valor JSON canónico que devuelve execute (objeto/array/escalar/null). Esta es la API para llamadas programáticas (el await tools.xxx() en Code Mode); debe diseñarse para devolver directamente identificadores y campos; la explicación orientada a humanos va en output.render.
  • execute(args, exec):
    • args ya está validado en tiempo de ejecución, pero las restricciones que no se pueden expresar con el DSL del esquema (cadena no vacía, número positivo, entre campos) deben manejarse con throw new Error(...).
    • Devuelve el valor canónico declarado en output.schema. No devuelva bloques de contenido, no obligue a la parte llamante a analizar identificadores del lenguaje natural.
    • Obedezca exec.signal: cancele el trabajo en curso cuando se active la señal.
    • Fallos de infraestructura (excepción/valor de retorno no válido) → el resultado se marca como isError. Éxito pero resultado no ideal (por ejemplo, código de salida distinto de cero) → devuelva el valor canónico y explíquelo en render.
  • output.render(args, value): Función pura que convierte el valor canónico en ContentBlock[] (texto que ve el modelo). Nunca haga E/S, ni lea el estado de la sesión aquí.
  • Opcional output.presentationMeta(args, value): Deriva metadatos de interfaz de usuario reproducibles a partir del valor canónico (función pura).
  • Opcional presentCall(args) / presentResult(args, result): Declara la intención de renderizado de la tarjeta de la herramienta en la interfaz de usuario (card: 'generic' | 'terminal' | 'diff' | 'search' | 'web' | 'read'). Deben ser funciones puras (se ejecutan tanto en el flujo en tiempo real como en la reproducción de la sesión), no hagan E/S.
  • No incluya metadatos de tiempo de ejecución como timeoutMs, isConcurrencySafe, finalizeContent como esquema visible para el modelo; no se filtrarán al modelo.
  • Los parámetros son inmutables: trate args como de solo lectura; después de registrarlos, no modifique el esquema ni reemplace los callbacks.

Tareas de larga duración (tareas en segundo plano)

Para soportar run_in_background:

const jobs = ctx.get('jobs')
if (!jobs) throw new Error('tareas en segundo plano no disponibles: cargue @deepseek-ai/dsh-jobs')
return {
  kind: 'background',
  jobId: jobs.start({
    kind: 'my-work',
    label: args.command,
    ...exec.agent ? { owner: exec.agent } : {},
    run: () => { /* Devuelve { cancel, done, readOutput? } */ },
  }),
}

Puntos clave: después de publicar jobId, use la señal de cancelación propia de la tarea (gestionada por job_kill / owner dispose), ya no use exec.signal; el esquema de salida debe poder contener un identificador canónico como { kind: 'background', jobId }. Consulte References/03-tools.md y la implementación de @deepseek-ai/dsh-tool-bash.

Estrategias de ejecución de herramientas (puntos de extensión, usar según sea necesario)

Punto de extensiónModoUso
tools/pre-executewaterfallPermitir/denegar/preguntar estrategias (control de acceso); devuelve {kind:'allow'} / {kind:'deny',reason} / {kind:'ask'}
ctx.tools.guard()Guardia monótonaDenegación final, los oyentes posteriores no pueden revertirla (devolver reason significa denegación)
tools/executewaterfallEnvolver la distribución: timeout/reintentos/métricas; puede reemplazar exec.signal pero no se puede eliminar
tools/post-executewaterfallReemplazar contenido/valor, evitar resultados, anexar contexto del modelo
tools/resultemitObservación de solo lectura del resultado final inmutable (registro, auditoría)

No integre las estrategias en la herramienta; coloque las estrategias de implementación en plugins de hooks (plugins Cordis normales que escuchan estos eventos, como el ejemplo de control de acceso en References/11-cookbook.md).


5. Configuración de plugins (Schemastery)

El plugin exporta Config (interfaz TypeScript del mismo nombre + esquema Schemastery); Cordis valida y llena los valores por defecto antes de apply:

import type { Context } from '@deepseek-ai/cordis'
import Schema from '@deepseek-ai/schemastery'

export interface Config {
  greeting: string
  maxRetries: number
  verbose?: boolean
}

export const Config: Schema<Config> = Schema.object({
  greeting: Schema.string().default('Hola'),
  maxRetries: Schema.number().default(3),
  verbose: Schema.boolean().default(false),
})

export function apply(ctx: Context, config: Config) {
  // config siempre está completo y validado
}

Pasar configuración en cordis.yml:

- name: './src/my-plugin.ts'
  config:
    greeting: 'Hola'
    maxRetries: 5

Puntos clave:

  • Config debe ser un objeto Standard Schema (construido con Schemastery), no puede exportar un objeto simple.
  • Constructores comunes: Schema.string().required() / .default(x), Schema.number(), Schema.boolean(), Schema.array(String), Schema.union(['a','b']), Schema.object({...}) anidados.
  • Soporta expresiones !!js evaluadas en tiempo de carga (por ejemplo, greeting: !!js process.env.GREETING ?? 'Hola'); !!js solo es válido para los campos config y disabled.
  • Los cambios de configuración activan HMR: la instancia anterior se descarga (los registros se limpian automáticamente) → se carga la nueva instancia. No almacene en caché la configuración fuera del plugin.

6. Servicios y dependencias (desarrollo del lado del servidor)

Uso de servicios (consumidor)

export const inject = ['tools']        // Dependencia obligatoria: si no se cumple, no se carga
export function apply(ctx: Context) {
  ctx.tools.register(/* ... */)        // Garantizado que está listo en apply
}

Dependencia opcional: no escriba inject, use ctx.get('service') para detectar (devuelve undefined si no hay proveedor).

Proporcionar un servicio (proveedor)

Use una subclase de Service (plugin de forma de clase):

import { Service, type Context } from '@deepseek-ai/cordis'

declare module '@deepseek-ai/cordis' {
  interface Context {
    metrics: MetricsService     // Declaración de fusión: da tipo a ctx.metrics
  }
}

export default class MetricsService extends Service {
  static inject = ['llm']       // Los servicios también pueden depender de otros servicios
  constructor(ctx: Context) {
    super(ctx, 'metrics')       // 'metrics' es el nombre del servicio
  }
  record(event: string, value: number) { /* ... */ }
}

export const name = 'metrics'
export function apply(ctx: Context) {
  ctx.plugin(MetricsService)
}

API de bajo nivel (no común pero debe conocer): ctx.provide(name, value) registra una implementación de servicio (efecto, se da de baja automáticamente al descargar), ctx.set/get para leer/escribir almacenamiento, ctx.accessor para definir propiedades computadas, ctx.mixin para montar miembros del servicio en ctx.

Semántica del comportamiento del servicio (comprender más que memorizar)

  • inject no es una verificación de arranque única: si un servicio obligatorio desaparece durante la ejecución, el plugin dependiente se elimina automáticamente; si el servicio se restaura, se recarga automáticamente. Esto garantiza que el consumidor nunca tenga una referencia a un servicio descargado.
  • Los nombres de servicio son un espacio de nombres global plano: tools, llm, etc. ya están ocupados; los nombres de servicio propios deben tener un prefijo distintivo (por ejemplo, myCap, metrics).
  • Aislamiento de servicios: en cordis.yml, use group + isolate para que diferentes grupos de plugins vean diferentes instancias del mismo nombre de servicio (por ejemplo, dos grupos con proveedores de shell configurados con diferentes timeouts).

7. Sistema de eventos (comunicación entre plugins)

Modos de distribución (parte del nombre del evento, debe elegirse correctamente)

ModoLlamadaSemántica
emitctx.emit(name, ...args)Síncrono, no espera ni recoge valores de retorno
parallelawait ctx.parallel(...)Todos los oyentes se ejecutan en paralelo y se espera
serialawait ctx.serial(...)Se ejecuta en orden, el primer valor no null/false/undefined gana y detiene la ejecución
bailctx.bail(...)Versión síncrona de serial
waterfallawait ctx.waterfall(name, ...args, next)Middleware envolvente; los oyentes reciben next, envuelven el valor de retorno descendente

Regla de hierro de waterfall: los oyentes que solo observan/anotan deben llamar a next(); no llamar a next() y devolver directamente = cortocircuito intencionado (veto/intercepción). Olvidar llamar a next() consumirá silenciosamente el comportamiento predeterminado descendente.

Eventos con seguridad de tipos

declare module '@deepseek-ai/cordis' {
  interface Events {
    'my-plugin/ready': (payload: { id: string }) => void
    'my-plugin/check': (input: string) => boolean | undefined
  }
}

Convención de nombres de eventos: namespace/action (por ejemplo, agent/step, tools/result, session/event). Los oyentes se registran con ctx.on() y se limpian automáticamente al descargar el plugin.

Eventos comunes de Harness (se usan a menudo en el desarrollo)

  • tools/pre-execute / tools/execute / tools/post-execute / tools/result — Canalización de herramientas (ver tabla anterior)
  • agent/* (agent/request, agent/pre-step, agent/session-start, agent/turn-stopping, etc.) — Ciclo de vida del agente y construcción de solicitudes
  • session/event — Flujo de eventos de sesión persistente (turn/*, step/*, tool/call, tool/result, assistant/chunk son event.type aquí, no son eventos Cordis del mismo nombre)
  • approval/request — Waterfall de aprobación
  • system-prompt/assemble — Ensamblaje completo del mensaje del sistema (retorno autoritario, el oyente tiene la responsabilidad de preservar las contribuciones existentes)

Las firmas/modos de activación completos se encuentran en los bloques cordis-surface generados por cada página de subsistema (consulte References/08-capability-layering.md).


8. Adaptadores LLM (conectar nuevos proveedores de modelos)

Un adaptador = una clase que hereda LlmAdapter e implementa stream(), que convierte las solicitudes independientes del proveedor de Harness en llamadas API específicas y las devuelve como fragmentos StreamChunk.

import type { Context } from '@deepseek-ai/cordis'
import Schema from '@deepseek-ai/schemastery'
import { LlmAdapter, type GenerateOptions, type StreamChunk } from '@deepseek-ai/dsh-llm'

class MyAdapter extends LlmAdapter {
  async *stream(options: GenerateOptions): AsyncIterable<StreamChunk> {
    // 1. options.messages → formato del proveedor
    // 2. Llamar API de transmisión (debe pasar options.signal)
    // 3. Respuesta → secuencia de StreamChunk
  }
}

export const name = 'my-llm-adapter'
export const inject = ['llm']
export const Config = Schema.object({
  apiKey: Schema.string().required(),
  providers: Schema.array(String).required(),
})

export function apply(ctx: Context, config: Config) {
  ctx.llm.registerAdapter(config.providers, new MyAdapter(config.apiKey))
}

Protocolo StreamChunk (seguir estrictamente)

async function* chunks(): AsyncIterable<StreamChunk> {
  yield { type: 'block-start', index: 0, blockType: 'text' }
  yield { type: 'text-delta', index: 0, text: 'Hola' }
  yield { type: 'block-end', index: 0, block: { type: 'text', text: 'Hola mundo' } }
  // Bloque de llamada a herramienta:
  yield { type: 'block-start', index: 1, blockType: 'tool-call' }
  yield { type: 'tool-call-delta', index: 1, id: CallId('c1'), name: 'bash', argumentsDelta: '{"command":"ls"}' }
  yield { type: 'block-end', index: 1, block: { type: 'tool-call', id: CallId('c1'), name: 'bash', arguments: '{"command":"ls"}' } }
  yield { type: 'usage', usage: { inputTokens: 100, outputTokens: 50 } }   // Debe ir antes de finish
  yield { type: 'finish', reason: { kind: 'stop' } }                        // Debe ser el último
}

Reglas: cada block-start debe tener su correspondiente block-end; index comienza en 0 y se incrementa; arguments de tool-call es una cadena JSON sin procesar durante todo el proceso; finish es el último bloque; usage va antes de finish.

Errores y metadatos

  • Fallos de transporte/protocolo: throw new LlmError(msg, 'STABLE_CODE') (con código estable), no dependa de la conversión automática de Error normal.
  • El proveedor no soporta un campo de GenerateOptions: throw new LlmError(..., 'UNSUPPORTED'), nunca lo ignore silenciosamente.
  • Cada solicitud HTTP debe incluir attributionHeaders() y pasar options.signal.
  • Opcional: anular resolveModel() (devuelve la identidad del proveedor/modelo + metadatos opcionales de contexto/razonamiento) y listModels() (publica opciones de modelos).

Tutorial completo en References/05-llm-adapter.md; implementaciones de referencia: packages/llm/llm-deepseek (SSE compatible con OpenAI) y packages/llm/llm-pi-ai.


9. Capas de capacidad (tres roles, patrón de diseño de capacidades reemplazables)

Cuando una capacidad necesita un proveedor reemplazable (como la ejecución de Bash), se divide en tres roles, cada uno en un paquete diferente:

  1. Definición del Servicio (por ejemplo, dsh-shell): Define la interfaz del servicio Cordis + tipos Request/Result. abstract class MyCapService extends Service { super(ctx,'myCap'); abstract execute(req): Promise<res> }
  2. Proveedor del Servicio (por ejemplo, dsh-bash-local): Implementa la interfaz. class MyCapLocal extends MyCapService { ... }; apply(ctx){ ctx.plugin(MyCapLocal) }
  3. Consumidor (por ejemplo, dsh-tool-bash): Expone la capacidad como una herramienta del modelo. inject: ['tools','myCap']

Dirección de dependencia: El proveedor depende de la definición; el consumidor depende de la definición; el proveedor y el consumidor no dependen el uno del otro. Para cambiar de proveedor, solo se modifica una línea en cordis.yml; la definición y el consumidor no se modifican.

No divida de forma preventiva: solo divida en paquetes si los roles necesitan evolucionar de forma independiente. Un plugin de herramienta simple es suficiente con un solo paquete.


10. Empaquetado e instalación (entregar un plugin a los usuarios)

Dos conceptos

  • Paquete combinado (bundle): Un paquete npm con una capa de configuración adjunta, cuyo manifiesto declara dsh.bundle. Es lo que usted escribe y distribuye.
  • Perfil (profile): Un combo iniciable ubicado en $DSH_HOME/profiles/<nombre>, cuyo manifiesto declara dsh.profile (que contiene una lista ordenada de bundles). Es lo que el usuario inicia.

Empaquetar un paquete combinado

hello-plugin/
├── package.json       # Declara dsh.bundle
├── cordis.patch.yml   # Contenido de la capa
└── index.js           # Módulo del plugin
// package.json
{
  "name": "dsh-hello-plugin",
  "version": "0.1.0",
  "type": "module",
  "main": "index.js",
  "files": ["index.js", "cordis.patch.yml"],
  "dsh": { "bundle": { "patch": "cordis.patch.yml" } }
}

cordis.patch.yml es una capa de configuración (parche de cordis.yml) que puede contener plugins, servicios, inyecciones, etc. Se fusiona con la configuración del perfil activo en el momento de la carga.

Instalación y resolución de dependencias

Para usar un paquete combinado, el usuario lo agrega a la lista bundles del perfil:

# $DSH_HOME/profiles/mi-perfil/dsh.profile
name: mi-perfil
version: "1.0.0"
bundles:
  - npm:dsh-hello-plugin

pnpm dsh install descarga e instala las dependencias de todos los paquetes combinados en el perfil.

Complementar plugins con cordis.patch.yml

El archivo de parche se usa para agregar, modificar o eliminar plugins de la configuración base. Ejemplo típico:

# cordis.patch.yml
plugins:
  - name: './src/my-tool.ts'
    id: my-tool
    config:
      verbose: true

Puntos clave:

  • El archivo de parche no es un cordis.yml completo, sino una capa que se superpone.
  • Se pueden usar varios archivos de parche: se aplican en orden.
  • Los parches pueden deshabilitar plugins con disabled: true.

11. Verificación (lista de verificación antes de enviar)

Antes de enviar el código, verifique los siguientes puntos:

  • ¿Están todos los registros de efectos a través de ctx? (sin addEventListener / setTimeout / fs.watch sin ctx.effect)
  • ¿Están declaradas todas las dependencias en inject? (no usar ctx.get() para dependencias obligatorias)
  • ¿Está todo el comportamiento sensible a la configuración en Config? (sin valores codificados)
  • ¿Se valida la configuración con el esquema y se proporciona un error claro?
  • ¿Los callbacks de presentación (render, presentCall, presentResult) son funciones puras? ¿No hay E/S?
  • ¿Responde execute a exec.signal? (tareas largas: cancelar con la señal)
  • ¿Devuelve execute un valor canónico (no texto en lenguaje natural)?
  • ¿Se utiliza LlmError con un código estable para errores de protocolo del adaptador LLM?
  • ¿Sigue la secuencia StreamChunk el formato correcto? (block-start/block-end, uso, finalización)
  • ¿Se ha probado la herramienta con diferentes configuraciones? (valores válidos, no válidos, límites)
  • ¿Se ha probado la desinstalación/recarga del plugin? (sin fugas de memoria, sin referencias colgantes)

12. Referencias

Consulte el directorio References/ para obtener documentos detallados sobre:

DocumentoContenido
References/01-quickstart.mdGuía de inicio rápido para el desarrollo de plugins
References/02-cordis.mdTutorial del framework Cordis
References/03-tools.mdReferencia detallada de la API de herramientas
References/04-services.mdPatrones de servicios y dependencias
References/05-llm-adapter.mdTutorial de creación de adaptadores LLM
References/06-events.mdSistema de eventos y puntos de extensión
References/07-config.mdValidación de esquemas y configuración
References/08-capability-layering.mdCapas de capacidad y patrones de reemplazo
References/09-bundle.mdEmpaquetado y distribución de bundles
References/10-spatiotemporal.mdArtículo sobre el paradigma de programación espaciotemporal
References/11-cookbook.mdRecetario de ejemplos comunes

Skills relacionados