zugzbot 1.0.39 → 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.
@@ -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.
@@ -54,6 +58,8 @@ Para evitar bucles de redirección ("redirect loops") y pantallas parpadeantes (
54
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.
55
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.
56
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.
57
63
 
58
64
  ## 7. Mockups Visuales y Validación Temprana de Layout (F0/F1)
59
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:
@@ -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 conocidas (EVITAR siempre)
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**: 4 llamadas a `oh-my-design_list_references` con `category: "saas"`, "fintech", "ecommerce", "consumer" solo para mostrar opciones.
48
- **HAZ**: 1 llamada a `sdd_list_design_recommendations({ use_case: "all", max_per_category: 3 })`. Si el usuario quiere "Personalizar", ahí sí usa `oh-my-design_search_by_vibe`.
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")` + `sdd_set_phase("F1_CONTRACT", ...)` en 2 calls (race condition de timestamp, observado en sesión 137a).
52
- **HAZ**: 1 sola call: `sdd_set_phase({ phase: "F1_CONTRACT", spec_name: "mi-spec" })`. Devuelve `activeContract` listo.
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: Reescribir `globals.css` desde cero
55
- **NO HAGAS**: Sobrescribir `src/app/globals.css` quitando las variables shadcn (`--color-border: var(--border)`, etc.) al aplicar tokens de marca. Build falla con `Cannot apply unknown utility class 'border-border'` (observado en sesión 137a).
56
- **HAZ**: Usar `sdd_apply_brand_tokens` que inyecta en un bloque `@theme inline` aparte, preservando las variables shadcn.
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: Cargar `next-devtools` MCP en sesión normal
59
- **NO HAGAS**: Dejar `next-devtools` habilitado. Su tool `init` inyecta 1000+ palabras de "FORGET ALL PRIOR KNOWLEDGE" (~8K tokens de reasoning desperdiciado — el coder tuvo el mayor consumo de tokens de la sesión 137a por esta razón).
60
- **HAZ**: Está deshabilitado por defecto en `opencode.json`. Solo activarlo on-demand si un subagente reporta un error específico de Next 16.
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: Escribir el contrato desde cero
63
- **NO HAGAS**: Redactar 600+ líneas de `contract.json` en cada sesión. Riesgo alto de inconsistencia.
64
- **HAZ**: Cargar la skill `sdd-quickstart` y usar la plantilla pre-rellenada. Solo rellenar `{{...}}`.
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: Tests en F2
67
- **NO HAGAS**: Que el coder escriba los tests después de implementar (loop Coder Tester Coder, observado en sesión 137a).
68
- **HAZ**: Que el spec-writer (en F1) cree los tests con assertions reales basadas en `test_scenarios`. El coder solo implementa el código de producción para hacerlos pasar.
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: 5+ llamadas a `todowrite` durante la sesión
71
- **NO HAGAS**: Actualizar la lista de TODOs cada vez que cambias de fase (observado 5 veces en sesión 137a).
72
- **HAZ**: Crear la lista al inicio. Marcar `in_progress` solo cuando arrancas la fase. Marcar `completed` **en bloque** al final.
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: `lint: false` en el orquestador
75
- **NO HAGAS**: Dejar que el tester descubra imports no usados en tests.
76
- **HAZ**: El self-audit del coder (F2) y el auto-lint gate de `sdd_set_phase("F3_VERIFICATION")` ya lo previenen. El orquestador debe **reportar el `lintWarning`** al usuario antes de delegar al tester.
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: Cargar skills duplicadas
79
- **NO HAGAS**: Cargar skills de forma genérica en subagentes si su contenido ya está integrado en su prompt de identidad (ej. cargar `sdd-methodology` en `@sdd-deployer` o `@sdd-tester`). Esto duplica los tokens de input consumidos.
80
- **HAZ**: Limitar la carga de skills a los casos proactivos indicados o cuando se requieran plantillas/recursos específicos de la skill (ej. `sdd-quickstart` en `@sdd-spec-writer`).
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: Playwright en modo Console
83
- **NO HAGAS**: Invocar herramientas de Playwright (`playwright_browser_navigate`, `playwright_browser_snapshot`, etc.) si `verificationMode` está configurado en `"console"`. Esto consume tiempo y reasoning innecesarios.
84
- **HAZ**: En modo `console`, confía en pruebas unitarias/integración (Vitest) y verificaciones directas con curls/logs. No abras navegadores.
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 (si fallan por SVG/React)
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
- Sun: () => <div data-testid="icon-sun" />,
42
- Moon: () => <div data-testid="icon-moon" />,
43
- Plus: () => <div data-testid="icon-plus" />,
44
- Trash2: () => <div data-testid="icon-trash" />,
45
- History: () => <div data-testid="icon-history" />,
46
- Clock: () => <div data-testid="icon-clock" />,
47
- Calculator: () => <div data-testid="icon-calculator" />
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.
@@ -81,6 +81,9 @@ Utiliza las plantillas y bloques existentes de Shadcn como el estándar absoluto
81
81
 
82
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
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.
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:
86
89
  ```tsx
@@ -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 Estética de Diseño Premium y Layouts (OBLIGATORIO)
113
- Queda **estrictamente prohibido** generar interfaces visualmente planas, vacías o que parezcan un "mínimo producto viable" básico (por ejemplo, una sola caja minimalista en el centro de un fondo blanco plano con un botón gris).
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` (`mcp__shadcn__search_items`, `mcp__shadcn__get_item`) para documentar en el contrato (`contract.json`) qué componentes y bloques se usarán para la UI y verificar sus APIs/propiedades expuestas.
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` y ejecuta `npx shadcn@latest add` para instalar los componentes requeridos para la interfaz. Implementa las vistas componiendo dichos bloques y vinculando el estado con el backend.
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`):
@@ -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 un aprendizaje, decisión de diseño, ruta concreta, resolución de error o memoria del proyecto en el archivo .openspec/brain.md. Es acumulativo y añade una marca de tiempo.",
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 del archivo .openspec/brain.md. Si se especifica una categoría, solo lee esa sección para optimizar tokens y contexto. Si no se especifica, lista las categorías disponibles.",
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 (qué plantilla se usó, cuándo, qué componentes shadcn están instalados, versión de Node y package manager). Si el proyecto no está bootstrapped, retorna NOT_BOOTSTRAPPED. Útil para que el coder verifique antes de empezar a codear.",
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 a partir de la plantilla canónica en .opencode/templates/nextjs-shadcn/. Es IDEMPOTENTE: si el proyecto ya está inicializado y no se pasa force=true, no toca nada. Copia archivo-por-archivo (sin pisar los existentes), mergea package.json, y opcionalmente instala dependencias y shadcn components.",
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 a partir de la plantilla canónica en .opencode/templates/fastapi-sdd/. Es IDEMPOTENTE: si el proyecto ya está inicializado y no se pasa force=true, no toca nada. Copia archivo-por-archivo (sin pisar los existentes), opcionalmente instala dependencias con uv (fallback pip).",
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 (crea un package.json básico, requirements.txt, o estructura plana de archivos según sea necesario). Evita la sobrecarga de frameworks pesados.",
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 (F0_DETECT, F1_CONTRACT, F2_IMPLEMENTATION, F3_VERIFICATION, F4_DEPLOYMENT). Si phase=F1_CONTRACT y se pasa spec_name, crea la carpeta del spec atómicamente y devuelve la ruta absoluta. Si phase=F3_VERIFICATION, ejecuta auto-lint (no bloqueante, solo informativo) y aborta si hay errores de lint.",
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 (fase activa, contrato seleccionado, stack validado)",
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 atómicamente todos los datos de inicio de sesión: el estado actual del arnés, las memorias históricas clave del Brain ('learnings', 'design', 'routing'), y la lista curada de recomendaciones de diseño de Oh My Design. Reemplaza las llamadas secuenciales a sdd_get_state, brain_read_memory y sdd_list_design_recommendations.",
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 breve y estructurado del spec o contrato activo en .openspec/active-brief.md para que sirva de anclaje de contexto de sistema (System State Anchoring) para el subagente sdd-coder o sdd-tester.",
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 (formato: yyyy-mm-dd__hh-mm-ss_nombre)",
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 de forma estricta el archivo contract.json contra el contract-schema.json oficial para detectar errores de tipos, alucinaciones o campos faltantes antes de avanzar.",
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 sus ejemplos y recursos interactivos asociados desde el catálogo original de oh-my-design a la carpeta .openspec/ del proyecto.",
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 y corta de marcas de diseño recomendadas (con assets HTML+CSS interactivos), filtrada por categoría de uso. Reemplaza 3-4 llamadas a oh-my-design_list_references en F0.",
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 (colores, tipografía, radius) en src/app/globals.css preservando las variables shadcn (--color-border, --color-background, etc.). Usar en F2 cuando se necesite aplicar el tema 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 e idempotente. Si node_modules/lucide-react existe, verifica contra los exports reales; de lo contrario, valida contra un listado estático de los iconos más comunes.",
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: detiene y elimina TODOS los contenedores (activos o inactivos), remueve TODAS las imágenes, volúmenes y redes para garantizar un lienzo en blanco absoluto antes de desplegar.",
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 multi-stage, .dockerignore y docker-compose.yml optimizados a partir del stack del proyecto (nextjs|fastapi|agnostic). Detecta package manager desde package.json.",
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: "Busca y termina de manera forzada cualquier proceso que esté escuchando en un puerto específico",
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 de desarrollo o producción en segundo plano y registra su PID para limpieza posterior",
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 usando el PID registrado",
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 de forma nativa y unificada el estado del ciclo SDD (.openspec/sdd_state.json) junto con un resumen de las categorías de memoria del cerebro (Brain). Evita llamadas lentas de consola y es multiplataforma.",
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/. Devuelve exit code y warnings. Usado como gate automático antes de transicionar a F3.",
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 en el proyecto: ejecuta el compilador de TypeScript (tsc) y el linter (eslint) de manera combinada. Limpia y parsea semánticamente los stack traces y logs de error crudos, devolviendo un JSON limpio y estructurado de errores que el LLM puede digerir y solucionar de inmediato sin perder atención.",
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 unitarias/integración en el directorio corporativo de pruebas a partir de los escenarios de prueba descritos en el contrato activo de sdd_state.json. No pisa archivos de pruebas existentes.",
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 captura visual/videos (.openspec/.playwright/) generados por Playwright a la carpeta del spec/contrato activo de forma ordenada, evitando ensuciar la raíz.",
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 = "ses_11ca"
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": "MCP oficial de Oh My Design para buscar, consultar y aplicar temas de diseño (Toss, Stripe, Supabase, etc.)."
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": "Librería UI objetivo. Usar para browse/search/install de componentes y blocks (dashboards, landings, auth, forms)."
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": "Playwright MCP. Artefactos (screenshots, traces, videos, downloads) van a .openspec/.playwright/<call-id>/. Para evidencia por sesión SDD, promueve los artefactos relevantes a .openspec/specs/<activeContract>/playwright/ con .opencode/tools/save-playwright-artifacts.sh. --isolated evita ensuciar el perfil del browser en disco."
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 Vercel para Next.js 16. Provee init, nextjs_docs, nextjs_index/nextjs_call (errores, logs, rutas, Server Actions en runtime), browser_eval, upgrade_nextjs_16 y enable_cache_components. Complementa context7 (docs genérico) con docs y runtime específicos de Next 16 (dev server expone /_next/mcp). Telemetría desactivada explícitamente. **DESHABILITADO por defecto** — solo activar on-demand cuando un subagente reporte un error específico de Next 16 que requiera docs oficiales. La razón: el tool `init` inyecta 1000+ palabras de 'FORGET ALL PRIOR KNOWLEDGE' en el contexto del coder (~8K tokens de reasoning desperdiciado en sesiones normales)."
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": "Permite buscar, filtrar y obtener ejemplos de uso JSX de más de 1,500 iconos de Lucide React de forma exacta mediante herramientas del MCP."
103
+ "purpose": "Busca y obtiene ejemplos de uso de iconos de Lucide React."
104
104
  }
105
105
  }
106
106
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zugzbot",
3
- "version": "1.0.39",
3
+ "version": "1.0.40",
4
4
  "description": "Fácil instalador del arnés SDD de Zugzbot para proyectos OpenCode",
5
5
  "type": "module",
6
6
  "bin": {