Introduces two new resource types (hooks, claude-md) with full CRUD, visual hook config editor, section-delimited CLAUDE.md installs, uninstall endpoints, and shell injection hardening in sync scripts.
6.2 KiB
Plan: Soporte de Skills en formato carpeta (Folder-based resources)
Contexto
El PDF oficial de Anthropic define que una skill puede ser una carpeta con subdirectorios:
my-skill/
├── SKILL.md # Requerido
├── scripts/ # Opcional - codigo ejecutable
├── references/ # Opcional - documentacion
└── assets/ # Opcional - plantillas, fuentes, iconos
Actualmente Skillit almacena cada recurso como un unico .md en data/<type>/<slug>.md. Queremos soportar ambos formatos: simple (archivo .md) y carpeta (directorio con SKILL.md + subdirectorios).
Archivos a modificar
| Archivo | Cambio |
|---|---|
src/lib/registry.ts |
Agregar mainFileName por tipo y constante FOLDER_SUBDIRS |
src/lib/resources.ts |
Reescribir CRUD para detectar/manejar ambos formatos; nuevas funciones para sub-archivos |
src/lib/skills.ts |
Actualizar interfaz Skill con format y files |
src/lib/sync.ts |
Scripts de sync/push con soporte carpeta |
src/pages/api/resources/[type]/index.ts |
Aceptar format en POST |
src/pages/api/resources/[type]/[slug].ts |
Manejar carpeta en GET |
src/pages/[type]/[slug].astro |
Mostrar arbol de archivos |
src/pages/[type]/[slug]/edit.astro |
Pasar format/files al editor |
src/pages/[type]/new.astro |
Soporte selector de formato |
src/pages/[type]/[slug]/i.ts |
Install scripts multi-archivo |
src/pages/[type]/[slug]/gi.ts |
Install global multi-archivo |
src/components/ResourceEditor.vue |
Toggle formato + integrar FileManager |
Archivos nuevos
| Archivo | Proposito |
|---|---|
src/pages/api/resources/[type]/[slug]/files/index.ts |
Listar y subir sub-archivos |
src/pages/api/resources/[type]/[slug]/files/[...filePath].ts |
CRUD individual de sub-archivos |
src/components/FileManager.vue |
Componente Vue para gestionar sub-archivos |
src/components/FolderTree.astro |
Componente Astro para mostrar arbol de archivos en detalle |
Fases de implementacion
Fase 1: Registry (registry.ts)
Agregar campo mainFileName a ResourceTypeConfig:
- skills:
SKILL.md - agents:
AGENT.md - output-styles:
OUTPUT-STYLE.md - rules:
RULE.md
Agregar constante FOLDER_SUBDIRS = ['scripts', 'references', 'assets'].
Fase 2: Core CRUD (resources.ts)
Cambios principales:
-
Nuevos tipos:
ResourceFormat = 'file' | 'folder'ResourceFileEntry = { relativePath: string; size: number }- Agregar
formatyfilesa interfazResource
-
resolveResource(type, slug)(nueva): detecta si el recurso es archivo o carpeta. Carpeta tiene prioridad si ambos existen. -
listResources(type): escanear tanto*.mdcomo directorios con el mainFileName. -
getResource(type, slug): usarresolveResource, leer mainFile, listar sub-archivos si es carpeta. -
createResource(type, slug, content, format?): parametroformatopcional (default'file'). Si'folder', crear directorio y escribir mainFileName. -
updateResource(type, slug, content): auto-detectar formato, escribir en la ruta correcta. -
deleteResource(type, slug): auto-detectar. Para carpeta usarfs.rm(dirPath, { recursive: true }). -
Funciones nuevas para sub-archivos:
listResourceFiles(type, slug)- listar archivos auxiliaresgetResourceFile(type, slug, relativePath)- leer sub-archivo (Buffer)addResourceFile(type, slug, relativePath, data: Buffer)- escribir sub-archivodeleteResourceFile(type, slug, relativePath)- eliminar sub-archivoconvertToFolder(type, slug)- convertir simple a carpeta
-
Seguridad: validar que
relativePathno contenga.., solo permita rutas dentro deFOLDER_SUBDIRS.
Fase 3: API de sub-archivos
/api/resources/[type]/[slug]/files/index.ts:
- GET: lista sub-archivos (JSON)
- POST: subir archivo via multipart/form-data
/api/resources/[type]/[slug]/files/[...filePath].ts:
- GET: descargar sub-archivo
- PUT: subir/reemplazar sub-archivo
- DELETE: eliminar sub-archivo
Modificar /api/resources/[type]/index.ts:
- POST acepta
format: 'file' | 'folder'opcional
Fase 4: Pagina de detalle ([type]/[slug].astro)
- Comprobar
resource.format - Para carpeta: renderizar seccion "Files" con
FolderTree.astro - El raw markdown (para curl) sigue devolviendo solo el mainFile
FolderTree.astro: componente que muestra arbol de archivos con links de descarga.
Fase 5: Editor UI
ResourceEditor.vue:
- Nuevos props:
initialFormat,files - Toggle formato al crear (Simple / Carpeta)
- Seccion FileManager al editar recurso tipo carpeta
FileManager.vue (nuevo componente Vue):
- Lista archivos con boton eliminar
- Boton subir: selector de subdirectorio (scripts/references/assets) + file input
- Llamadas fetch a la API de files
Fase 6: Scripts de instalacion
[type]/[slug]/i.ts y gi.ts:
- Para formato carpeta: generar script que crea estructura de directorios y descarga cada archivo
- URLs de sub-archivos:
${origin}/api/resources/${type}/${slug}/files/${relativePath} chmod +xpara archivos enscripts/
sync.ts:
- Sync: detectar formato por recurso, generar descarga multi-archivo
- Push: iterar tanto
*.mdcomo directorios; subir main content + sub-archivos
Fase 7: Backward compat (skills.ts)
Actualizar interfaz Skill con format y files. El wrapper sigue delegando a resources.ts.
Orden de implementacion
- Fase 1 (registry) - base
- Fase 2 (resources.ts CRUD) - critico
- Fase 3 (API sub-archivos)
- Fase 4 (pagina detalle)
- Fase 5 (editor UI)
- Fase 6 (scripts instalacion)
- Fase 7 (backward compat)
Verificacion
- Crear un skill simple (
test-simple) via web - verificar que funciona como antes - Crear un skill carpeta (
test-folder) via web - verificar que se crea directorio con SKILL.md - Subir archivos a scripts/ y references/ del skill carpeta via FileManager
- Ver pagina de detalle - verificar arbol de archivos
- Ejecutar script de instalacion (
curl .../skills/test-folder/i | bash) - verificar descarga completa - Verificar que listado muestra ambos formatos correctamente
- Editar ambos formatos - verificar que se actualizan
- Eliminar ambos formatos - verificar limpieza