zugzbot 1.0.38 → 1.0.40
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.opencode/agents/sdd-coder.md +7 -2
- package/.opencode/agents/sdd-tester.md +4 -0
- package/.opencode/rules/sdd-global.md +20 -3
- package/.opencode/skills/docker-templates/SKILL.md +7 -0
- package/.opencode/skills/sdd-methodology/SKILL.md +30 -42
- package/.opencode/skills/sdd-quickstart/SKILL.md +1 -0
- package/.opencode/skills/sdd-tester-quickstart/SKILL.md +73 -11
- package/.opencode/skills/shadcn/SKILL.md +51 -51
- package/.opencode/skills/shadcn-templates/SKILL.md +11 -14
- package/.opencode/skills/stack-validator/SKILL.md +4 -3
- package/.opencode/tools/brain.ts +2 -2
- package/.opencode/tools/sdd_bootstrap.ts +5 -5
- package/.opencode/tools/sdd_core.ts +6 -6
- package/.opencode/tools/sdd_design.ts +4 -4
- package/.opencode/tools/sdd_docker.ts +2 -2
- package/.opencode/tools/sdd_network.ts +3 -3
- package/.opencode/tools/sdd_status.ts +1 -1
- package/.opencode/tools/sdd_testing.ts +4 -4
- package/.utils/export_opencode_session.py +1 -1
- package/opencode.json +5 -5
- package/package.json +1 -1
|
@@ -66,7 +66,7 @@ Eres el Programador de Código (sdd-coder) del arnés SDD. Tu trabajo es codific
|
|
|
66
66
|
</bootstrap_obligatorio>
|
|
67
67
|
|
|
68
68
|
<consolidar_instalaciones>
|
|
69
|
-
Si necesitas paquetes adicionales o componentes shadcn, instálalos agrupados en un solo comando de terminal o llamada de herramienta (`npm install a b` o `npx shadcn@
|
|
69
|
+
Si necesitas paquetes adicionales o componentes shadcn, instálalos agrupados en un solo comando de terminal o llamada de herramienta (`npm install a b` o `npx shadcn@latest add x y --yes`). No los instales uno a uno.
|
|
70
70
|
</consolidar_instalaciones>
|
|
71
71
|
|
|
72
72
|
<tests_y_contratos>
|
|
@@ -85,7 +85,12 @@ Eres el Programador de Código (sdd-coder) del arnés SDD. Tu trabajo es codific
|
|
|
85
85
|
<coding_cheatsheet>
|
|
86
86
|
- **Linear/Brand tokens**: Los tokens se inyectan en `globals.css` vía CSS vars. PROHIBIDO reescribir `globals.css` desde cero o usar colores Hex manuales en componentes. Usa variables como `var(--color-brand-primary)`.
|
|
87
87
|
- **Estado**: Declara estados centralizados con `useState` en el componente padre (`owner` o `AppLayout`) y pásalos como props. Evita declarar estados compartidos en hijos.
|
|
88
|
-
- **Instalación de Shadcn Segura**: La herramienta de shadcn a utilizar en F2 es
|
|
88
|
+
- **Instalación de Shadcn Segura**: La herramienta de shadcn a utilizar en F2 es `npx shadcn@latest add <componentes>` (o simplemente `npx shadcn add`). Utiliza siempre la última versión final estable de Shadcn para garantizar la compatibilidad con Tailwind v4 y permitir la descarga de bloques complejos de la comunidad y del registro oficial (como dashboards, sidebars y formularios modernos) sin errores 404.
|
|
89
|
+
- **Next.js & Tailwind v4 Style Resolution**: En Tailwind v4, si `globals.css` importa `@import "shadcn/tailwind.css";`, debes asegurarte de instalar el paquete ejecutable `shadcn` ejecutando `npm install shadcn` o el compilador fallará.
|
|
90
|
+
- **Next.js Auth Redirects robustas (Evitar bucles/parpadeo)**:
|
|
91
|
+
- Usa siempre `router.replace("/")` en lugar de `push` para redirecciones de login.
|
|
92
|
+
- Para evitar efectos concurrentes o solapados en Strict Mode, usa un `useRef(false)` en redirecciones asíncronas para dispararlas solo una vez.
|
|
93
|
+
- En layouts protegidos por SSR, para evitar que parpadeen spinners o modales antes de hidratar la sesión en cliente, declara un estado `mounted` (`useEffect` asignando `setMounted(true)`) y retorna `null` si `!mounted`.
|
|
89
94
|
- **Iconos**: Importa desde `lucide-react`. Usa `data-icon="inline-start"` para espaciados automáticos.
|
|
90
95
|
</coding_cheatsheet>
|
|
91
96
|
|
|
@@ -46,6 +46,10 @@ Eres el Validador de Contratos (sdd-tester) del flujo SDD. Tu trabajo es ejecuta
|
|
|
46
46
|
- **Minimizar Lecturas/Búsquedas**: No realices búsquedas ciegas (`glob` repetidos) ni lecturas innecesarias. Guíate estrictamente por la lista `files_affected` provista en tu sección del brief activo para conocer qué archivos de producción se han modificado y dónde están ubicados los tests correspondientes.
|
|
47
47
|
- **Memoria de Errores**: Tienes PROHIBIDO llamar a `brain_read_memory`. Toda la información histórica sobre fallos técnicos ha sido inyectada directamente en `.opencode/active-brief.md`. Consúltala allí.
|
|
48
48
|
- **Restricción de Archivos**: Solo se te permite modificar/escribir archivos en la fase 'F3_VERIFICATION', y únicamente archivos que contengan 'test', 'spec', 'tests/' o '.openspec/' en su ruta. Tienes estrictamente prohibido modificar el código fuente de producción.
|
|
49
|
+
- **Extensión JSX en Tests**: Todo archivo de pruebas que contenga JSX, monte componentes o simule iconos (mocks de Lucide con `<svg>`) **DEBE** tener la extensión `.tsx` obligatoriamente (nunca `.ts` ya que esbuild/Vitest fallarán en la compilación).
|
|
50
|
+
- **Selectores de Formularios Robustos**: Evita usar `getByLabelText(/password/i)` si hay botones con aria-label que coincidan de forma ambigua. Prefiere placeholders como `getByPlaceholderText()` o expresiones regulares con anclajes estrictos como `/^Password$/` para aislar el input deseado.
|
|
51
|
+
- **Ocultamiento CSS vs Presencia DOM**: Para barras de navegación o sidebars colapsados por CSS (`hidden`, `w-0`), evita usar `.not.toBeInTheDocument()`. El texto sigue existiendo físicamente en el DOM, por lo que el test fallará. Verifica clases CSS de visibilidad directamente o usa `.not.toBeVisible()` de `@testing-library/jest-dom`.
|
|
52
|
+
- **Mocks Dinámicos de Hooks**: Mocks de hooks que controlan toggles (como `useTheme` de `next-themes`) deben usar getters locales reactivos en la definición del mock, o las pruebas sucesivas de clics de toggle reportarán el mismo valor (el mock estático no retiene el cambio).
|
|
49
53
|
- **PROHIBIDO EL USO DE `todowrite`**: Tienes ESTRICTAMENTE PROHIBIDO usar la herramienta `todowrite`. El seguimiento de progreso está centralizado en el Orquestador. No la invoques en absoluto.
|
|
50
54
|
- **Batcheo Extremo de ESCRITURA/EDICIÓN (CRÍTICO)**: NO modifiques ni crees archivos de tests uno a uno para luego correr el test runner cada vez en un bucle lento. Debes usar BATCH EXTREMO. Si tienes que modificar o crear 5 archivos de pruebas, debes enviar en TU MISMA respuesta todas las llamadas a `write` o `edit` necesarias al mismo tiempo (concurrencia). Solo después de enviar todos los cambios corres `vitest run` o `pytest`.
|
|
51
55
|
</constraints>
|
|
@@ -25,8 +25,9 @@ Cuando el estado del sistema tiene `loopMode === true` (activado mediante el com
|
|
|
25
25
|
## 3. Uso Mandatorio de Bloques Prehechos de Shadcn UI (dashboard, sidebar, login, etc.)
|
|
26
26
|
Para optimizar el tiempo de desarrollo, garantizar una experiencia visual premium y evitar la invención de layouts o formularios comunes desde cero:
|
|
27
27
|
- **Prioridad de Bloques**: Al diseñar cualquier interfaz de usuario (Layouts, Dashboards, Paneles de Control, Vistas de Configuración, Páginas de Autenticación, Tablas de Datos, Gráficos), los agentes **deben** buscar y utilizar de forma prioritaria los bloques prehechos del registro oficial `@shadcn` (como `dashboard-01`, `sidebar-01` al `16`, `login-01` al `05`, `signup-01` al `05`).
|
|
28
|
-
- **Búsqueda Proactiva**: El Spec-Writer **debe** consultar el registro utilizando las herramientas del MCP `shadcn` (`shadcn_search_items_in_registries`, `shadcn_list_items_in_registries`) al redactar el contrato (F1) para identificar qué bloques se ajustan a la necesidad, y declararlos en `frontend.components` y `files_affected` de `contract.json`.
|
|
29
|
-
- **Implementación por Distribución y Composición**: El Coder (F2) **debe** instalar estos bloques usando `npx shadcn@latest add <block-name>` (ej: `dashboard-01`, `login-03`) en su proyecto, integrando y distribuyendo los elementos con el estado y lógica del backend, sin rediseñar o codificar layouts que ya existen de forma oficial.
|
|
28
|
+
- **Búsqueda Proactiva**: El Spec-Writer **debe** consultar el registro utilizando las herramientas del MCP `shadcn` (`shadcn_search_items_in_registries`, `shadcn_list_items_in_registries`) al redactar el contrato (F1) para identificar qué bloques se ajustan a la necesidad, y declararlos en `frontend.components` y `files_affected` de `contract.json`. Además, el Spec-Writer **debe** invocar `shadcn_view_items_in_registries` sobre los bloques complejos seleccionados para inspeccionar por adelantado sus archivos, rutas y dependencias inyectadas por defecto, anticipando cualquier colisión de ruteo y documentándolo con precisión en el contrato.
|
|
29
|
+
- **Implementación por Distribución y Composición**: El Coder (F2) **debe** instalar estos bloques usando `npx shadcn@latest add <block-name>` (ej: `dashboard-01`, `login-03`) en su proyecto, integrando y distribuyendo los elementos con el estado y lógica del backend, sin rediseñar o codificar layouts que ya existen de forma oficial. El Coder puede usar `shadcn_get_item_examples_from_registries` para ver ejemplos de implementación realistas y aplicarlos limpiamente a la primera, reduciendo el desvío visual.
|
|
30
|
+
- **Resolución Activa de Conflictos de Ruteo por Inyección de Bloques**: Si la CLI de Shadcn inyecta automáticamente una estructura de rutas (ej: `src/app/dashboard/page.tsx`) que compite con las rutas del contrato (como un route group `(dashboard)` o una ruta raíz), el Coder **debe** borrar o refactorizar de inmediato el código inyectado por defecto para evitar bucles de redirección infinitos o colisiones en el router.
|
|
30
31
|
|
|
31
32
|
## 4. Soporte para Subdirectorios, Monorepos (targetDir) y Estándar Corporativo `src/`
|
|
32
33
|
Si el proyecto o aplicación principal vive en un subdirectorio (ej. `next-app`, `frontend`, `backend`), se deben seguir estas directivas estrictas para mantener la consistencia y el "estándar corporativo con carpeta `src/`":
|
|
@@ -42,6 +43,9 @@ Cualquier desarrollo de interfaz de usuario (Dashboards, Landings, Formularios,
|
|
|
42
43
|
- Se deben mapear obligatoriamente a variables semánticas de Shadcn/Tailwind que soporten modo claro/oscuro dinámico por defecto (ej. `bg-background`, `bg-muted/50`, `bg-accent`, `text-foreground`, `text-muted-foreground`, `border-border`).
|
|
43
44
|
- **Gráficos Dinámicos y Reactivos (SVG/Recharts Theme Sync):**
|
|
44
45
|
- Cualquier componente de gráficos (como Recharts o visores vectoriales SVG) que use atributos de pintado inline (`stroke`, `fill`, `color`) debe resolver sus colores mediante un custom hook o variables dinámicas que consuman el estado del tema actual (`useTheme` de `next-themes` u homólogo), previniendo que líneas o textos queden invisibles en modo oscuro.
|
|
46
|
+
- Está estrictamente prohibido usar variables CSS puras directamente en `stroke` o `fill` de SVG si estas no son resueltas de forma dinámica. Si es necesario, utiliza una paleta de colores hexadecimales fija de alto contraste y compatible con ambos modos claro y oscuro (ej: `#0072f5` para líneas y barras, o una paleta de sectores sólida para PieCharts) que garantice legibilidad 100% en fondos claros y oscuros, manteniendo solo los ejes y rejillas de fondo (grids) referenciando variables semánticas.
|
|
47
|
+
- **Evitar Solapamiento de Sidebar (Sidebar Overlap Prevention):**
|
|
48
|
+
- Al implementar barras laterales colapsables de Shadcn (`Sidebar`), el Coder debe asegurarse de que el contenedor del contenido principal use de forma robusta `<SidebarInset>` o una estructura flexbox flexible (ej: `flex flex-1 flex-col`) que responda al estado del sidebar. Está estrictamente prohibido usar posicionamiento fijo o absoluto en el sidebar sin un espaciador o contenedor dinámico que evite que el sidebar se sobreponga al contenido en pantallas anchas.
|
|
45
49
|
- **Robustez HTML y Regla de No-Nesting en Triggers:**
|
|
46
50
|
- Al utilizar componentes contenedores de Radix/Shadcn UI (como `TooltipTrigger`, `DropdownMenuTrigger`, `DialogTrigger`, `SheetTrigger`), está estrictamente PROHIBIDO anidar un elemento interactivo nativo (como `<button>` o `<a>`) directamente dentro de otro trigger que ya renderice un botón por defecto.
|
|
47
51
|
- Para evitar la hidratación rota y HTML inválido, se debe usar siempre el prop `asChild` en el trigger de Radix o delegar los props correctamente usando las directivas del componente de base.
|
|
@@ -49,8 +53,21 @@ Cualquier desarrollo de interfaz de usuario (Dashboards, Landings, Formularios,
|
|
|
49
53
|
- **Tooltips:** Todo botón que contenga únicamente un icono de acción debe estar envuelto en un componente `Tooltip` con su descripción respectiva.
|
|
50
54
|
- **Skeletons y Empty States:** Las vistas de carga deben contar con animaciones de `Skeleton` fluidas. Las listas o tablas vacías deben presentar un `Empty State` visual y explicativo agradable con iconos y un botón de acción alternativo, nunca una página o cuadro en blanco.
|
|
51
55
|
|
|
52
|
-
## 6.
|
|
56
|
+
## 6. Estándar de Robustez en Autenticación, Ruteo y SSR (Next.js)
|
|
57
|
+
Para evitar bucles de redirección ("redirect loops") y pantallas parpadeantes (flickers/blinking) tras iniciar sesión:
|
|
58
|
+
- **Evitar Race Conditions en Redirecciones:** En el formulario de login, usa siempre `router.replace("/")` en lugar de `push` tras un login exitoso para evitar empujar estados duplicados al historial.
|
|
59
|
+
- **Evitar useEffects Cruzados Activos:** Si usas un guard de redirección en `LoginPage` o similar para usuarios ya autenticados, utiliza un `useRef(false)` para controlar que la redirección asíncrona solo se dispare una vez y no se encadene con re-renderizados concurrentes de React.
|
|
60
|
+
- **Evitar Flash de Carga SSR en Layouts:** Para layouts o guards protegidos, nunca asumas estados por defecto que pinten elementos cargando (spinners) durante el servidor. Comprueba si el componente está montado (`mounted === true`) antes de evaluar la sesión en el cliente y renderizar el contenido. Retorna `null` antes de montar para evitar desajustes de hidratación (hydration mismatch).
|
|
61
|
+
- **Eliminación Obligatoria de Placeholders de Página Raíz:**
|
|
62
|
+
- El Coder debe asegurar que la página de entrada de la aplicación (`src/app/page.tsx` o similar) no se quede con el texto placeholder por defecto. Debe ser reemplazada por el componente principal especificado o contener una redirección limpia (`redirect("/dashboard")`) hacia la vista principal protegida o pública definida por el contrato.
|
|
63
|
+
|
|
64
|
+
## 7. Mockups Visuales y Validación Temprana de Layout (F0/F1)
|
|
53
65
|
Para optimizar el diseño, evitar cambios de arquitectura estructurales a mitad del desarrollo (como rediseñar pestañas a layouts de sidebar lateral) y garantizar alineación inmediata con las expectativas del usuario:
|
|
54
66
|
- **Propuesta de Layout Visual:** Durante la transición de F0 a F1, el `@sdd-spec-writer` **debe** proponer un mockup textual o diagrama de cajas ASCII detallando la distribución estructural de la pantalla (Layout general, barras laterales sticky, contenedores de contenido responsivos y anchos de pantalla recomendados, ej. `max-w-6xl` vs `w-full`).
|
|
55
67
|
- **Ancho y Densidad Modernos:** Por defecto, los layouts complejos deben evitar contenedores angostos restrictivos como `max-w-3xl` para maximizar el aprovechamiento de pantallas de escritorio modernas mediante rejillas responsivas (`grid grid-cols-1 md:grid-cols-X gap-6`).
|
|
56
68
|
- **Aprobación Temprana:** El orquestador presentará esta propuesta visual al usuario en la fase F1. Una vez aprobada la disposición espacial y la estructura de navegación local (ej: sidebar split vs horizontal tabs), el `@sdd-coder` la ejecutará exactamente como se acordó, previniendo loops redundantes de maquetación en fases tardías.
|
|
69
|
+
|
|
70
|
+
## 8. Abstracción y Prohibición de Parchar Código en F3/Orquestador
|
|
71
|
+
Para mantener la limpieza y disciplina en la ventana de contexto de la sesión:
|
|
72
|
+
- **Orquestador No-Coder:** El orquestador principal (`sdd-orchestrator`) tiene estrictamente prohibido usar herramientas de edición (`edit` o `write`) para modificar código de producción o archivos de test.
|
|
73
|
+
- **Rollback Disciplinado:** Si en la fase `F3_VERIFICATION` el linter o los tests reportan errores, el orquestador **debe** transicionar el estado a `F2_IMPLEMENTATION` mediante `sdd_core_set_phase` y re-invocar al subagente experto (`sdd-coder`) para que realice la corrección cleanly. No se permiten parches rápidos a mitad de fase de test.
|
|
@@ -63,6 +63,13 @@ ENV HOSTNAME="0.0.0.0"
|
|
|
63
63
|
CMD ["node", "server.js"]
|
|
64
64
|
```
|
|
65
65
|
|
|
66
|
+
#### 🛠️ **Manejo de Conflictos de Dependencias y Sincronización de Lockfile**
|
|
67
|
+
En proyectos donde las dependencias cambian con frecuencia por la adición automática de componentes de Shadcn, es muy común que el comando estricto `npm ci --frozen-lockfile` falle dentro de Docker con errores de desincronización de lockfile (ej: `Invalid: lock file's picomatch... does not satisfy`).
|
|
68
|
+
|
|
69
|
+
Para solucionar esto de manera robusta:
|
|
70
|
+
1. **Solución Local Primaria**: El Coder debe añadir de manera explícita la dependencia par conflictiva en su `package.json` (ej: `"picomatch": "^4.0.4"`) y ejecutar `npm install` localmente para regenerar y sincronizar un `package-lock.json` limpio antes de intentar compilar el contenedor.
|
|
71
|
+
2. **Estrategia Fallback en Dockerfile**: Si la sincronización del lockfile sigue presentando conflictos intermitentes e inestabilidad insalvable, el Deployer tiene autorización para modificar el paso de instalación del Dockerfile de un estricto `npm ci` a un dinámico `npm install --no-audit --no-fund` para permitir que el motor de resolución de Node resuelva las dependencias pares de forma adaptativa.
|
|
72
|
+
|
|
66
73
|
#### **.dockerignore**
|
|
67
74
|
```ignore
|
|
68
75
|
node_modules
|
|
@@ -41,65 +41,53 @@ Cada fase tiene un **gate explícito** (HIL del usuario) antes de transicionar a
|
|
|
41
41
|
|
|
42
42
|
---
|
|
43
43
|
|
|
44
|
-
## 3. Trampas
|
|
44
|
+
## 3. Trampas del Flujo Maestro (EVITAR siempre)
|
|
45
45
|
|
|
46
46
|
### Trampa 1: Listar marcas de diseño una por una
|
|
47
|
-
**NO HAGAS**:
|
|
48
|
-
**HAZ**:
|
|
47
|
+
**NO HAGAS**: Hacer múltiples llamadas a `oh-my-design_list_references` para mostrar opciones al usuario en F0.
|
|
48
|
+
**HAZ**: Haz una única llamada consolidada a `sdd_list_design_recommendations({ use_case: "all", max_per_category: 3 })`.
|
|
49
49
|
|
|
50
50
|
### Trampa 2: Crear la carpeta del spec en 2 steps
|
|
51
|
-
**NO HAGAS**: `sdd_create_spec_folder("mi-spec")`
|
|
52
|
-
**HAZ**:
|
|
51
|
+
**NO HAGAS**: Llamar a `sdd_create_spec_folder("mi-spec")` y luego a `sdd_set_phase("F1_CONTRACT", ...)` por separado (causa race conditions en el timestamp).
|
|
52
|
+
**HAZ**: Transiciona en un solo paso: `sdd_set_phase({ phase: "F1_CONTRACT", spec_name: "mi-spec" })`.
|
|
53
53
|
|
|
54
|
-
### Trampa 3:
|
|
55
|
-
**NO HAGAS**:
|
|
56
|
-
**HAZ**:
|
|
54
|
+
### Trampa 3: Cargar `next-devtools` MCP en sesión normal
|
|
55
|
+
**NO HAGAS**: Activar `next-devtools` por defecto. Inyecta miles de palabras de instrucciones redundantes al contexto, desperdiciando tokens de razonamiento.
|
|
56
|
+
**HAZ**: Mantenerlo deshabilitado en `opencode.json` y activarlo únicamente bajo demanda si se depura un error muy específico del runtime de Next.js.
|
|
57
57
|
|
|
58
|
-
### Trampa 4:
|
|
59
|
-
**NO HAGAS**:
|
|
60
|
-
**HAZ**:
|
|
58
|
+
### Trampa 4: Escribir el contrato desde cero en F1
|
|
59
|
+
**NO HAGAS**: Redactar cientos de líneas de `contract.json` de forma manual.
|
|
60
|
+
**HAZ**: Cargar la skill `sdd-quickstart` y rellenar los huecos `{{...}}` de su plantilla preconfigurada.
|
|
61
61
|
|
|
62
|
-
### Trampa 5:
|
|
63
|
-
**NO HAGAS**:
|
|
64
|
-
**HAZ**:
|
|
62
|
+
### Trampa 5: Permitir que el Coder escriba los tests en F2
|
|
63
|
+
**NO HAGAS**: Desarrollar la lógica y luego redactar las pruebas (causa bucles redundantes entre Coder y Tester).
|
|
64
|
+
**HAZ**: Que el Spec-Writer declare las aserciones en el contrato en F1. El Coder solo implementa el código de negocio necesario para que pasen.
|
|
65
65
|
|
|
66
|
-
### Trampa 6:
|
|
67
|
-
**NO HAGAS**:
|
|
68
|
-
**HAZ**:
|
|
66
|
+
### Trampa 6: Exceso de actualizaciones de TODOs con `todowrite`
|
|
67
|
+
**NO HAGAS**: Llamar a `todowrite` para actualizar el estado del arnés tras cada pequeño cambio o fase.
|
|
68
|
+
**HAZ**: Inicializar la lista al inicio, marcar `in_progress` al arrancar una fase, y marcar los TODOs completados en bloque al final.
|
|
69
69
|
|
|
70
|
-
### Trampa 7:
|
|
71
|
-
**NO HAGAS**:
|
|
72
|
-
**HAZ**:
|
|
70
|
+
### Trampa 7: Cargar skills duplicadas en subagentes
|
|
71
|
+
**NO HAGAS**: Cargar skills generales (como `sdd-methodology`) de manera redundante en subagentes especializados (como `@sdd-deployer` o `@sdd-tester`) que ya la tienen incorporada en su prompt base.
|
|
72
|
+
**HAZ**: Limitar la carga de skills estrictamente a tareas que requieran sus plantillas específicas.
|
|
73
73
|
|
|
74
|
-
### Trampa 8:
|
|
75
|
-
**NO HAGAS**:
|
|
76
|
-
**HAZ**:
|
|
74
|
+
### Trampa 8: Invocar Playwright en modo Console
|
|
75
|
+
**NO HAGAS**: Abrir navegadores o tomar snapshots si `verificationMode` es `"console"`.
|
|
76
|
+
**HAZ**: Confiar plenamente en Vitest/Pytest y curls rápidos desde la terminal.
|
|
77
77
|
|
|
78
|
-
### Trampa 9:
|
|
79
|
-
**NO HAGAS**:
|
|
80
|
-
**HAZ**:
|
|
78
|
+
### Trampa 9: Orquestador usurpador (Ruptura de Abstracción)
|
|
79
|
+
**NO HAGAS**: Editar código de producción o escribir/ejecutar tests directamente desde el orquestador si un subagente falla o se queda sin pasos.
|
|
80
|
+
**HAZ**: Re-invocar al subagente experto (`sdd-coder` o `sdd-tester`) mediante la herramienta `task` pasándole el `task_id` original para que continúe limpiamente.
|
|
81
81
|
|
|
82
|
-
### Trampa 10:
|
|
83
|
-
**NO HAGAS**:
|
|
84
|
-
**HAZ**:
|
|
85
|
-
|
|
86
|
-
### Trampa 11: Orquestador usurpador (Ruptura de Abstracción)
|
|
87
|
-
**NO HAGAS**: Permitir que el Orquestador principal (`sdd-orchestrator`) tome el rol de escribir el código de producción o escribir/ejecutar tests directamente si un subagent (ej. `@sdd-coder`) falla o alcanza el límite de pasos ("Maximum Steps Reached"). Esto ensucia la ventana de contexto principal de la sesión.
|
|
88
|
-
**HAZ**: Re-invoca al mismo subagente usando la herramienta `task`, pasando el `task_id` original del subagente interrumpido e instruyéndole: "Te quedaste sin pasos. Continúa y finaliza los archivos pendientes".
|
|
89
|
-
|
|
90
|
-
### Trampa 12: Obsesión por alineación de consola (Pixel-Peeping)
|
|
91
|
-
**NO HAGAS**: Gastar múltiples iteraciones o miles de tokens en el razonamiento de `@sdd-coder` tratando de lograr una alineación perfecta de columnas con espacios exactos en salidas CLI o tablas ASCII.
|
|
92
|
-
**HAZ**: Usa funciones estándar de formateo de strings de tu lenguaje (como `ljust()`, `rjust()` o `center()` en Python; o formateadores sencillos en JS/TS) para lograr una presentación razonable de forma inmediata y avanzar directamente a la creación de pruebas.
|
|
93
|
-
|
|
94
|
-
### Trampa 13: Omitir la disposición espacial y propuesta de Layout en F1
|
|
95
|
-
**NO HAGAS**: Redactar el contrato en F1 listando únicamente archivos de forma abstracta sin definir o validar la geometría estructural y distribución de la UI (ej. si se requieren Sidebars locales de navegación vs pestañas horizontales planas), asumiendo anchos angostos y estáticos (como `max-w-3xl`) o rompiendo el soporte de modo oscuro con colores absolutos (`bg-white`).
|
|
96
|
-
**HAZ**: El spec-writer debe proponer proactivamente en F1 un bosquejo textual o diagrama ASCII de la interfaz y validar con el usuario un layout responsivo amplio (`max-w-6xl` o superior). Además, el coder debe implementar soporte semántico dinámico de temas de entrada (sin colores duros) y sincronizar colores SVG/gráficos dinámicamente con el tema actual.
|
|
82
|
+
### Trampa 10: Obsesión por alineación exacta en consola (Pixel-Peeping)
|
|
83
|
+
**NO HAGAS**: Consumir iteraciones intentando alinear espacios exactos en salidas CLI o tablas ASCII.
|
|
84
|
+
**HAZ**: Usar funciones estándar de formateo de strings de tu lenguaje (`ljust()`, `rjust()`) y priorizar la lógica de negocio y las pruebas.
|
|
97
85
|
|
|
98
86
|
---
|
|
99
87
|
|
|
100
88
|
## 4. Stack cerrado (NO abrir)
|
|
101
89
|
|
|
102
|
-
- **Frontend**: Next.js 15/16 + React 19 + TypeScript + Tailwind v4 + Shadcn UI
|
|
90
|
+
- **Frontend**: Next.js 15/16 + React 19 + TypeScript + Tailwind v4 + Shadcn UI @latest (Radix UI) + lucide-react + Vitest. **PROHIBIDO**: Shadcn v4/Base-UI (por inestabilidad y falta de soporte actual), HeroUI, Chakra, Material-UI.
|
|
103
91
|
- **Backend**: Python 3.11+ + FastAPI + Pydantic v2 + Uvicorn + Pytest + Ruff. **PROHIBIDO**: Django, Flask, sync SQLAlchemy.
|
|
104
92
|
- **Persistencia**: localStorage (frontend-only) o PostgreSQL con pgvector. **PROHIBIDO**: MongoDB (excepto si se justifica), Redis como primary store.
|
|
105
93
|
- **Containerización**: Docker multi-stage con `node:20-alpine` (Next) o `python:3.11-slim` (FastAPI). Usuario no-root. Healthcheck via `node -e` (no wget en alpine).
|
|
@@ -160,6 +160,7 @@ Copia y adapta los IDs y descripciones que apliquen. Borra los que no apliquen.
|
|
|
160
160
|
- **NO escribas más de 5-6 `test_scenarios`** para modo `console`. Más de eso no acelera la entrega, solo retrasa F2.
|
|
161
161
|
- **NO incluyas escenarios `visual` o `e2e` si `verificationMode` es `console`.** El tester los rechazará.
|
|
162
162
|
- **NO omitas la disposición espacial y propuesta de Layout**: El spec-writer DEBE proponer un bosquejo textual o diagrama ASCII de la disposición espacial de la UI en F1 (ej. layouts con sidebar lateral para configuración o paneles complejos en lugar de simples pestañas tradicionales planas) y acordar anchos de pantalla generosos (`max-w-6xl` o superior, evitando el limitante `max-w-3xl`) con el usuario antes de transicionar a F2. Esto previene reestructuraciones estéticas costosas y asegura entregas de alta gama a la primera.
|
|
163
|
+
- **NO omitas la página raíz (`src/app/page.tsx`) en el mapeo de archivos afectados**: El spec-writer DEBE asegurar que `src/app/page.tsx` quede registrado explícitamente y que el contrato aclare si la ruta raíz `/` servirá el contenido principal de la aplicación, o si simplemente ejecutará una redirección limpia (`redirect("/dashboard")`) hacia el panel principal. Esto evita que el Coder conserve el placeholder por defecto de bootstrap y cause inconsistencias visuales o de navegación.
|
|
163
164
|
|
|
164
165
|
---
|
|
165
166
|
|
|
@@ -19,12 +19,14 @@ Esta habilidad proporciona un **flujo de trabajo estructurado en 4 pasos** para
|
|
|
19
19
|
- En el **Paso 3**, no aplican los mocks de React, Lucide ni `crypto.randomUUID` en JS. Si necesitas mockear en Python, usa `unittest.mock` (como `patch` o `MagicMock`).
|
|
20
20
|
- En el **Paso 4**, ejecuta `ruff check src/` o similar para linting, y `python -m pytest tests/ -v` para ejecutar toda la suite de pruebas de una sola llamada consolidada.
|
|
21
21
|
|
|
22
|
-
### Paso 1: Leer solo lo indispensable (Máximo 3 reads)
|
|
22
|
+
### Paso 1: Leer solo lo indispensable (Máximo 3 reads) y asegurar entorno
|
|
23
23
|
1. **Contrato**: Lee únicamente `contract.json` para extraer los `test_scenarios` y el `verificationMode`.
|
|
24
24
|
2. **Setup**: Lee `src/test/setup.ts` o `vitest.config.ts` para confirmar si ya hay polyfills.
|
|
25
25
|
3. **Breve examen**: Lee el componente principal (`AppLayout` o similar) para confirmar el `stateFlow`.
|
|
26
26
|
*NO uses `glob` ciegos para buscar archivos del proyecto.*
|
|
27
27
|
|
|
28
|
+
**VERIFICACIÓN CLAVE DE DEPENDENCIAS**: Asegúrate de que `package.json` tenga instaladas las devDependencies necesarias para pruebas de React: `happy-dom`, `@testing-library/jest-dom` y `@testing-library/dom`. Si no están presentes, instálalas en un solo comando unificado: `npm install --save-dev happy-dom @testing-library/jest-dom @testing-library/dom`.
|
|
29
|
+
|
|
28
30
|
### Paso 2: Autogenerar plantillas de tests (BLOQUEANTE)
|
|
29
31
|
Antes de escribir cualquier test a mano, **DEBES** ejecutar:
|
|
30
32
|
```bash
|
|
@@ -35,17 +37,24 @@ Esto creará automáticamente las plantillas correspondientes en base a los `tes
|
|
|
35
37
|
### Paso 3: Completar aserciones usando Mocks Estandarizados (Evitar fallos de librerías)
|
|
36
38
|
Completa los tests importando los componentes reales. Si Vitest o happy-dom fallan por dependencias externas de Shadcn UI o Lucide, aplica estos mocks centralizados:
|
|
37
39
|
|
|
38
|
-
#### Mock de Lucide Icons (
|
|
40
|
+
#### Mock Dinámico de Lucide Icons (Recomendado para evitar fallos de iconos faltantes)
|
|
41
|
+
Para evitar que tests fallen porque falta mockear un icono específico (ej. `PanelLeft`, `Search`, etc.), usa un Proxy que mockea dinámicamente CUALQUIER icono exportado por `lucide-react`:
|
|
39
42
|
```typescript
|
|
40
|
-
vi.mock('lucide-react', () =>
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
43
|
+
vi.mock('lucide-react', () => {
|
|
44
|
+
return new Proxy(
|
|
45
|
+
{},
|
|
46
|
+
{
|
|
47
|
+
get: (target, prop) => {
|
|
48
|
+
// Retorna un componente funcional con el testid del icono solicitado
|
|
49
|
+
const IconComponent = (props: any) => (
|
|
50
|
+
<span data-testid={`icon-${String(prop).toLowerCase()}`} {...props} />
|
|
51
|
+
);
|
|
52
|
+
IconComponent.displayName = String(prop);
|
|
53
|
+
return IconComponent;
|
|
54
|
+
},
|
|
55
|
+
}
|
|
56
|
+
);
|
|
57
|
+
});
|
|
49
58
|
```
|
|
50
59
|
|
|
51
60
|
#### Mock de Base UI / Shadcn Radix Primitives
|
|
@@ -74,6 +83,38 @@ if (!globalThis.crypto) {
|
|
|
74
83
|
}
|
|
75
84
|
```
|
|
76
85
|
|
|
86
|
+
#### Mock de `next-themes` (Soporte reactivo de Tema)
|
|
87
|
+
Para probar toggles de tema sin que fallen en clics sucesivos:
|
|
88
|
+
```typescript
|
|
89
|
+
let currentTheme = 'light';
|
|
90
|
+
const mockSetTheme = vi.fn((newTheme: string) => {
|
|
91
|
+
currentTheme = newTheme;
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
vi.mock('next-themes', () => ({
|
|
95
|
+
useTheme: () => ({
|
|
96
|
+
get theme() { return currentTheme; },
|
|
97
|
+
setTheme: mockSetTheme,
|
|
98
|
+
get resolvedTheme() { return currentTheme; },
|
|
99
|
+
}),
|
|
100
|
+
}));
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
#### Mock de `next/navigation` (Router y Pathname)
|
|
104
|
+
```typescript
|
|
105
|
+
const mockPush = vi.fn();
|
|
106
|
+
const mockReplace = vi.fn();
|
|
107
|
+
|
|
108
|
+
vi.mock('next/navigation', () => ({
|
|
109
|
+
useRouter: () => ({
|
|
110
|
+
push: mockPush,
|
|
111
|
+
replace: mockReplace,
|
|
112
|
+
prefetch: vi.fn(),
|
|
113
|
+
}),
|
|
114
|
+
usePathname: () => '/',
|
|
115
|
+
}));
|
|
116
|
+
```
|
|
117
|
+
|
|
77
118
|
### Paso 4: Ejecutar Lint y Tests consolidando comandos
|
|
78
119
|
1. Corre el linter enfocado en el código fuente:
|
|
79
120
|
```bash
|
|
@@ -91,3 +132,24 @@ npx vitest run
|
|
|
91
132
|
1. **PROHIBIDO Playwright en modo Console**: Si `verificationMode === "console"`, no instancies ni corras ningún test de Playwright, ni navegues con tools de Playwright. Solo corre tests de Vitest.
|
|
92
133
|
2. **PROHIBIDO modificar código de features para "hacer pasar" el test**: Si el código tiene un bug, haz rollback a `F2_IMPLEMENTATION` reportando el error exacto al coder. No parches la lógica del negocio en F3.
|
|
93
134
|
3. **Consolidación**: No corras `vitest` archivo por archivo. Corre la suite completa en una sola llamada a `bash`.
|
|
135
|
+
4. **REGLA DE ORO DE ASERCIONES DE TEXTO (Acentos y Encoding)**: Para evitar fallos tontos de aserción por diferencias de codificación en caracteres con tildes (ej: `ó` vs `\u00f3`, `ñ` vs `\u00f1`), usa siempre expresiones regulares insensibles a mayúsculas y comodines (ej: `screen.getByText(/Inicia sesi.n/i)` o `screen.getByText(/contrase.a/i)`). Nunca utilices comparaciones estrictas de cadenas de texto acentuadas.
|
|
136
|
+
|
|
137
|
+
---
|
|
138
|
+
|
|
139
|
+
## ⚠️ Trampas Comunes de Pruebas (Testing Gotchas)
|
|
140
|
+
|
|
141
|
+
### 1. Extensión incorrecta en archivos de pruebas con JSX
|
|
142
|
+
* **No hagas**: Usar la extensión `.ts` para archivos de tests que renderizan primitivas de HTML o JSX o que mockean componentes de interfaz (causa fallos de compilación inmediatos en Vitest).
|
|
143
|
+
* **Haz**: Toda suite de pruebas que monte componentes o contenga JSX debe grabarse con la extensión `.tsx` obligatoriamente.
|
|
144
|
+
|
|
145
|
+
### 2. Selectores ambiguos para campos interactivos comunes
|
|
146
|
+
* **No hagas**: Usar queries genéricas e insensibles como `screen.getByLabelText(/password/i)` si existen múltiples elementos en el DOM que contengan esa palabra (ej: botones de "Show password"). Esto lanzará un error de "Found multiple elements".
|
|
147
|
+
* **Haz**: Usa selectores de coincidencia exacta como `screen.getByLabelText(/^Password$/)` o busca mediante placeholders específicos (`screen.getByPlaceholderText(...)`).
|
|
148
|
+
|
|
149
|
+
### 3. Validar ausencia de elementos ocultos por CSS con `not.toBeInTheDocument()`
|
|
150
|
+
* **No hagas**: Tratar de validar que un menú o modal colapsado/oculto ya no es visible utilizando `expect(queryByText("...")).not.toBeInTheDocument()`. Si el elemento simplemente se oculta con clases de CSS (como `hidden`, `w-0` u `opacity-0`), el nodo sigue existiendo físicamente en el DOM.
|
|
151
|
+
* **Haz**: Verifica la visibilidad real usando `.not.toBeVisible()` de `@testing-library/jest-dom`, o comprueba directamente las clases CSS de colapso.
|
|
152
|
+
|
|
153
|
+
### 4. Mocks estáticos de hooks con estado
|
|
154
|
+
* **No hagas**: Mockear hooks que controlan toggles (como `useTheme` de `next-themes`) usando un retorno fijo estático. Al simular el clic en el botón de toggle, el test fallará o entrará en bucles porque el valor del estado simulado permanece congelado.
|
|
155
|
+
* **Haz**: Declara variables mutables locales a nivel de archivo de pruebas y usa getters dinámicos en la definición del mock de Vitest para simular los cambios de estado correctamente.
|
|
@@ -9,19 +9,19 @@ compatibility: opencode
|
|
|
9
9
|
|
|
10
10
|
A framework for building ui, components and design systems. Components are added as source code to the user's project via the CLI.
|
|
11
11
|
|
|
12
|
-
> **IMPORTANT:** Run all CLI commands using the project's package runner: `npx shadcn@
|
|
12
|
+
> **IMPORTANT:** Run all CLI commands using the project's package runner: `npx shadcn@latest`, `pnpm dlx shadcn@latest`, or `bunx --bun shadcn@latest` — based on the project's `packageManager`. Examples below use `npx shadcn@latest` but substitute the correct runner for the project.
|
|
13
13
|
|
|
14
14
|
## Current Project Context
|
|
15
15
|
|
|
16
16
|
```json
|
|
17
|
-
!`npx shadcn@
|
|
17
|
+
!`npx shadcn@latest info --json`
|
|
18
18
|
```
|
|
19
19
|
|
|
20
|
-
The JSON above contains the project config and installed components. Use `npx shadcn@
|
|
20
|
+
The JSON above contains the project config and installed components. Use `npx shadcn@latest docs <component>` to get documentation and example URLs for any component.
|
|
21
21
|
|
|
22
22
|
## Principles
|
|
23
23
|
|
|
24
|
-
1. **Use existing components first.** Use `npx shadcn@
|
|
24
|
+
1. **Use existing components first.** Use `npx shadcn@latest search` to check registries before writing custom UI. Check community registries too.
|
|
25
25
|
2. **Compose, don't reinvent.** Settings page = Tabs + Card + form controls. Dashboard = Sidebar + Card + Chart + Table.
|
|
26
26
|
3. **Use built-in variants before custom styles.** `variant="outline"`, `size="sm"`, etc.
|
|
27
27
|
4. **Use semantic colors.** `bg-primary`, `text-muted-foreground` — never raw values like `bg-blue-500`.
|
|
@@ -52,7 +52,7 @@ These rules are **always enforced**. Each links to a file with Incorrect/Correct
|
|
|
52
52
|
### Component Structure → [composition.md](../../docs/shadcn/rules/composition.md)
|
|
53
53
|
|
|
54
54
|
- **Items always inside their Group.** `SelectItem` → `SelectGroup`. `DropdownMenuItem` → `DropdownMenuGroup`. `CommandItem` → `CommandGroup`.
|
|
55
|
-
- **Use `asChild` (radix) or `render` (base) for custom triggers.** Check `base` field from `npx shadcn@
|
|
55
|
+
- **Use `asChild` (radix) or `render` (base) for custom triggers.** Check `base` field from `npx shadcn@latest info`. → [base-vs-radix.md](../../docs/shadcn/rules/base-vs-radix.md)
|
|
56
56
|
- **Dialog, Sheet, and Drawer always need a Title.** `DialogTitle`, `SheetTitle`, `DrawerTitle` required for accessibility. Use `className="sr-only"` if visually hidden.
|
|
57
57
|
- **Use full Card composition.** `CardHeader`/`CardTitle`/`CardDescription`/`CardContent`/`CardFooter`. Don't dump everything in `CardContent`.
|
|
58
58
|
- **Button has no `isPending`/`isLoading`.** Compose with `Spinner` + `data-icon` + `disabled`.
|
|
@@ -77,8 +77,8 @@ These rules are **always enforced**. Each links to a file with Incorrect/Correct
|
|
|
77
77
|
|
|
78
78
|
### CLI
|
|
79
79
|
|
|
80
|
-
- **Never decode preset codes or build preset URLs manually.** Use `npx shadcn@
|
|
81
|
-
- **Apply preset codes directly with the CLI.** Use `npx shadcn@
|
|
80
|
+
- **Never decode preset codes or build preset URLs manually.** Use `npx shadcn@latest preset decode <code>`, `preset url <code>`, or `preset open <code>`. For project-aware preset detection, use `npx shadcn@latest preset resolve`.
|
|
81
|
+
- **Apply preset codes directly with the CLI.** Use `npx shadcn@latest apply <code>` for existing projects, or `npx shadcn@latest init --preset <code>` when initializing.
|
|
82
82
|
|
|
83
83
|
## Key Patterns
|
|
84
84
|
|
|
@@ -151,7 +151,7 @@ The injected project context contains these key fields:
|
|
|
151
151
|
- **`resolvedPaths`** → exact file-system destinations for components, utils, hooks, etc.
|
|
152
152
|
- **`framework`** → routing and file conventions (e.g. Next.js App Router vs Vite SPA).
|
|
153
153
|
- **`packageManager`** → use this for any non-shadcn dependency installs (e.g. `pnpm add date-fns` vs `npm install date-fns`).
|
|
154
|
-
- **`preset`** → resolved preset code and values for the current project. Use `npx shadcn@
|
|
154
|
+
- **`preset`** → resolved preset code and values for the current project. Use `npx shadcn@latest preset resolve --json` when you only need preset information.
|
|
155
155
|
|
|
156
156
|
See [cli.md — `info` command](../../docs/shadcn/cli.md) for the full field reference.
|
|
157
157
|
|
|
@@ -166,29 +166,29 @@ DO NOT run bash commands to view docs. Instead, explicitly use the built-in MCP
|
|
|
166
166
|
|
|
167
167
|
## Workflow
|
|
168
168
|
|
|
169
|
-
1. **Get project context** — already injected above. Run `npx shadcn@
|
|
169
|
+
1. **Get project context** — already injected above. Run `npx shadcn@latest info` again if you need to refresh.
|
|
170
170
|
2. **Check installed components first** — before running `add`, always check the `components` list from project context or list the `resolvedPaths.ui` directory. Don't import components that haven't been added, and don't re-add ones already installed.
|
|
171
|
-
3. **Find components** — `npx shadcn@
|
|
172
|
-
4. **Get docs and examples** — use the MCP tool `shadcn_get_item_examples_from_registries` with query strings like `'button demo'` or `'login block example'` to see exact implementations. To preview changes to installed components, use `npx shadcn@
|
|
173
|
-
5. **Install or update** — `npx shadcn@
|
|
174
|
-
6. **Fix imports in third-party components** — After adding components from community registries (e.g. `@bundui`, `@magicui`), check the added non-UI files for hardcoded import paths like `@/components/ui/...`. These won't match the project's actual aliases. Use `npx shadcn@
|
|
171
|
+
3. **Find components** — `npx shadcn@latest search`.
|
|
172
|
+
4. **Get docs and examples** — use the MCP tool `shadcn_get_item_examples_from_registries` with query strings like `'button demo'` or `'login block example'` to see exact implementations. To preview changes to installed components, use `npx shadcn@latest add --diff`.
|
|
173
|
+
5. **Install or update** — `npx shadcn@latest add`. When updating existing components, use `--dry-run` and `--diff` to preview changes first (see [Updating Components](#updating-components) below).
|
|
174
|
+
6. **Fix imports in third-party components** — After adding components from community registries (e.g. `@bundui`, `@magicui`), check the added non-UI files for hardcoded import paths like `@/components/ui/...`. These won't match the project's actual aliases. Use `npx shadcn@latest info` to get the correct `ui` alias (e.g. `@workspace/ui/components`) and rewrite the imports accordingly. The CLI rewrites imports for its own UI files, but third-party registry components may use default paths that don't match the project.
|
|
175
175
|
7. **Review added components** — After adding a component or block from any registry, **always read the added files and verify they are correct**. Check for missing sub-components (e.g. `SelectItem` without `SelectGroup`), missing imports, incorrect composition, or violations of the [Critical Rules](#critical-rules). Also replace any icon imports with the project's `iconLibrary` from the project context (e.g. if the registry item uses `lucide-react` but the project uses `hugeicons`, swap the imports and icon names accordingly). Fix all issues before moving on.
|
|
176
176
|
8. **Registry must be explicit** — When the user asks to add a block or component, **do not guess the registry**. If no registry is specified (e.g. user says "add a login block" without specifying `@shadcn`, `@tailark`, `owner/repo`, etc.), ask which registry to use. Never default to a registry on behalf of the user.
|
|
177
177
|
9. **Switching presets** — Ask the user first: **overwrite**, **partial**, **merge**, or **skip**?
|
|
178
|
-
- **Inspect current preset**: `npx shadcn@
|
|
179
|
-
- **Inspect incoming preset**: `npx shadcn@
|
|
180
|
-
- **Overwrite**: `npx shadcn@
|
|
181
|
-
- **Partial**: `npx shadcn@
|
|
182
|
-
- **Merge**: `npx shadcn@
|
|
183
|
-
- **Skip**: `npx shadcn@
|
|
178
|
+
- **Inspect current preset**: `npx shadcn@latest preset resolve`. Use `--json` when you need structured values.
|
|
179
|
+
- **Inspect incoming preset**: `npx shadcn@latest preset decode <code>`. Use `preset url <code>` or `preset open <code>` to share or open the preset builder.
|
|
180
|
+
- **Overwrite**: `npx shadcn@latest apply <code>`. Overwrites detected components, fonts, and CSS variables.
|
|
181
|
+
- **Partial**: `npx shadcn@latest apply <code> --only theme,font`. Updates only the selected preset parts without reinstalling UI components. Supported values are `theme` and `font`; comma-separated combinations are allowed. `icon` is intentionally not supported, because icon changes may require full component reinstall and transforms.
|
|
182
|
+
- **Merge**: `npx shadcn@latest init --preset <code> --force --no-reinstall`, then run `npx shadcn@latest info` to list installed components, then for each installed component use `--dry-run` and `--diff` to [smart merge](#updating-components) it individually.
|
|
183
|
+
- **Skip**: `npx shadcn@latest init --preset <code> --force --no-reinstall`. Only updates config and CSS, leaves components as-is.
|
|
184
184
|
- **Important**: Always run preset commands inside the user's project directory. `apply` only works in an existing project with a `components.json` file. The CLI automatically preserves the current base (`base` vs `radix`) from `components.json`. If you must use a scratch/temp directory (e.g. for `--dry-run` comparisons), pass `--base <current-base>` explicitly — preset codes do not encode the base.
|
|
185
185
|
|
|
186
186
|
## Updating Components
|
|
187
187
|
|
|
188
188
|
When the user asks to update a component from upstream while keeping their local changes, use `--dry-run` and `--diff` to intelligently merge. **NEVER fetch raw files from GitHub manually — always use the CLI.**
|
|
189
189
|
|
|
190
|
-
1. Run `npx shadcn@
|
|
191
|
-
2. For each file, run `npx shadcn@
|
|
190
|
+
1. Run `npx shadcn@latest add <component> --dry-run` to see all files that would be affected.
|
|
191
|
+
2. For each file, run `npx shadcn@latest add <component> --diff <file>` to see what changed upstream vs local.
|
|
192
192
|
3. Decide per file based on the diff:
|
|
193
193
|
- No local changes → safe to overwrite.
|
|
194
194
|
- Has local changes → read the local file, analyze the diff, and apply upstream updates while preserving local modifications.
|
|
@@ -199,55 +199,55 @@ When the user asks to update a component from upstream while keeping their local
|
|
|
199
199
|
|
|
200
200
|
```bash
|
|
201
201
|
# Create a new project.
|
|
202
|
-
npx shadcn@
|
|
203
|
-
npx shadcn@
|
|
202
|
+
npx shadcn@latest init --name my-app --preset base-nova
|
|
203
|
+
npx shadcn@latest init --name my-app --preset a2r6bw --template vite
|
|
204
204
|
|
|
205
205
|
# Create a monorepo project.
|
|
206
|
-
npx shadcn@
|
|
207
|
-
npx shadcn@
|
|
206
|
+
npx shadcn@latest init --name my-app --preset base-nova --monorepo
|
|
207
|
+
npx shadcn@latest init --name my-app --preset base-nova --template next --monorepo
|
|
208
208
|
|
|
209
209
|
# Initialize existing project.
|
|
210
|
-
npx shadcn@
|
|
211
|
-
npx shadcn@
|
|
210
|
+
npx shadcn@latest init --preset base-nova
|
|
211
|
+
npx shadcn@latest init --defaults # shortcut: --template=next --preset=nova (base style implied)
|
|
212
212
|
|
|
213
213
|
# Apply a preset to an existing project.
|
|
214
|
-
npx shadcn@
|
|
215
|
-
npx shadcn@
|
|
216
|
-
npx shadcn@
|
|
217
|
-
npx shadcn@
|
|
214
|
+
npx shadcn@latest apply a2r6bw
|
|
215
|
+
npx shadcn@latest apply a2r6bw --only theme
|
|
216
|
+
npx shadcn@latest apply a2r6bw --only font
|
|
217
|
+
npx shadcn@latest apply a2r6bw --only theme,font
|
|
218
218
|
|
|
219
219
|
# Inspect preset codes and project preset state.
|
|
220
|
-
npx shadcn@
|
|
221
|
-
npx shadcn@
|
|
222
|
-
npx shadcn@
|
|
223
|
-
npx shadcn@
|
|
224
|
-
npx shadcn@
|
|
220
|
+
npx shadcn@latest preset decode a2r6bw
|
|
221
|
+
npx shadcn@latest preset url a2r6bw
|
|
222
|
+
npx shadcn@latest preset open a2r6bw
|
|
223
|
+
npx shadcn@latest preset resolve
|
|
224
|
+
npx shadcn@latest preset resolve --json
|
|
225
225
|
|
|
226
226
|
# Add components.
|
|
227
|
-
npx shadcn@
|
|
228
|
-
npx shadcn@
|
|
229
|
-
npx shadcn@
|
|
230
|
-
npx shadcn@
|
|
227
|
+
npx shadcn@latest add button card dialog
|
|
228
|
+
npx shadcn@latest add @magicui/shimmer-button
|
|
229
|
+
npx shadcn@latest add owner/repo/item
|
|
230
|
+
npx shadcn@latest add --all
|
|
231
231
|
|
|
232
232
|
# Preview changes before adding/updating.
|
|
233
|
-
npx shadcn@
|
|
234
|
-
npx shadcn@
|
|
235
|
-
npx shadcn@
|
|
236
|
-
npx shadcn@
|
|
233
|
+
npx shadcn@latest add button --dry-run
|
|
234
|
+
npx shadcn@latest add button --diff button.tsx
|
|
235
|
+
npx shadcn@latest add @acme/form --view button.tsx
|
|
236
|
+
npx shadcn@latest add owner/repo/item --dry-run
|
|
237
237
|
|
|
238
238
|
# Search registries.
|
|
239
|
-
npx shadcn@
|
|
240
|
-
npx shadcn@
|
|
241
|
-
npx shadcn@
|
|
242
|
-
npx shadcn@
|
|
243
|
-
npx shadcn@
|
|
239
|
+
npx shadcn@latest search @shadcn -q "sidebar"
|
|
240
|
+
npx shadcn@latest search @tailark -q "stats"
|
|
241
|
+
npx shadcn@latest search owner/repo -q "login"
|
|
242
|
+
npx shadcn@latest search # all configured registries
|
|
243
|
+
npx shadcn@latest search @shadcn -q "menu" -t ui # filter by item type
|
|
244
244
|
|
|
245
245
|
# Get component docs and example URLs.
|
|
246
246
|
# ALWAYS use your MCP Tools (shadcn_get_item_examples_from_registries) instead of bash for docs.
|
|
247
247
|
|
|
248
248
|
# View registry item details (for items not yet installed).
|
|
249
|
-
npx shadcn@
|
|
250
|
-
npx shadcn@
|
|
249
|
+
npx shadcn@latest view @shadcn/button
|
|
250
|
+
npx shadcn@latest view owner/repo/item
|
|
251
251
|
```
|
|
252
252
|
|
|
253
253
|
**Named presets:** `nova`, `vega`, `maia`, `lyra`, `mira`, `luma`
|
|
@@ -73,13 +73,16 @@ npx shadcn@latest add <component-name>
|
|
|
73
73
|
Al diseñar o codificar páginas con Shadcn UI, sigue estas reglas estrictas:
|
|
74
74
|
|
|
75
75
|
### 3.1 Componer, no reinventar (MANDATORIO)
|
|
76
|
-
Utiliza las plantillas y bloques existentes de Shadcn como el estándar absoluto de tu interfaz. Queda **estrictamente prohibido** escribir layouts, páginas de autenticación o cuadros de mando desde cero si ya existe un bloque oficial que resuelva el caso de uso:
|
|
77
|
-
- **Dashboards**: Utiliza `dashboard-01`
|
|
76
|
+
Utiliza las plantillas y bloques existentes de Shadcn como el estándar absoluto de tu interfaz. Queda **estrictamente prohibido** escribir layouts, páginas de autenticación o cuadros de mando desde cero si ya existe un bloque oficial que resuelva el caso de uso. **No estás restringido a ningún subconjunto fijo de componentes**: tienes total libertad para buscar en el catálogo completo de 97+ bloques oficiales y componentes primitivos de Shadcn:
|
|
77
|
+
- **Dashboards**: Utiliza `dashboard-01` o cualquier variante de panel de control interactivo oficial.
|
|
78
78
|
- **Sidebars / Barras de Navegación**: Utiliza `sidebar-01` al `16` para paneles laterales funcionales, colapsables, dinámicos o anidados. No programes componentes de navegación complejos a mano.
|
|
79
79
|
- **Login / Registro**: Utiliza `login-01` al `05` y `signup-01` al `05` para flujos de login y registro de usuarios.
|
|
80
80
|
- **Gráficos y Métricas**: Busca y añade bloques de gráficos oficiales de Recharts (`chart-area-*`, `chart-bar-*`, `chart-pie-*`, `chart-radar-*`) para dar vida a la visualización de datos.
|
|
81
81
|
|
|
82
|
-
Busca layouts de dashboards o formularios complejos en el registro mediante el MCP `shadcn` antes de escribir cualquier código personalizado. Una vez agregado el bloque, distribuye y adapta sus elementos con el estado y la lógica de tu aplicación.
|
|
82
|
+
Busca layouts de dashboards o formularios complejos en el registro mediante el MCP `shadcn` antes de escribir cualquier código personalizado. Una vez agregado el bloque, distribuye y adapta sus elementos con el estado y la lógica de tu aplicación. Te motivamos a explorar todo el ecosistema de bloques pre-creados por Shadcn para armar una UI robusta y moderna.
|
|
83
|
+
|
|
84
|
+
**REGLA CRÍTICA DE RUTAS DUPLICADAS POR SHADCN CLI**:
|
|
85
|
+
Al agregar un bloque interactivo complejo (como `dashboard-01`), el CLI de Shadcn puede inyectar automáticamente archivos en directorios fijos (como `src/app/dashboard/page.tsx`). El Coder **debe** verificar inmediatamente si existe una colisión con la estructura de rutas establecida por el contrato (`contract.json`) —por ejemplo, si el contrato establece un Route Group `src/app/(dashboard)/page.tsx` que sirve en la raíz `/`—. Si ocurre esto, el Coder tiene la obligación de **borrar, mover o refactorizar de inmediato el archivo inyectado automáticamente** para eliminar la duplicidad de rutas, evitando así bucles infinitos de redirección o errores fatales de compilación del router de Next.js.
|
|
83
86
|
|
|
84
87
|
### 3.2 Form Layouts (FieldGroup + Field)
|
|
85
88
|
Para estructurar campos de formularios, no uses `div`s arbitrarios con clases de espaciado complejas. Usa las composiciones semánticas oficiales de Shadcn:
|
|
@@ -109,25 +112,19 @@ Para estructurar campos de formularios, no uses `div`s arbitrarios con clases de
|
|
|
109
112
|
### 3.4 Sin Placeholders en Producción
|
|
110
113
|
Los datos dummy y placeholders deben reemplazarse inmediatamente por estados y hooks reales en el frontend que llamen a las APIs del backend (ej. estados de carga, manejo de errores de llamada, y datos dinámicos).
|
|
111
114
|
|
|
112
|
-
### 3.5
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
El diseño debe ser profesional y generar impacto visual instantáneo. Sigue estas directrices:
|
|
116
|
-
- **Estructura de Layout Completa**: Toda herramienta, calculadora o pantalla debe estar contenida en un layout profesional. Usa barras de navegación superiores (`Header`), paneles laterales colapsables (`Sidebar`), menús de usuario con avatares, y una barra de estado o pie de página.
|
|
117
|
-
- **Grids de KPIs y Métricas**: Añade tarjetas estadísticas en la parte superior de la página para resumir datos clave (ej. número de cálculos realizados, tiempo de respuesta promedio, tasa de éxito) utilizando iconos, números destacados y pequeños indicadores porcentuales.
|
|
118
|
-
- **Gráficos e Historiales**: Si hay tablas o historiales, hazlos interactivos. Usa bordes redondeados (`rounded-xl`), sombras suaves, efectos de hover en las filas y, de ser posible, integra gráficos modernos (ej. utilizando `@/components/ui/chart` o Recharts) para representar tendencias.
|
|
119
|
-
- **Colores Semánticos y Gradientes**: Utiliza gradientes sutiles y la paleta de colores HSL/OKLCH del tema en lugar de colores puros. Asegúrate de que el botón de cambiar tema (Modo Claro/Oscuro) esté visible en la barra de navegación y funcione de manera impecable.
|
|
120
|
-
- **Estados Dinámicos y Micro-animaciones**: Añade pequeños efectos de transición y hover (`transition-all duration-200`) en botones, inputs y tarjetas para que la interfaz se sienta "viva" y responda a las acciones del usuario.
|
|
115
|
+
### 3.5 Reglas de Diseño y Estándares de Calidad (Consolidadas)
|
|
116
|
+
* **Estándar Semántico**: Consulta y aplica estrictamente la **Sección 5 de `.opencode/rules/sdd-global.md`** para la prevención de colores fijos (hardcoded light/dark), sincronización de temas en gráficos Recharts, prevención de solapamientos del sidebar (Sidebar Overlap) y la regla de no anidamiento en triggers de Radix.
|
|
117
|
+
* **Componentes de Calidad**: Toda interfaz debe estar pulida con skeletons de carga fluidos, empty states agradables con iconos ilustrativos, y tooltips descriptivos para cualquier botón basado únicamente en iconos.
|
|
121
118
|
|
|
122
119
|
---
|
|
123
120
|
|
|
124
121
|
## 4. Flujo de Trabajo en SDD
|
|
125
122
|
|
|
126
123
|
### Fase F1 (Spec-Driven Contract)
|
|
127
|
-
El `@sdd-spec-writer` utiliza el MCP `shadcn` (`
|
|
124
|
+
El `@sdd-spec-writer` utiliza de manera proactiva el MCP `shadcn` (`shadcn_search_items_in_registries`, `shadcn_list_items_in_registries`) para encontrar bloques. **Es obligatorio** usar la herramienta `shadcn_view_items_in_registries` para inspeccionar el contenido completo, la estructura de archivos y las dependencias del bloque seleccionado antes de cerrar el contrato. Esto le permite al Spec-Writer mapear con exactitud los archivos que se generarán en `files_affected` y documentar explícitamente cualquier potencial colisión de ruteo en el `contract.json`.
|
|
128
125
|
|
|
129
126
|
### Fase F2 (Implementation)
|
|
130
|
-
El `@sdd-coder` utiliza el template base `nextjs-shadcn`
|
|
127
|
+
El `@sdd-coder` utiliza el template base `nextjs-shadcn`. Si el contrato no detalla todos los sub-componentes o el Coder necesita verificar el comportamiento de un bloque antes de acoplarlo con el backend, debe ejecutar `shadcn_get_item_examples_from_registries` para ver ejemplos funcionales del componente real. Tras ejecutar la instalación con `npx shadcn@latest add`, el Coder debe contrastar los archivos inyectados con el mapa del contrato y limpiar de inmediato cualquier archivo redundante (como una página de inicio duplicada) que no coincida con el router oficial.
|
|
131
128
|
|
|
132
129
|
### Fase F3 (Verification)
|
|
133
130
|
El `@sdd-tester` ejecuta las pruebas según el modo de verificación especificado en el contrato (`settings.verificationMode`):
|
|
@@ -66,11 +66,12 @@ Para garantizar consistencia y escalabilidad en todos los proyectos, la estructu
|
|
|
66
66
|
className={cn("base-classes", condition && "extra", className)}
|
|
67
67
|
```
|
|
68
68
|
5. **Iconos**: usar `lucide-react` (`import { Icon } from "lucide-react"`).
|
|
69
|
-
6. **Block/Template installation**: usar el MCP `shadcn` para browse/search/install:
|
|
70
|
-
- Dashboards →
|
|
69
|
+
6. **Block/Template installation**: usar el MCP `shadcn` para browse/search/install. **NOTA CRÍTICA: NO existe ninguna restricción de lista fija**. Tienes libertad absoluta y la obligación proactiva de buscar e instalar CUALQUIER componente primitivo o bloque del catálogo oficial de Shadcn UI que se adapte al caso de uso de la aplicación (entre los 97+ bloques disponibles como dashboards, sidebars colapsables, login, charts, etc.):
|
|
70
|
+
- Dashboards → `@shadcn/dashboard-01`
|
|
71
71
|
- Landings → `@shadcn/landing-hero`, `@shadcn/pricing`, etc.
|
|
72
|
-
- Auth flows → `@shadcn/login-01`, `@shadcn/signup-01`
|
|
72
|
+
- Auth flows → `@shadcn/login-01` al `05`, `@shadcn/signup-01` al `05`
|
|
73
73
|
- Forms complejos → `@shadcn/settings`, `@shadcn/data-table`
|
|
74
|
+
- Sidebars → `@shadcn/sidebar-01` al `16`
|
|
74
75
|
7. **Shadcn v4 (Base UI)**: En Shadcn UI v4.11.0+, la biblioteca primitiva es `@base-ui/react` (no Radix UI). La propiedad `asChild` **no existe**. Para evitar HTML inválido y problemas de SEO/accesibilidad, no anides interactives (`<Button><Link>`). Aplica las clases de estilo del botón directamente sobre el elemento `<Link>` de Next.js.
|
|
75
76
|
8. **Compatibilidad Turbopack + CSS**: Turbopack no resuelve directivas `@import` para archivos CSS de `node_modules` (ej. `@import "tw-animate-css"` o `@import "shadcn/tailwind.css"`). En Tailwind CSS v4, define las variables y estilos inline en `globals.css` en lugar de importar desde `node_modules`.
|
|
76
77
|
9. **Despliegue y Next Config**: Todo proyecto de Next.js debe estar configurado para Docker standalone en `next.config.ts`:
|
package/.opencode/tools/brain.ts
CHANGED
|
@@ -75,7 +75,7 @@ const writeBrainFile = (filePath: string, title: string, sections: Record<string
|
|
|
75
75
|
}
|
|
76
76
|
|
|
77
77
|
export const save_memory = tool({
|
|
78
|
-
description: "Guarda
|
|
78
|
+
description: "Guarda una memoria o aprendizaje clave en .openspec/brain.md de forma acumulativa.",
|
|
79
79
|
args: {
|
|
80
80
|
category: tool.schema.string().describe("Categoría o sección donde clasificar la memoria (ej: 'design', 'learnings', 'routing', 'errors')"),
|
|
81
81
|
content: tool.schema.string().describe("El contenido o aprendizaje exacto que se desea guardar. Se recomienda ser conciso y claro.")
|
|
@@ -115,7 +115,7 @@ export const save_memory = tool({
|
|
|
115
115
|
})
|
|
116
116
|
|
|
117
117
|
export const read_memory = tool({
|
|
118
|
-
description: "Recupera la memoria y los aprendizajes del proyecto
|
|
118
|
+
description: "Recupera la memoria y los aprendizajes del proyecto de .openspec/brain.md.",
|
|
119
119
|
args: {
|
|
120
120
|
category: tool.schema.string().optional().describe("La categoría específica a leer (ej: 'design', 'learnings', 'routing', 'errors'). Si no se provee, se listarán las categorías disponibles.")
|
|
121
121
|
},
|
|
@@ -101,7 +101,7 @@ function detectPythonPackageManager(root: string): "uv" | "pip" {
|
|
|
101
101
|
|
|
102
102
|
// Tool: sdd_bootstrap_status
|
|
103
103
|
export const bootstrap_status = tool({
|
|
104
|
-
description: "Reporta el estado de bootstrap del proyecto
|
|
104
|
+
description: "Reporta el estado de bootstrap del proyecto.",
|
|
105
105
|
args: {},
|
|
106
106
|
async execute(args, context) {
|
|
107
107
|
const root = getRoot(context)
|
|
@@ -143,7 +143,7 @@ export const bootstrap_status = tool({
|
|
|
143
143
|
|
|
144
144
|
// Tool: sdd_bootstrap_nextjs_shadcn
|
|
145
145
|
export const bootstrap_nextjs_shadcn = tool({
|
|
146
|
-
description: "Inicializa un proyecto Next.js 16 + Shadcn UI + Tailwind v4 + Vitest
|
|
146
|
+
description: "Inicializa un proyecto Next.js 16 + Shadcn UI + Tailwind v4 + Vitest.",
|
|
147
147
|
args: {
|
|
148
148
|
targetDir: tool.schema.string().default(".").describe("Subdirectorio donde se inicializará el proyecto Next.js (ej: 'next-app' o '.')."),
|
|
149
149
|
components: tool.schema.array(tool.schema.string()).default([]).describe("Lista de shadcn components a instalar (ej: ['button','input','table']). Vacío = no instalar shadcn components."),
|
|
@@ -297,7 +297,7 @@ export const bootstrap_nextjs_shadcn = tool({
|
|
|
297
297
|
let componentsError: string | null = null
|
|
298
298
|
if (args.components && args.components.length > 0) {
|
|
299
299
|
try {
|
|
300
|
-
const cmd = `npx shadcn@
|
|
300
|
+
const cmd = `npx shadcn@latest add ${args.components.join(" ")} --yes --overwrite`
|
|
301
301
|
execSync(cmd, {
|
|
302
302
|
cwd: targetPath,
|
|
303
303
|
stdio: "ignore",
|
|
@@ -353,7 +353,7 @@ export const bootstrap_nextjs_shadcn = tool({
|
|
|
353
353
|
|
|
354
354
|
// Tool: sdd_bootstrap_fastapi
|
|
355
355
|
export const bootstrap_fastapi = tool({
|
|
356
|
-
description: "Inicializa un proyecto FastAPI + Pydantic + Uvicorn + Pytest + Ruff
|
|
356
|
+
description: "Inicializa un proyecto FastAPI + Pydantic + Uvicorn + Pytest + Ruff.",
|
|
357
357
|
args: {
|
|
358
358
|
targetDir: tool.schema.string().default(".").describe("Subdirectorio donde se inicializará el proyecto FastAPI (ej: 'backend' o '.')."),
|
|
359
359
|
extras: tool.schema.array(tool.schema.string()).default([]).describe("Lista de paquetes Python adicionales a instalar (ej: ['sqlalchemy','pydantic-settings','pytest-asyncio']). Vacío = no instalar extras extra."),
|
|
@@ -543,7 +543,7 @@ export const bootstrap_fastapi = tool({
|
|
|
543
543
|
|
|
544
544
|
// Tool: sdd_bootstrap_agnostic
|
|
545
545
|
export const bootstrap_agnostic = tool({
|
|
546
|
-
description: "Inicializa un proyecto de tipo script, tooling o agnóstico de forma idempotente
|
|
546
|
+
description: "Inicializa un proyecto de tipo script, tooling o agnóstico de forma idempotente.",
|
|
547
547
|
args: {
|
|
548
548
|
language: tool.schema.enum(["javascript", "python", "bash", "google-apps-script", "plano"]).default("plano").describe("El lenguaje o entorno para inicializar"),
|
|
549
549
|
install: tool.schema.boolean().default(true).describe("Si true, ejecuta npm init -y o uv init de forma básica si aplica.")
|
|
@@ -248,7 +248,7 @@ const getPidFilePath = (root: string) => {
|
|
|
248
248
|
|
|
249
249
|
// Tool: sdd_set_phase (file sdd_core.ts, export set_phase -> sdd_set_phase)
|
|
250
250
|
export const set_phase = tool({
|
|
251
|
-
description: "Establece la fase activa del ciclo de desarrollo SDD
|
|
251
|
+
description: "Establece la fase activa del ciclo de desarrollo SDD.",
|
|
252
252
|
args: {
|
|
253
253
|
phase: tool.schema.enum(["F0_DETECT", "F1_CONTRACT", "F2_IMPLEMENTATION", "F3_VERIFICATION", "F4_DEPLOYMENT"]).describe("La fase a establecer"),
|
|
254
254
|
activeContract: tool.schema.string().optional().describe("La ruta o nombre del archivo de contrato JSON activo (.openspec/specs/XXXX_TIMESTAMP_NAME/contract.json)"),
|
|
@@ -431,7 +431,7 @@ export const set_phase = tool({
|
|
|
431
431
|
|
|
432
432
|
// Tool: sdd_get_state (file sdd_core.ts, export get_state -> sdd_get_state)
|
|
433
433
|
export const get_state = tool({
|
|
434
|
-
description: "Obtiene el estado de desarrollo actual
|
|
434
|
+
description: "Obtiene el estado de desarrollo actual.",
|
|
435
435
|
args: {},
|
|
436
436
|
async execute(args, context) {
|
|
437
437
|
const filePath = getStateFilePath(context)
|
|
@@ -442,7 +442,7 @@ export const get_state = tool({
|
|
|
442
442
|
|
|
443
443
|
// Tool: sdd_get_initial_session_data
|
|
444
444
|
export const get_initial_session_data = tool({
|
|
445
|
-
description: "Obtiene
|
|
445
|
+
description: "Obtiene de forma atómica el estado actual, memorias del Brain y recomendaciones Oh My Design.",
|
|
446
446
|
args: {},
|
|
447
447
|
async execute(args, context) {
|
|
448
448
|
const root = getRoot(context)
|
|
@@ -498,7 +498,7 @@ export const get_initial_session_data = tool({
|
|
|
498
498
|
|
|
499
499
|
// Tool: sdd_save_active_brief
|
|
500
500
|
export const save_active_brief = tool({
|
|
501
|
-
description: "Guarda un resumen
|
|
501
|
+
description: "Guarda un resumen del spec activo en .openspec/active-brief.md como anclaje de contexto.",
|
|
502
502
|
args: {
|
|
503
503
|
brief: tool.schema.string().describe("Contenido en formato Markdown con el resumen del spec activo, componentes, diseño y dependencias.")
|
|
504
504
|
},
|
|
@@ -558,7 +558,7 @@ export const save_active_brief = tool({
|
|
|
558
558
|
|
|
559
559
|
// Tool: sdd_create_spec_folder (file sdd_core.ts, export create_spec_folder -> sdd_create_spec_folder)
|
|
560
560
|
export const create_spec_folder = tool({
|
|
561
|
-
description: "Crea una nueva carpeta ordenada para la especificación del cambio
|
|
561
|
+
description: "Crea una nueva carpeta ordenada para la especificación del cambio.",
|
|
562
562
|
args: {
|
|
563
563
|
name: tool.schema.string().describe("Nombre del cambio en minúsculas y separado por guiones (ej. sumar-endpoint)")
|
|
564
564
|
},
|
|
@@ -593,7 +593,7 @@ export const create_spec_folder = tool({
|
|
|
593
593
|
|
|
594
594
|
// Tool: sdd_validate_contract
|
|
595
595
|
export const validate_contract = tool({
|
|
596
|
-
description: "Valida
|
|
596
|
+
description: "Valida contract.json contra el contract-schema.json oficial.",
|
|
597
597
|
args: {
|
|
598
598
|
contractPath: tool.schema.string().describe("Ruta relativa al contract.json (ej. '.openspec/specs/XXXX/contract.json')")
|
|
599
599
|
},
|
|
@@ -41,7 +41,7 @@ export const RECOMMENDED_BRANDS: Record<string, { id: string; name: string; cate
|
|
|
41
41
|
|
|
42
42
|
// Tool: sdd_select_design
|
|
43
43
|
export const select_design = tool({
|
|
44
|
-
description: "Copia fielmente el archivo DESIGN.md y
|
|
44
|
+
description: "Copia fielmente el archivo DESIGN.md y ejemplos de la marca a .openspec/",
|
|
45
45
|
args: {
|
|
46
46
|
brandId: tool.schema.string().describe("ID exacto del diseño en oh-my-design (ej: 'linear.app', 'vercel', 'stripe')")
|
|
47
47
|
},
|
|
@@ -128,7 +128,7 @@ async function selectDesignHelper(brandId: string, context: any) {
|
|
|
128
128
|
|
|
129
129
|
// Tool: sdd_list_design_recommendations
|
|
130
130
|
export const list_design_recommendations = tool({
|
|
131
|
-
description: "Devuelve una lista curada
|
|
131
|
+
description: "Devuelve una lista curada de marcas de diseño recomendadas.",
|
|
132
132
|
args: {
|
|
133
133
|
use_case: tool.schema.enum(["saas", "fintech", "ecommerce", "consumer", "all"]).default("all").describe("Categoría del proyecto para filtrar marcas relevantes"),
|
|
134
134
|
max_per_category: tool.schema.number().default(3).describe("Máximo de marcas a devolver por categoría"),
|
|
@@ -162,7 +162,7 @@ export const list_design_recommendations = tool({
|
|
|
162
162
|
|
|
163
163
|
// Tool: sdd_apply_brand_tokens
|
|
164
164
|
export const apply_brand_tokens = tool({
|
|
165
|
-
description: "Inyecta tokens de diseño de marca
|
|
165
|
+
description: "Inyecta tokens de diseño de marca en src/app/globals.css.",
|
|
166
166
|
args: {
|
|
167
167
|
tokens: tool.schema.string().describe("JSON stringificado con {colors: {...}, typography: {...}, radius: {...}} extraído de contract.json design.tokens"),
|
|
168
168
|
},
|
|
@@ -232,7 +232,7 @@ ${brandVarLines.join("\n")}
|
|
|
232
232
|
|
|
233
233
|
// Tool: sdd_validate_lucide_icons_batch
|
|
234
234
|
export const validate_lucide_icons_batch = tool({
|
|
235
|
-
description: "Valida un lote de nombres de iconos de Lucide React de forma rápida
|
|
235
|
+
description: "Valida un lote de nombres de iconos de Lucide React de forma rápida.",
|
|
236
236
|
args: {
|
|
237
237
|
icons: tool.schema.array(tool.schema.string()).describe("Lista de nombres de iconos a validar (ej: ['Sun', 'Moon', 'Plus'])"),
|
|
238
238
|
},
|
|
@@ -34,7 +34,7 @@ const getTargetDir = (root: string): string => {
|
|
|
34
34
|
|
|
35
35
|
// Tool: sdd_clean_docker_environment
|
|
36
36
|
export const clean_docker_environment = tool({
|
|
37
|
-
description: "Asegura que Docker esté abierto y realiza una limpieza total y agresiva
|
|
37
|
+
description: "Asegura que Docker esté abierto y realiza una limpieza total y agresiva.",
|
|
38
38
|
args: {},
|
|
39
39
|
async execute(args, context) {
|
|
40
40
|
const results: Record<string, string> = {}
|
|
@@ -114,7 +114,7 @@ export const clean_docker_environment = tool({
|
|
|
114
114
|
|
|
115
115
|
// Tool: sdd_generate_dockerfile
|
|
116
116
|
export const generate_dockerfile = tool({
|
|
117
|
-
description: "Genera Dockerfile
|
|
117
|
+
description: "Genera Dockerfile, .dockerignore y docker-compose.yml optimizados para el stack.",
|
|
118
118
|
args: {
|
|
119
119
|
stack: tool.schema.enum(["nextjs", "fastapi", "agnostic"]).describe("Stack del proyecto"),
|
|
120
120
|
port: tool.schema.number().default(3000).describe("Puerto de la aplicación"),
|
|
@@ -39,7 +39,7 @@ const getPidFilePath = (root: string) => {
|
|
|
39
39
|
|
|
40
40
|
// Tool: sdd_free_port
|
|
41
41
|
export const free_port = tool({
|
|
42
|
-
description: "
|
|
42
|
+
description: "Libera un puerto específico de forma forzada.",
|
|
43
43
|
args: {
|
|
44
44
|
port: tool.schema.number().describe("El puerto a liberar (ej. 3000 o 8000)")
|
|
45
45
|
},
|
|
@@ -69,7 +69,7 @@ export const free_port = tool({
|
|
|
69
69
|
|
|
70
70
|
// Tool: sdd_start_server
|
|
71
71
|
export const start_server = tool({
|
|
72
|
-
description: "Inicia un servidor
|
|
72
|
+
description: "Inicia un servidor en segundo plano y registra su PID.",
|
|
73
73
|
args: {
|
|
74
74
|
command: tool.schema.string().describe("Comando para iniciar el servidor (ej. 'yarn dev' o 'npm run dev')"),
|
|
75
75
|
port: tool.schema.number().optional().default(3000).describe("Puerto esperado del servidor (default: 3000)"),
|
|
@@ -132,7 +132,7 @@ export const start_server = tool({
|
|
|
132
132
|
|
|
133
133
|
// Tool: sdd_stop_server
|
|
134
134
|
export const stop_server = tool({
|
|
135
|
-
description: "Detiene el servidor en segundo plano
|
|
135
|
+
description: "Detiene el servidor en segundo plano registrado.",
|
|
136
136
|
args: {},
|
|
137
137
|
async execute(args, context) {
|
|
138
138
|
const root = getRoot(context)
|
|
@@ -10,7 +10,7 @@ const getRoot = (context: any) => {
|
|
|
10
10
|
};
|
|
11
11
|
|
|
12
12
|
export default tool({
|
|
13
|
-
description: "Obtiene
|
|
13
|
+
description: "Obtiene el estado unificado del ciclo SDD y un resumen de las categorías del Brain.",
|
|
14
14
|
args: {},
|
|
15
15
|
async execute(args, context) {
|
|
16
16
|
const root = getRoot(context)
|
|
@@ -71,7 +71,7 @@ const parseSemanticErrors = (rawOutput: string, type: "eslint" | "tsc"): any[] =
|
|
|
71
71
|
|
|
72
72
|
// Tool: sdd_quick_lint
|
|
73
73
|
export const quick_lint = tool({
|
|
74
|
-
description: "Ejecuta el linter del proyecto (eslint) restringido a src/.
|
|
74
|
+
description: "Ejecuta el linter del proyecto (eslint) restringido a src/.",
|
|
75
75
|
args: {},
|
|
76
76
|
async execute(args, context) {
|
|
77
77
|
const root = getRoot(context)
|
|
@@ -140,7 +140,7 @@ export const quick_lint = tool({
|
|
|
140
140
|
|
|
141
141
|
// Tool: sdd_shift_left_verify
|
|
142
142
|
export const shift_left_verify = tool({
|
|
143
|
-
description: "Ejecuta validaciones estáticas Shift-Left completas
|
|
143
|
+
description: "Ejecuta validaciones estáticas Shift-Left completas (tsc + eslint) combinadas.",
|
|
144
144
|
args: {},
|
|
145
145
|
async execute(args, context) {
|
|
146
146
|
const root = getRoot(context)
|
|
@@ -323,7 +323,7 @@ export const shift_left_verify = tool({
|
|
|
323
323
|
|
|
324
324
|
// Tool: sdd_generate_tests
|
|
325
325
|
export const generate_tests = tool({
|
|
326
|
-
description: "Autogenera plantillas de pruebas
|
|
326
|
+
description: "Autogenera plantillas de pruebas a partir de los escenarios del contrato activo.",
|
|
327
327
|
args: {},
|
|
328
328
|
async execute(args, context) {
|
|
329
329
|
const root = getRoot(context)
|
|
@@ -442,7 +442,7 @@ export const generate_tests = tool({
|
|
|
442
442
|
|
|
443
443
|
// Tool: sdd_save_playwright_artifacts
|
|
444
444
|
export const save_playwright_artifacts = tool({
|
|
445
|
-
description: "Promueve y archiva los artefactos de
|
|
445
|
+
description: "Promueve y archiva los artefactos de Playwright a la carpeta del contrato activo.",
|
|
446
446
|
args: {
|
|
447
447
|
callId: tool.schema.string().optional().describe("ID de llamada de Playwright MCP específica. Si no se pasa, toma la última ejecución de forma automática."),
|
|
448
448
|
move: tool.schema.boolean().default(false).describe("Si true, mueve los archivos en lugar de copiarlos.")
|
|
@@ -9,7 +9,7 @@ DB_PATH = "/Users/wavesbyte/.local/share/opencode/opencode.db"
|
|
|
9
9
|
|
|
10
10
|
# Escribe aquí el ID de la sesión que deseas exportar (ejemplo: "ses_1234...")
|
|
11
11
|
# Si se deja vacío, el script requerirá el ID como argumento al ejecutarlo
|
|
12
|
-
TARGET_SESSION_ID = "
|
|
12
|
+
TARGET_SESSION_ID = "ses_11a7"
|
|
13
13
|
|
|
14
14
|
|
|
15
15
|
def format_timestamp(ts):
|
package/opencode.json
CHANGED
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
"./.opencode/oh-my-design/packages/mcp/dist/index.mjs"
|
|
44
44
|
],
|
|
45
45
|
"enabled": true,
|
|
46
|
-
"purpose": "
|
|
46
|
+
"purpose": "Busca, consulta y aplica temas de diseño (Toss, Stripe, Supabase, etc.)."
|
|
47
47
|
},
|
|
48
48
|
"shadcn": {
|
|
49
49
|
"type": "local",
|
|
@@ -54,7 +54,7 @@
|
|
|
54
54
|
"mcp"
|
|
55
55
|
],
|
|
56
56
|
"enabled": true,
|
|
57
|
-
"purpose": "
|
|
57
|
+
"purpose": "Usa para browse/search/install de componentes y blocks oficiales de Shadcn UI."
|
|
58
58
|
},
|
|
59
59
|
"context7": {
|
|
60
60
|
"type": "local",
|
|
@@ -76,7 +76,7 @@
|
|
|
76
76
|
"--isolated"
|
|
77
77
|
],
|
|
78
78
|
"enabled": true,
|
|
79
|
-
"purpose": "
|
|
79
|
+
"purpose": "Ejecuta pruebas de regresión visual y capturas de pantalla de Playwright."
|
|
80
80
|
},
|
|
81
81
|
"next-devtools": {
|
|
82
82
|
"type": "local",
|
|
@@ -89,7 +89,7 @@
|
|
|
89
89
|
"environment": {
|
|
90
90
|
"NEXT_TELEMETRY_DISABLED": "1"
|
|
91
91
|
},
|
|
92
|
-
"purpose": "Toolchain oficial
|
|
92
|
+
"purpose": "Toolchain oficial para depurar Next.js 16 (deshabilitado por defecto)."
|
|
93
93
|
},
|
|
94
94
|
"lucide-icons": {
|
|
95
95
|
"type": "local",
|
|
@@ -100,7 +100,7 @@
|
|
|
100
100
|
"--stdio"
|
|
101
101
|
],
|
|
102
102
|
"enabled": true,
|
|
103
|
-
"purpose": "
|
|
103
|
+
"purpose": "Busca y obtiene ejemplos de uso de iconos de Lucide React."
|
|
104
104
|
}
|
|
105
105
|
}
|
|
106
106
|
}
|