roadmap-kit 1.0.0

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.
Files changed (39) hide show
  1. package/INSTALL.md +358 -0
  2. package/LICENSE +21 -0
  3. package/README.md +503 -0
  4. package/cli.js +548 -0
  5. package/dashboard/dist/assets/index-BzYzLB7u.css +1 -0
  6. package/dashboard/dist/assets/index-DIonhzlK.js +506 -0
  7. package/dashboard/dist/index.html +18 -0
  8. package/dashboard/dist/roadmap.json +268 -0
  9. package/dashboard/index.html +17 -0
  10. package/dashboard/package-lock.json +4172 -0
  11. package/dashboard/package.json +37 -0
  12. package/dashboard/postcss.config.js +6 -0
  13. package/dashboard/public/roadmap.json +268 -0
  14. package/dashboard/server.js +1366 -0
  15. package/dashboard/src/App.jsx +6979 -0
  16. package/dashboard/src/components/CircularProgress.jsx +55 -0
  17. package/dashboard/src/components/ProgressBar.jsx +33 -0
  18. package/dashboard/src/components/ProjectSettings.jsx +420 -0
  19. package/dashboard/src/components/SharedResources.jsx +239 -0
  20. package/dashboard/src/components/TaskList.jsx +273 -0
  21. package/dashboard/src/components/TechnicalDebt.jsx +170 -0
  22. package/dashboard/src/components/ui/accordion.jsx +46 -0
  23. package/dashboard/src/components/ui/badge.jsx +38 -0
  24. package/dashboard/src/components/ui/card.jsx +60 -0
  25. package/dashboard/src/components/ui/progress.jsx +22 -0
  26. package/dashboard/src/components/ui/tabs.jsx +47 -0
  27. package/dashboard/src/index.css +440 -0
  28. package/dashboard/src/lib/utils.js +6 -0
  29. package/dashboard/src/main.jsx +10 -0
  30. package/dashboard/tailwind.config.js +142 -0
  31. package/dashboard/vite.config.js +18 -0
  32. package/docker/Dockerfile +35 -0
  33. package/docker/docker-compose.yml +30 -0
  34. package/docker/entrypoint.sh +31 -0
  35. package/package.json +68 -0
  36. package/scanner.js +351 -0
  37. package/setup.sh +354 -0
  38. package/templates/clinerules.template +130 -0
  39. package/templates/roadmap.template.json +30 -0
@@ -0,0 +1,55 @@
1
+ import React from 'react';
2
+
3
+ export default function CircularProgress({ percentage = 0, size = 120, strokeWidth = 8 }) {
4
+ const radius = (size - strokeWidth) / 2;
5
+ const circumference = radius * 2 * Math.PI;
6
+ const offset = circumference - (percentage / 100) * circumference;
7
+
8
+ const gradientId = `progress-${Math.random().toString(36).substr(2, 9)}`;
9
+
10
+ return (
11
+ <div className="relative" style={{ width: size, height: size }}>
12
+ <svg width={size} height={size} className="transform -rotate-90">
13
+ <defs>
14
+ <linearGradient id={gradientId} x1="0%" y1="0%" x2="100%" y2="0%">
15
+ <stop offset="0%" stopColor="#3b82f6" />
16
+ <stop offset="50%" stopColor="#06b6d4" />
17
+ <stop offset="100%" stopColor="#22d3ee" />
18
+ </linearGradient>
19
+ </defs>
20
+
21
+ {/* Background */}
22
+ <circle
23
+ cx={size / 2}
24
+ cy={size / 2}
25
+ r={radius}
26
+ fill="none"
27
+ stroke="rgba(255,255,255,0.05)"
28
+ strokeWidth={strokeWidth}
29
+ />
30
+
31
+ {/* Progress */}
32
+ <circle
33
+ cx={size / 2}
34
+ cy={size / 2}
35
+ r={radius}
36
+ fill="none"
37
+ stroke={`url(#${gradientId})`}
38
+ strokeWidth={strokeWidth}
39
+ strokeLinecap="round"
40
+ strokeDasharray={circumference}
41
+ strokeDashoffset={offset}
42
+ className="transition-all duration-700 ease-out"
43
+ style={{
44
+ filter: 'drop-shadow(0 0 6px rgba(59, 130, 246, 0.5))'
45
+ }}
46
+ />
47
+ </svg>
48
+
49
+ {/* Center text */}
50
+ <div className="absolute inset-0 flex items-center justify-center">
51
+ <span className="text-lg font-bold text-gradient-blue">{percentage}%</span>
52
+ </div>
53
+ </div>
54
+ );
55
+ }
@@ -0,0 +1,33 @@
1
+ import React from 'react';
2
+
3
+ /**
4
+ * ProgressBar Component
5
+ * Displays an animated progress bar with percentage
6
+ */
7
+ export default function ProgressBar({ percentage = 0, label = '', color = 'green' }) {
8
+ const colorClasses = {
9
+ green: 'bg-status-completed',
10
+ yellow: 'bg-status-progress',
11
+ gray: 'bg-status-pending',
12
+ blue: 'bg-blue-500'
13
+ };
14
+
15
+ const bgColor = colorClasses[color] || colorClasses.green;
16
+
17
+ return (
18
+ <div className="w-full">
19
+ {label && (
20
+ <div className="flex justify-between mb-1">
21
+ <span className="text-sm font-medium text-dark-text">{label}</span>
22
+ <span className="text-sm font-medium text-dark-text">{percentage}%</span>
23
+ </div>
24
+ )}
25
+ <div className="w-full bg-dark-border rounded-full h-2.5 overflow-hidden">
26
+ <div
27
+ className={`h-2.5 rounded-full transition-all duration-500 ease-out ${bgColor}`}
28
+ style={{ width: `${percentage}%` }}
29
+ />
30
+ </div>
31
+ </div>
32
+ );
33
+ }
@@ -0,0 +1,420 @@
1
+ import React, { useState } from 'react';
2
+ import { Settings, Download, FileCode, Copy, Check, RefreshCw } from 'lucide-react';
3
+ import { Card, CardContent, CardHeader, CardTitle, CardDescription } from './ui/card';
4
+ import { Badge } from './ui/badge';
5
+ import { Accordion, AccordionItem, AccordionTrigger, AccordionContent } from './ui/accordion';
6
+
7
+ /**
8
+ * ProjectSettings Component
9
+ * Manage project conventions and generate .clinerules file
10
+ */
11
+ export default function ProjectSettings({ roadmap = {}, onReload }) {
12
+ const [copiedSection, setCopiedSection] = useState(null);
13
+ const [editMode, setEditMode] = useState(false);
14
+ const [conventions, setConventions] = useState(roadmap?.project_info?.conventions || {});
15
+
16
+ const copyToClipboard = (text, id) => {
17
+ navigator.clipboard.writeText(text);
18
+ setCopiedSection(id);
19
+ setTimeout(() => setCopiedSection(null), 2000);
20
+ };
21
+
22
+ // Generate .clinerules content
23
+ const generateClinerules = () => {
24
+ const projectInfo = roadmap?.project_info || {};
25
+ const { ui_components = [], utilities = [], database_tables = [] } = projectInfo.shared_resources || {};
26
+
27
+ return `# Reglas del Proyecto: ${projectInfo.name || '[PROJECT_NAME]'}
28
+
29
+ ## 🎯 Contexto General
30
+ ${projectInfo.description || '[PROJECT_DESCRIPTION]'}
31
+
32
+ **Propósito:** ${projectInfo.purpose || '[PROJECT_PURPOSE]'}
33
+
34
+ ## 📐 Arquitectura
35
+ ${projectInfo.architecture || '[ARCHITECTURE_DESCRIPTION]'}
36
+
37
+ **Stack Tecnológico:**
38
+ ${projectInfo.stack ? projectInfo.stack.map(tech => `- ${tech}`).join('\n') : '- [STACK_ITEMS]'}
39
+
40
+ ---
41
+
42
+ ## 🛠️ Sistema de Gestión de Proyecto (OBLIGATORIO)
43
+
44
+ Este proyecto utiliza **ROADMAP-KIT** para gestionar el progreso y mantener la coherencia.
45
+
46
+ ### 📋 Reglas de Operación:
47
+
48
+ 1. **📖 Consulta el Roadmap SIEMPRE:**
49
+ - ANTES de empezar cualquier tarea, lee \`roadmap-kit/roadmap.json\`
50
+ - Verifica el contexto, las dependencias y los recursos compartidos
51
+ - Busca tu tarea específica por \`id\` y lee su \`description\`
52
+
53
+ 2. **♻️ NO Duplicar - Reutilizar:**
54
+ - Consulta la sección \`shared_resources\` en el JSON
55
+ - Si una utilidad, componente o tabla DB ya existe, **DEBES reutilizarla**
56
+ - Añade el recurso reutilizado a \`reused_resources\` de tu tarea
57
+ - **NUNCA** crees componentes, funciones o tablas duplicadas
58
+
59
+ 3. **📝 Actualización Post-Tarea:**
60
+ Al finalizar una tarea, actualiza el \`roadmap.json\` con:
61
+ - \`status\`: "completed" (o "in_progress" si no terminaste)
62
+ - \`ai_notes\`: Explica QUÉ decisiones tomaste y POR QUÉ
63
+ - \`affected_files\`: Lista TODOS los archivos que creaste o modificaste
64
+ - \`reused_resources\`: Lista los recursos compartidos que usaste
65
+ - \`technical_debt\`: Si dejaste algo pendiente, "sucio" o temporal, anótalo aquí con severidad (high/medium/low) y esfuerzo estimado
66
+
67
+ 4. **🔖 Formato de Commit:**
68
+ Cada vez que termines una tarea, genera un commit con este formato EXACTO:
69
+ \`\`\`
70
+ [task:ID_DE_LA_TAREA] [status:completed] Breve descripción del cambio
71
+ \`\`\`
72
+
73
+ Ejemplos:
74
+ \`\`\`
75
+ [task:auth-login] [status:completed] Implementa endpoint de login con JWT
76
+ [task:user-list] [status:in_progress] [debt:Falta paginación] Añade listado básico
77
+ \`\`\`
78
+
79
+ 5. **⚠️ Reportar Deuda Técnica:**
80
+ Si detectas algo que debe mejorarse pero no tienes tiempo ahora:
81
+ \`\`\`
82
+ [task:payment-api] [status:completed] [debt:Falta validación de tarjetas] [debt:Sin logs centralizados] Implementa endpoint de pagos
83
+ \`\`\`
84
+
85
+ ---
86
+
87
+ ## 📝 Convenciones de Código
88
+
89
+ ### Nomenclatura
90
+ ${conventions.naming ? Object.entries(conventions.naming).map(([key, value]) => `- **${key.charAt(0).toUpperCase() + key.slice(1)}**: ${value}`).join('\n') : `- **Variables y funciones**: camelCase
91
+ - **Componentes**: PascalCase
92
+ - **Archivos**: kebab-case
93
+ - **Constantes**: UPPER_SNAKE_CASE`}
94
+
95
+ ### Estructura de Archivos
96
+ ${conventions.file_structure || '[FILE_STRUCTURE_DESCRIPTION]'}
97
+
98
+ ### Base de Datos
99
+ ${conventions.database || '[DATABASE_CONVENTIONS]'}
100
+
101
+ ### Estilos
102
+ ${conventions.styling || '[STYLING_CONVENTIONS]'}
103
+
104
+ ### Manejo de Errores
105
+ ${conventions.error_handling || '[ERROR_HANDLING_CONVENTIONS]'}
106
+
107
+ ---
108
+
109
+ ## 🚫 Recursos Compartidos (NO DUPLICAR)
110
+
111
+ ### Componentes UI Existentes
112
+ **ANTES de crear un nuevo componente UI, verifica si ya existe uno similar:**
113
+
114
+ ${ui_components.length > 0 ? ui_components.map(comp => `- \`${comp.path}\` - ${comp.description}
115
+ - Uso: \`${comp.usage || 'N/A'}\``).join('\n\n') : '*(No hay componentes UI registrados aún)*'}
116
+
117
+ ### Utilidades Existentes
118
+ **SIEMPRE importar estas utilidades. NO duplicar lógica:**
119
+
120
+ ${utilities.length > 0 ? utilities.map(util => `- \`${util.path}\` - ${util.description}
121
+ - Exports: ${util.exports ? util.exports.map(e => `'${e}'`).join(', ') : 'N/A'}
122
+ - Uso: \`${util.usage || 'N/A'}\`${util.warning ? `\n - ⚠️ **IMPORTANTE**: ${util.warning}` : ''}`).join('\n\n') : '*(No hay utilidades registradas aún)*'}
123
+
124
+ ### Base de Datos
125
+ **Tablas existentes:**
126
+
127
+ ${database_tables.length > 0 ? database_tables.map(table => `- \`${table.name}\` (${table.fields.join(', ')})
128
+ - ${table.description}`).join('\n\n') : '*(No hay tablas registradas aún)*'}
129
+
130
+ **IMPORTANTE:** NO crear nuevas tablas sin consultar el roadmap y actualizar \`shared_resources\`.
131
+
132
+ ---
133
+
134
+ ## 🔄 Flujo de Trabajo
135
+
136
+ 1. **Inicio de Tarea:**
137
+ \`\`\`bash
138
+ # Lee el roadmap
139
+ cat roadmap-kit/roadmap.json
140
+ # Busca tu tarea por ID
141
+ \`\`\`
142
+
143
+ 2. **Durante el Desarrollo:**
144
+ - Reutiliza componentes y utilidades existentes
145
+ - Sigue las convenciones de nomenclatura
146
+ - NO refactorices código que no está relacionado con tu tarea
147
+
148
+ 3. **Al Finalizar:**
149
+ \`\`\`bash
150
+ # Actualiza el roadmap.json (campos: status, ai_notes, affected_files, etc.)
151
+ # Haz commit con el formato correcto
152
+ git add .
153
+ git commit -m "[task:tu-task-id] [status:completed] Descripción del cambio"
154
+ \`\`\`
155
+
156
+ 4. **Sincronización:**
157
+ \`\`\`bash
158
+ # El scanner automático leerá tu commit y actualizará métricas
159
+ npm run roadmap:scan
160
+ \`\`\`
161
+
162
+ ---
163
+
164
+ ## 📊 Visualización del Progreso
165
+
166
+ Para ver el estado del proyecto:
167
+
168
+ \`\`\`bash
169
+ npm run roadmap # Abre el dashboard visual
170
+ npm run roadmap:scan # Actualiza desde Git
171
+ \`\`\`
172
+
173
+ O con Docker:
174
+ \`\`\`bash
175
+ docker-compose up roadmap-dashboard
176
+ \`\`\`
177
+
178
+ ---
179
+
180
+ ## ✅ Checklist Antes de Cada Commit
181
+
182
+ - [ ] ¿Leí la descripción de mi tarea en roadmap.json?
183
+ - [ ] ¿Verifiqué que no estoy duplicando componentes/utilidades existentes?
184
+ - [ ] ¿Seguí las convenciones de nomenclatura del proyecto?
185
+ - [ ] ¿Actualicé el roadmap.json con mis cambios?
186
+ - [ ] ¿Añadí ai_notes explicando mis decisiones?
187
+ - [ ] ¿Listé todos los affected_files?
188
+ - [ ] ¿Reporté la technical_debt si existe?
189
+ - [ ] ¿Usé el formato correcto de commit \`[task:id] [status:...]\`?
190
+
191
+ ---
192
+
193
+ **🗺️ ROADMAP-KIT** - Because AI needs context too.
194
+
195
+ Última sincronización: ${projectInfo.last_sync ? new Date(projectInfo.last_sync).toLocaleString() : 'Nunca'}
196
+ `;
197
+ };
198
+
199
+ const downloadClinerules = () => {
200
+ const content = generateClinerules();
201
+ const blob = new Blob([content], { type: 'text/markdown' });
202
+ const url = URL.createObjectURL(blob);
203
+ const a = document.createElement('a');
204
+ a.href = url;
205
+ a.download = '.clinerules';
206
+ document.body.appendChild(a);
207
+ a.click();
208
+ document.body.removeChild(a);
209
+ URL.revokeObjectURL(url);
210
+ };
211
+
212
+ const projectInfo = roadmap?.project_info || {};
213
+
214
+ return (
215
+ <div className="space-y-6">
216
+ {/* Header */}
217
+ <Card className="bg-gradient-to-br from-purple-900/20 to-purple-800/10 border-purple-700/50">
218
+ <CardHeader>
219
+ <div className="flex items-center justify-between">
220
+ <div>
221
+ <CardTitle className="flex items-center gap-2 text-purple-400">
222
+ <Settings className="w-6 h-6" />
223
+ Configuración del Proyecto
224
+ </CardTitle>
225
+ <CardDescription className="mt-2">
226
+ Gestiona las convenciones y genera el archivo .clinerules para Claude/Cursor/Cline
227
+ </CardDescription>
228
+ </div>
229
+ <button
230
+ onClick={onReload}
231
+ className="p-3 hover:bg-purple-500/10 rounded-lg transition-all hover:scale-105"
232
+ title="Recargar"
233
+ >
234
+ <RefreshCw className="w-5 h-5 text-purple-400" />
235
+ </button>
236
+ </div>
237
+ </CardHeader>
238
+ </Card>
239
+
240
+ {/* Quick Info */}
241
+ <div className="grid grid-cols-1 md:grid-cols-3 gap-4">
242
+ <Card className="bg-slate-900/50 border-slate-700/50">
243
+ <CardContent className="p-6">
244
+ <h3 className="text-sm text-slate-400 mb-1">Nombre del Proyecto</h3>
245
+ <p className="text-lg font-semibold text-slate-100">{projectInfo.name || 'Sin nombre'}</p>
246
+ </CardContent>
247
+ </Card>
248
+
249
+ <Card className="bg-slate-900/50 border-slate-700/50">
250
+ <CardContent className="p-6">
251
+ <h3 className="text-sm text-slate-400 mb-1">Versión</h3>
252
+ <p className="text-lg font-semibold text-slate-100">{projectInfo.version || '1.0.0'}</p>
253
+ </CardContent>
254
+ </Card>
255
+
256
+ <Card className="bg-slate-900/50 border-slate-700/50">
257
+ <CardContent className="p-6">
258
+ <h3 className="text-sm text-slate-400 mb-1">Stack</h3>
259
+ <p className="text-lg font-semibold text-slate-100">
260
+ {projectInfo.stack ? projectInfo.stack.length : 0} tecnologías
261
+ </p>
262
+ </CardContent>
263
+ </Card>
264
+ </div>
265
+
266
+ {/* Generate .clinerules */}
267
+ <Card className="bg-slate-900/50 border-slate-700/50">
268
+ <CardHeader>
269
+ <CardTitle className="flex items-center gap-2">
270
+ <FileCode className="w-5 h-5 text-emerald-400" />
271
+ Generar .clinerules
272
+ </CardTitle>
273
+ <CardDescription>
274
+ Archivo de configuración para que Claude/Cursor/Cline siga las reglas del proyecto
275
+ </CardDescription>
276
+ </CardHeader>
277
+ <CardContent className="space-y-4">
278
+ <div className="flex gap-3">
279
+ <button
280
+ onClick={downloadClinerules}
281
+ className="flex items-center gap-2 px-4 py-2 bg-emerald-600 hover:bg-emerald-700 text-white rounded-lg transition-colors"
282
+ >
283
+ <Download className="w-4 h-4" />
284
+ Descargar .clinerules
285
+ </button>
286
+
287
+ <button
288
+ onClick={() => copyToClipboard(generateClinerules(), 'clinerules')}
289
+ className="flex items-center gap-2 px-4 py-2 bg-slate-700 hover:bg-slate-600 text-white rounded-lg transition-colors"
290
+ >
291
+ {copiedSection === 'clinerules' ? (
292
+ <>
293
+ <Check className="w-4 h-4" />
294
+ Copiado!
295
+ </>
296
+ ) : (
297
+ <>
298
+ <Copy className="w-4 h-4" />
299
+ Copiar al Portapapeles
300
+ </>
301
+ )}
302
+ </button>
303
+ </div>
304
+
305
+ <div className="bg-slate-950/50 rounded-lg p-4 border border-slate-700/50 max-h-96 overflow-y-auto scrollbar-dark">
306
+ <pre className="text-xs text-slate-300 whitespace-pre-wrap font-mono">
307
+ {generateClinerules()}
308
+ </pre>
309
+ </div>
310
+ </CardContent>
311
+ </Card>
312
+
313
+ {/* Conventions */}
314
+ <Card className="bg-slate-900/50 border-slate-700/50">
315
+ <CardHeader>
316
+ <CardTitle>Convenciones del Proyecto</CardTitle>
317
+ <CardDescription>
318
+ Define las reglas de nomenclatura y estructura que la IA debe seguir
319
+ </CardDescription>
320
+ </CardHeader>
321
+ <CardContent>
322
+ <Accordion type="multiple" className="space-y-2">
323
+ {/* Naming */}
324
+ <Card className="bg-slate-800/30 border-slate-700/50">
325
+ <AccordionItem value="naming" className="border-none">
326
+ <AccordionTrigger className="hover:no-underline px-4">
327
+ <div className="flex items-center gap-2">
328
+ <FileCode className="w-4 h-4 text-blue-400" />
329
+ <span>Nomenclatura</span>
330
+ <Badge variant="secondary">{Object.keys(conventions.naming || {}).length} reglas</Badge>
331
+ </div>
332
+ </AccordionTrigger>
333
+ <AccordionContent>
334
+ <div className="px-4 pb-4 space-y-2">
335
+ {conventions.naming && Object.entries(conventions.naming).map(([key, value]) => (
336
+ <div key={key} className="flex items-center justify-between bg-slate-900/50 p-3 rounded-lg">
337
+ <span className="text-sm text-slate-400">{key}:</span>
338
+ <code className="text-sm text-emerald-400">{value}</code>
339
+ </div>
340
+ ))}
341
+ </div>
342
+ </AccordionContent>
343
+ </AccordionItem>
344
+ </Card>
345
+
346
+ {/* Architecture */}
347
+ <Card className="bg-slate-800/30 border-slate-700/50">
348
+ <AccordionItem value="architecture" className="border-none">
349
+ <AccordionTrigger className="hover:no-underline px-4">
350
+ <div className="flex items-center gap-2">
351
+ <FileCode className="w-4 h-4 text-purple-400" />
352
+ <span>Arquitectura</span>
353
+ </div>
354
+ </AccordionTrigger>
355
+ <AccordionContent>
356
+ <div className="px-4 pb-4">
357
+ <div className="bg-slate-900/50 p-4 rounded-lg">
358
+ <p className="text-sm text-slate-300">{projectInfo.architecture || 'No definida'}</p>
359
+ </div>
360
+ </div>
361
+ </AccordionContent>
362
+ </AccordionItem>
363
+ </Card>
364
+
365
+ {/* File Structure */}
366
+ <Card className="bg-slate-800/30 border-slate-700/50">
367
+ <AccordionItem value="structure" className="border-none">
368
+ <AccordionTrigger className="hover:no-underline px-4">
369
+ <div className="flex items-center gap-2">
370
+ <FileCode className="w-4 h-4 text-amber-400" />
371
+ <span>Estructura de Archivos</span>
372
+ </div>
373
+ </AccordionTrigger>
374
+ <AccordionContent>
375
+ <div className="px-4 pb-4">
376
+ <div className="bg-slate-900/50 p-4 rounded-lg">
377
+ <p className="text-sm text-slate-300">{conventions.file_structure || 'No definida'}</p>
378
+ </div>
379
+ </div>
380
+ </AccordionContent>
381
+ </AccordionItem>
382
+ </Card>
383
+
384
+ {/* Database */}
385
+ <Card className="bg-slate-800/30 border-slate-700/50">
386
+ <AccordionItem value="database" className="border-none">
387
+ <AccordionTrigger className="hover:no-underline px-4">
388
+ <div className="flex items-center gap-2">
389
+ <FileCode className="w-4 h-4 text-green-400" />
390
+ <span>Base de Datos</span>
391
+ </div>
392
+ </AccordionTrigger>
393
+ <AccordionContent>
394
+ <div className="px-4 pb-4">
395
+ <div className="bg-slate-900/50 p-4 rounded-lg">
396
+ <p className="text-sm text-slate-300">{conventions.database || 'No definida'}</p>
397
+ </div>
398
+ </div>
399
+ </AccordionContent>
400
+ </AccordionItem>
401
+ </Card>
402
+ </Accordion>
403
+ </CardContent>
404
+ </Card>
405
+
406
+ {/* Instructions */}
407
+ <Card className="bg-blue-900/10 border-blue-700/50">
408
+ <CardContent className="p-6">
409
+ <h3 className="text-sm font-semibold text-blue-400 mb-3">📖 Instrucciones de Instalación</h3>
410
+ <div className="space-y-2 text-sm text-slate-300">
411
+ <p>1. Descarga o copia el contenido del archivo .clinerules</p>
412
+ <p>2. Colócalo en la raíz de tu proyecto como <code className="text-emerald-400">.clinerules</code></p>
413
+ <p>3. Si usas Cursor, renómbralo a <code className="text-emerald-400">.cursorrules</code></p>
414
+ <p>4. Claude/Cursor/Cline leerá automáticamente estas reglas antes de generar código</p>
415
+ </div>
416
+ </CardContent>
417
+ </Card>
418
+ </div>
419
+ );
420
+ }