zugzbot 1.0.39 → 1.0.41
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 +1 -1
- package/.opencode/agents/sdd-deployer.md +1 -1
- package/.opencode/agents/sdd-orchestrator.md +1 -1
- package/.opencode/agents/sdd-reviewer.md +1 -1
- package/.opencode/agents/sdd-spec-writer.md +1 -1
- package/.opencode/agents/sdd-tester.md +1 -1
- package/.opencode/rules/sdd-global.md +10 -3
- package/.opencode/skills/docker-templates/SKILL.md +7 -0
- package/.opencode/skills/sdd-methodology/SKILL.md +29 -65
- package/.opencode/skills/sdd-quickstart/SKILL.md +1 -0
- package/.opencode/skills/sdd-tester-quickstart/SKILL.md +41 -11
- package/.opencode/skills/shadcn-templates/SKILL.md +32 -18
- package/.opencode/tools/brain.ts +2 -2
- package/.opencode/tools/sdd_bootstrap.ts +4 -4
- 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/.utils/toggle_model.py +145 -168
- package/opencode.json +6 -6
- package/package.json +1 -1
|
@@ -22,11 +22,13 @@ Cuando el estado del sistema tiene `loopMode === true` (activado mediante el com
|
|
|
22
22
|
- **Specs Incrementales**: Si la petición es grande, el orquestador debe dividirla secuencialmente en contratos incrementales. Completa un spec por completo (F0->F4) y arranca el siguiente de inmediato de forma autónoma hasta finalizar todo el plan.
|
|
23
23
|
- **Rollback de Emergencia**: Si una misma fase falla de forma continua (más de 2 rollbacks), desactiva `loopMode` usando `sdd_set_phase` y solicita asistencia humana en el chat.
|
|
24
24
|
|
|
25
|
-
## 3. Uso Mandatorio de Bloques Prehechos de Shadcn UI
|
|
25
|
+
## 3. Uso Mandatorio de Bloques Prehechos de Shadcn UI - Estrategia "Block-First" (MANDATORIO)
|
|
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
|
-
- **
|
|
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
|
+
- **Inyección Zero-Touch y Migración Física en Fase A**: El Coder (F2) **debe** instalar el bloque usando `npx shadcn@latest add <block-name>`. Los archivos se descargarán en `src/components/blocks/<block-name>/`. Queda **estrictamente prohibido** importar el `page.tsx` del bloque como un simple componente hijo (ej: `return <BlockPage />` desde la raíz de la app), ya que esto rompe el router, layouts y metadata de Next.js. El Coder debe **copiar íntegramente el contenido del código** de `src/components/blocks/<block-name>/page.tsx` hacia el `page.tsx` de la ruta destino, y **reescribir todos los imports relativos** de componentes y datos locales (ej. `./components/...` o `./data.json`) para usar aliases absolutos que apunten a la ruta física descargada por Shadcn (ej. `@/components/blocks/<block-name>/components/...` o `@/components/blocks/<block-name>/data.json`). El archivo de datos locales `data.json` debe preservarse e importarse para garantizar un renderizado visual clonado perfecto.
|
|
30
|
+
- **Sustitución Atómica de Datos en Fase B**: Una vez que el bloque compila e interactúa en el navegador de manera idéntica al demo con los datos de ejemplo, el Coder procederá de forma exclusiva a sustituir los datos mock por lógica y fetchings de datos dinámicos del backend, manteniendo intactos los contenedores estructurales del bloque (grids de diseño, paddings y contenedores flex) sin alteración alguna para evitar aberraciones visuales.
|
|
31
|
+
- **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
32
|
|
|
31
33
|
## 4. Soporte para Subdirectorios, Monorepos (targetDir) y Estándar Corporativo `src/`
|
|
32
34
|
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 +44,9 @@ Cualquier desarrollo de interfaz de usuario (Dashboards, Landings, Formularios,
|
|
|
42
44
|
- 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
45
|
- **Gráficos Dinámicos y Reactivos (SVG/Recharts Theme Sync):**
|
|
44
46
|
- 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.
|
|
47
|
+
- 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.
|
|
48
|
+
- **Evitar Solapamiento de Sidebar (Sidebar Overlap Prevention):**
|
|
49
|
+
- 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
50
|
- **Robustez HTML y Regla de No-Nesting en Triggers:**
|
|
46
51
|
- 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
52
|
- 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.
|
|
@@ -54,6 +59,8 @@ Para evitar bucles de redirección ("redirect loops") y pantallas parpadeantes (
|
|
|
54
59
|
- **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.
|
|
55
60
|
- **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.
|
|
56
61
|
- **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).
|
|
62
|
+
- **Eliminación Obligatoria de Placeholders de Página Raíz:**
|
|
63
|
+
- 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.
|
|
57
64
|
|
|
58
65
|
## 7. Mockups Visuales y Validación Temprana de Layout (F0/F1)
|
|
59
66
|
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:
|
|
@@ -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,83 +41,47 @@ 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.
|
|
97
|
-
|
|
98
|
-
### Trampa 14: Guardar archivos de tests que contienen JSX con extensión `.ts` en vez de `.tsx`
|
|
99
|
-
**NO HAGAS**: Usar la extensión `.ts` para archivos de tests que mockean iconos de lucide o renderizan primitivas de HTML o JSX (esbuild/Vitest fallarán en la compilación con errores como `Expected ">" but found "data"`).
|
|
100
|
-
**HAZ**: Toda suite de pruebas unitarias o de integración que monte componentes o contenga JSX debe grabarse con la extensión `.tsx` obligatoriamente.
|
|
101
|
-
|
|
102
|
-
### Trampa 15: Selectores de Testing Library ambiguos para campos comunes
|
|
103
|
-
**NO HAGAS**: Usar queries amplias y con insensibilidad a mayúsculas como `screen.getByLabelText(/password/i)` si hay botones como "Show password" con `aria-label` que repiten la palabra clave. Esto lanzará un error de "Found multiple elements".
|
|
104
|
-
**HAZ**: Usa selectores de coincidencia exacta como `screen.getByLabelText(/^Password$/)` o busca mediante `screen.getByPlaceholderText(...)` para aislar de forma unívoca el input deseado.
|
|
105
|
-
|
|
106
|
-
### Trampa 16: Probar la ausencia de elementos ocultos por CSS con `not.toBeInTheDocument()`
|
|
107
|
-
**NO HAGAS**: Tratar de validar que un menú, etiqueta de barra lateral colapsada o modal ya no es visible utilizando `expect(queryByText("...")).not.toBeInTheDocument()`. Al ocultar layouts mediante clases CSS de ancho cero (`w-0`), opacidad (`opacity-0`) o display (`hidden`), los elementos siguen existiendo físicamente en el DOM de pruebas.
|
|
108
|
-
**HAZ**: Verifica las clases CSS de visibilidad directamente (ej. `expect(sidebarEl.className).toContain("w-16")`) o usa `.not.toBeVisible()` de `@testing-library/jest-dom`.
|
|
109
|
-
|
|
110
|
-
### Trampa 17: Mocks estáticos para toggles y hooks con estado
|
|
111
|
-
**NO HAGAS**: Mockear hooks que controlan transiciones (como `useTheme` de `next-themes`) con retornos fijos y estáticos, ej. `vi.mock('next-themes', () => ({ useTheme: () => ({ theme: 'light', setTheme: vi.fn() }) }))`. El segundo clic en el toggle intentará pasar de 'light' a 'dark' pero fallará porque el estado simulado sigue en 'light' (llamando a setTheme('dark') por segunda vez).
|
|
112
|
-
**HAZ**: Define variables mutables a nivel de archivo dentro de la suite de mocks y usa getters en la definición del mock para reflejar los cambios en caliente.
|
|
113
|
-
|
|
114
|
-
### Trampa 18: Fallos en resolución de `@import "shadcn/tailwind.css"` en Tailwind v4 con Next.js 16/Shadcn
|
|
115
|
-
**NO HAGAS**: Importar `@import "shadcn/tailwind.css"` en `globals.css` sin comprobar si el paquete npm `shadcn` está instalado en la máquina, provocando fallos fatales de compilación durante el comando `next build`.
|
|
116
|
-
**HAZ**: El coder siempre debe instalar explícitamente el paquete base ejecutable y estilizado `npm install shadcn` en proyectos Next + Tailwind v4.
|
|
117
|
-
|
|
118
|
-
### Trampa 19: Bucle infinito y parpadeo de pantalla (Flicker) tras el inicio de sesión
|
|
119
|
-
**NO HAGAS**: Usar redirecciones cruzadas en `useEffect` con `router.push()` tanto en el formulario de login como en la propia página de login, o renderizar spinners por defecto antes de verificar la sesión en el cliente, causando que el router encadene múltiples repeticiones de renderizado y la pantalla parpadee.
|
|
120
|
-
**HAZ**: Usa `router.replace()` para evitar ensuciar el historial. Proporciona siempre una bandera de montaje (`mounted === true`) y retorna `null` para evitar desajustes de hidratación (hydration mismatch). Protege las redirecciones del login mediante una referencia `useRef(false)` para controlar que no se solapen redirecciones de estado concurrentes de React.
|
|
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.
|
|
121
85
|
|
|
122
86
|
---
|
|
123
87
|
|
|
@@ -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
|
|
@@ -123,3 +132,24 @@ npx vitest run
|
|
|
123
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.
|
|
124
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.
|
|
125
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.
|
|
@@ -72,14 +72,34 @@ npx shadcn@latest add <component-name>
|
|
|
72
72
|
|
|
73
73
|
Al diseñar o codificar páginas con Shadcn UI, sigue estas reglas estrictas:
|
|
74
74
|
|
|
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` o cualquier variante de panel de control interactivo oficial.
|
|
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
|
-
- **Login / Registro**: Utiliza `login-01` al `05` y `signup-01` al `05` para flujos de login y registro de usuarios.
|
|
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.
|
|
75
|
+
### 3.1 Componer, no reinventar - Estrategia "Block-First" con Inyección Zero-Touch (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.
|
|
81
77
|
|
|
82
|
-
|
|
78
|
+
Para garantizar interfaces de usuario premium y visualmente idénticas a los demos oficiales de Shadcn, se debe seguir de manera mandatoria la **Metodología de Arquitectura Block-First**:
|
|
79
|
+
|
|
80
|
+
1. **El Bloque es el Esqueleto Absoluto (Fase A - Inyección Pura y Migración Física)**:
|
|
81
|
+
- El Coder (F2) **debe** instalar el bloque de Shadcn correspondiente mediante la CLI (`npx shadcn@latest add <block-name>`).
|
|
82
|
+
- El bloque se descargará en `src/components/blocks/<block-name>/`. El Coder tiene **estrictamente prohibido** importar el `page.tsx` del bloque como un simple componente hijo (ej: `return <BlockPage />` desde la raíz de la app), ya que esto rompe la estructura del router de Next.js, layouts y metadata.
|
|
83
|
+
- **Acción Obligatoria**: El Coder debe **copiar el contenido íntegro del código** de `src/components/blocks/<block-name>/page.tsx` hacia el `page.tsx` de tu ruta destino (por ejemplo, `src/app/page.tsx` o `src/app/dashboard/page.tsx`).
|
|
84
|
+
- **Corrección de Imports de forma Manual**: Al mover el código de la ruta de componentes al App Router de Next.js, los imports relativos en ese archivo se romperán. El Coder tiene la obligación de **reescribir todos los imports relativos de componentes e información locales** (ej. `./components/app-sidebar` o `./data.json`) para usar aliases absolutos que apunten a la ubicación física descargada por Shadcn (ej. `@/components/blocks/<block-name>/components/app-sidebar` o `@/components/blocks/<block-name>/data.json`).
|
|
85
|
+
- **Preservación de Datos Mock/Dummy**: El archivo de datos del bloque (por ejemplo, `data.json` o constantes internas) **debe ser preservado e importado de manera intacta** durante esta Fase A para garantizar que la vista renderice con datos idénticos al demo original en el navegador.
|
|
86
|
+
- **Meta**: Al terminar la Fase A, la aplicación debe renderizarse de manera *pixel-perfect* (idéntica) al demo oficial de Shadcn en local, sin un solo error de compilación o de imports rotos.
|
|
87
|
+
|
|
88
|
+
2. **Sustitución de Datos Atómica (Fase B - Conexión de Lógica)**:
|
|
89
|
+
- Una vez comprobado que el esqueleto visual se muestra perfecto y sin aberraciones de flexbox o alineación, el Coder procederá a sustituir de manera quirúrgica y atómica los datos dummy o locales por la lógica de negocio real (estados de React, fetchings de API del backend).
|
|
90
|
+
- El Coder **no debe modificar las clases contenedoras estructurales** (`SidebarProvider`, `SidebarInset`, grids de diseño principales, anchos o paddings del bloque) para evitar corrupciones visuales en pantallas grandes o pequeñas.
|
|
91
|
+
|
|
92
|
+
3. **Prevención de Parpadeos (Flicker) de Sidebar y Providers**:
|
|
93
|
+
- Si el bloque utiliza providers globales como `<SidebarProvider>`, el Coder debe extraer la barra lateral (`AppSidebar`) y sus providers principales hacia `src/app/layout.tsx` (o un layout del Route Group respectivo) en lugar de dejarlos redundantes en el `page.tsx` de cada ruta, permitiendo un ruteo libre de parpadeos desagradables y garantizando consistencia.
|
|
94
|
+
|
|
95
|
+
4. **Catálogo de Bloques a Explorar**:
|
|
96
|
+
- **Dashboards**: Utiliza `dashboard-01` o cualquier variante de panel de control interactivo oficial.
|
|
97
|
+
- **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.
|
|
98
|
+
- **Login / Registro**: Utiliza `login-01` al `05` y `signup-01` al `05` para flujos de login y registro de usuarios.
|
|
99
|
+
- **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.
|
|
100
|
+
|
|
101
|
+
**REGLA CRÍTICA DE RUTAS DUPLICADAS POR SHADCN CLI**:
|
|
102
|
+
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
103
|
|
|
84
104
|
### 3.2 Form Layouts (FieldGroup + Field)
|
|
85
105
|
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 +129,19 @@ Para estructurar campos de formularios, no uses `div`s arbitrarios con clases de
|
|
|
109
129
|
### 3.4 Sin Placeholders en Producción
|
|
110
130
|
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
131
|
|
|
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.
|
|
132
|
+
### 3.5 Reglas de Diseño y Estándares de Calidad (Consolidadas)
|
|
133
|
+
* **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.
|
|
134
|
+
* **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
135
|
|
|
122
136
|
---
|
|
123
137
|
|
|
124
138
|
## 4. Flujo de Trabajo en SDD
|
|
125
139
|
|
|
126
140
|
### Fase F1 (Spec-Driven Contract)
|
|
127
|
-
El `@sdd-spec-writer` utiliza el MCP `shadcn` (`
|
|
141
|
+
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
142
|
|
|
129
143
|
### Fase F2 (Implementation)
|
|
130
|
-
El `@sdd-coder` utiliza el template base `nextjs-shadcn`
|
|
144
|
+
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
145
|
|
|
132
146
|
### Fase F3 (Verification)
|
|
133
147
|
El `@sdd-tester` ejecuta las pruebas según el modo de verificación especificado en el contrato (`settings.verificationMode`):
|
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."),
|
|
@@ -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"),
|