specleap-framework 2.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 (47) hide show
  1. package/.agents/backend.md +419 -0
  2. package/.agents/frontend.md +577 -0
  3. package/.agents/producto.md +516 -0
  4. package/.commands/adoptar.md +323 -0
  5. package/.commands/ayuda.md +142 -0
  6. package/.commands/crear-tickets.md +55 -0
  7. package/.commands/documentar.md +285 -0
  8. package/.commands/explicar.md +234 -0
  9. package/.commands/implementar.md +383 -0
  10. package/.commands/inicio.md +824 -0
  11. package/.commands/nuevo/README.md +292 -0
  12. package/.commands/nuevo/questions-base.yaml +320 -0
  13. package/.commands/nuevo/responses-example.yaml +53 -0
  14. package/.commands/planificar.md +253 -0
  15. package/.commands/refinar.md +306 -0
  16. package/LICENSE +21 -0
  17. package/README.md +603 -0
  18. package/SETUP.md +351 -0
  19. package/install.sh +152 -0
  20. package/package.json +60 -0
  21. package/proyectos/_template/.gitkeep +1 -0
  22. package/proyectos/_template/ANEXOS.md +21 -0
  23. package/proyectos/_template/CONTRATO.md +26 -0
  24. package/proyectos/_template/context/.gitkeep +1 -0
  25. package/rules/development-rules.md +113 -0
  26. package/rules/environment-protection.md +97 -0
  27. package/rules/git-workflow.md +142 -0
  28. package/rules/session-protocol.md +121 -0
  29. package/scripts/README.md +129 -0
  30. package/scripts/analyze-project.sh +826 -0
  31. package/scripts/create-asana-tasks.sh +133 -0
  32. package/scripts/detect-project-type.sh +141 -0
  33. package/scripts/estimate-effort.sh +290 -0
  34. package/scripts/generate-asana-structure.sh +262 -0
  35. package/scripts/generate-contract.sh +360 -0
  36. package/scripts/generate-contrato.sh +555 -0
  37. package/scripts/install-git-hooks.sh +141 -0
  38. package/scripts/install-skills.sh +130 -0
  39. package/scripts/lib/asana-utils.sh +191 -0
  40. package/scripts/lib/jira-project-utils.sh +222 -0
  41. package/scripts/lib/questions.json +831 -0
  42. package/scripts/lib/render-contrato.py +195 -0
  43. package/scripts/lib/validate.sh +325 -0
  44. package/scripts/parse-contrato.sh +190 -0
  45. package/scripts/setup-mcp.sh +654 -0
  46. package/scripts/test-cuestionario.sh +428 -0
  47. package/setup.sh +458 -0
@@ -0,0 +1,428 @@
1
+ #!/usr/bin/env bash
2
+
3
+ # SpecLeap — Suite de tests para el sistema de cuestionario
4
+ # Fase 2.5
5
+
6
+ set -euo pipefail
7
+
8
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
9
+ GENERATE_SCRIPT="$SCRIPT_DIR/generate-contrato.sh"
10
+ VALIDATE_LIB="$SCRIPT_DIR/lib/validate.sh"
11
+ PARSE_SCRIPT="$SCRIPT_DIR/parse-contrato.sh"
12
+ JIRA_SCRIPT="$SCRIPT_DIR/generate-jira-structure.sh"
13
+
14
+ # Colores
15
+ RED='\033[0;31m'
16
+ GREEN='\033[0;32m'
17
+ YELLOW='\033[1;33m'
18
+ CYAN='\033[0;36m'
19
+ BOLD='\033[1m'
20
+ RESET='\033[0m'
21
+
22
+ # Contadores
23
+ TESTS_RUN=0
24
+ TESTS_PASSED=0
25
+ TESTS_FAILED=0
26
+
27
+ print_test_header() {
28
+ echo -e "\n${CYAN}${BOLD}═══ $1 ═══${RESET}\n"
29
+ }
30
+
31
+ print_test() {
32
+ echo -e "${CYAN}→ Test: $1${RESET}"
33
+ }
34
+
35
+ print_pass() {
36
+ echo -e "${GREEN} ✅ PASS${RESET}"
37
+ TESTS_PASSED=$((TESTS_PASSED + 1))
38
+ }
39
+
40
+ print_fail() {
41
+ echo -e "${RED} ❌ FAIL: $1${RESET}"
42
+ TESTS_FAILED=$((TESTS_FAILED + 1))
43
+ }
44
+
45
+ run_test() {
46
+ TESTS_RUN=$((TESTS_RUN + 1))
47
+ }
48
+
49
+ # ============================================================================
50
+ # TESTS DE VALIDACIÓN
51
+ # ============================================================================
52
+
53
+ test_validate_string() {
54
+ print_test_header "Validaciones de String"
55
+
56
+ source "$VALIDATE_LIB"
57
+
58
+ # Test 1: String con pattern slug válido
59
+ print_test "String slug válido"
60
+ run_test
61
+ if validate_string_advanced "mi-proyecto-123" "^[a-z0-9-]+$" 3 50 > /dev/null 2>&1; then
62
+ print_pass
63
+ else
64
+ print_fail "Debería aceptar slug válido"
65
+ fi
66
+
67
+ # Test 2: String slug inválido (mayúsculas)
68
+ print_test "String slug inválido (mayúsculas)"
69
+ run_test
70
+ if ! validate_string_advanced "Mi-Proyecto" "^[a-z0-9-]+$" 3 50 > /dev/null 2>&1; then
71
+ print_pass
72
+ else
73
+ print_fail "Debería rechazar mayúsculas en slug"
74
+ fi
75
+
76
+ # Test 3: String muy corto
77
+ print_test "String muy corto (min_length)"
78
+ run_test
79
+ if ! validate_string_advanced "ab" "^[a-z0-9-]+$" 3 50 > /dev/null 2>&1; then
80
+ print_pass
81
+ else
82
+ print_fail "Debería rechazar string menor a min_length"
83
+ fi
84
+
85
+ # Test 4: String muy largo
86
+ print_test "String muy largo (max_length)"
87
+ run_test
88
+ local long_string=$(printf 'a%.0s' {1..100})
89
+ if ! validate_string_advanced "$long_string" "" 0 50 > /dev/null 2>&1; then
90
+ print_pass
91
+ else
92
+ print_fail "Debería rechazar string mayor a max_length"
93
+ fi
94
+
95
+ # Test 5: Hexcolor válido
96
+ print_test "Hexcolor válido"
97
+ run_test
98
+ if validate_string_advanced "#3B82F6" "^#[0-9A-Fa-f]{6}$" 0 999 > /dev/null 2>&1; then
99
+ print_pass
100
+ else
101
+ print_fail "Debería aceptar hexcolor válido"
102
+ fi
103
+
104
+ # Test 6: Hexcolor inválido
105
+ print_test "Hexcolor inválido"
106
+ run_test
107
+ if ! validate_string_advanced "#ZZZ" "^#[0-9A-Fa-f]{6}$" 0 999 > /dev/null 2>&1; then
108
+ print_pass
109
+ else
110
+ print_fail "Debería rechazar hexcolor inválido"
111
+ fi
112
+ }
113
+
114
+ test_validate_select() {
115
+ print_test_header "Validaciones de Select"
116
+
117
+ source "$VALIDATE_LIB"
118
+
119
+ # Test 1: Opción válida
120
+ print_test "Opción válida"
121
+ run_test
122
+ if validate_select_strict "laravel" "laravel" "nodejs" "python" > /dev/null 2>&1; then
123
+ print_pass
124
+ else
125
+ print_fail "Debería aceptar opción válida"
126
+ fi
127
+
128
+ # Test 2: Opción inválida
129
+ print_test "Opción inválida"
130
+ run_test
131
+ if ! validate_select_strict "django" "laravel" "nodejs" "python" > /dev/null 2>&1; then
132
+ print_pass
133
+ else
134
+ print_fail "Debería rechazar opción inválida"
135
+ fi
136
+
137
+ # Test 3: Case-insensitive matching
138
+ print_test "Case-insensitive matching"
139
+ run_test
140
+ if validate_select_strict "Laravel" "laravel" "nodejs" "python" > /dev/null 2>&1; then
141
+ print_pass
142
+ else
143
+ print_fail "Debería aceptar opciones case-insensitive"
144
+ fi
145
+ }
146
+
147
+ test_validate_boolean() {
148
+ print_test_header "Validaciones de Boolean"
149
+
150
+ source "$VALIDATE_LIB"
151
+
152
+ # Test valores true
153
+ print_test "Boolean true (múltiples formatos)"
154
+ run_test
155
+ local all_true=true
156
+ for val in "true" "s" "si" "yes" "y" "1"; do
157
+ if ! validate_boolean_strict "$val" | grep -q "true"; then
158
+ all_true=false
159
+ fi
160
+ done
161
+ if $all_true; then
162
+ print_pass
163
+ else
164
+ print_fail "Debería normalizar todos los valores true"
165
+ fi
166
+
167
+ # Test valores false
168
+ print_test "Boolean false (múltiples formatos)"
169
+ run_test
170
+ local all_false=true
171
+ for val in "false" "n" "no" "0"; do
172
+ if ! validate_boolean_strict "$val" | grep -q "false"; then
173
+ all_false=false
174
+ fi
175
+ done
176
+ if $all_false; then
177
+ print_pass
178
+ else
179
+ print_fail "Debería normalizar todos los valores false"
180
+ fi
181
+
182
+ # Test valor inválido
183
+ print_test "Boolean inválido"
184
+ run_test
185
+ if ! validate_boolean_strict "maybe" > /dev/null 2>&1; then
186
+ print_pass
187
+ else
188
+ print_fail "Debería rechazar valor booleano inválido"
189
+ fi
190
+ }
191
+
192
+ test_validate_number() {
193
+ print_test_header "Validaciones de Number"
194
+
195
+ source "$VALIDATE_LIB"
196
+
197
+ # Test número válido en rango
198
+ print_test "Número válido en rango"
199
+ run_test
200
+ if validate_number_range "50" 0 100 > /dev/null 2>&1; then
201
+ print_pass
202
+ else
203
+ print_fail "Debería aceptar número en rango"
204
+ fi
205
+
206
+ # Test número menor al mínimo
207
+ print_test "Número menor al mínimo"
208
+ run_test
209
+ if ! validate_number_range "5" 10 100 > /dev/null 2>&1; then
210
+ print_pass
211
+ else
212
+ print_fail "Debería rechazar número menor al mínimo"
213
+ fi
214
+
215
+ # Test número mayor al máximo
216
+ print_test "Número mayor al máximo"
217
+ run_test
218
+ if ! validate_number_range "150" 0 100 > /dev/null 2>&1; then
219
+ print_pass
220
+ else
221
+ print_fail "Debería rechazar número mayor al máximo"
222
+ fi
223
+
224
+ # Test no es número
225
+ print_test "No es número"
226
+ run_test
227
+ if ! validate_number_range "abc" 0 100 > /dev/null 2>&1; then
228
+ print_pass
229
+ else
230
+ print_fail "Debería rechazar texto como número"
231
+ fi
232
+ }
233
+
234
+ # ============================================================================
235
+ # TESTS DE PARSER
236
+ # ============================================================================
237
+
238
+ test_parser() {
239
+ print_test_header "Parser CONTRATO.md"
240
+
241
+ # Crear CONTRATO.md de prueba
242
+ local test_dir="/tmp/specleap-test-$$"
243
+ mkdir -p "$test_dir"
244
+
245
+ cat > "$test_dir/CONTRATO.md" <<'EOF'
246
+ ---
247
+ project:
248
+ name: test-project
249
+ display_name: Test Project
250
+ identity:
251
+ objective: Test objective
252
+ problem_solved: Test problem
253
+ stack:
254
+ backend:
255
+ framework: laravel
256
+ features:
257
+ core:
258
+ - Feature 1
259
+ - Feature 2
260
+ ---
261
+
262
+ # Test Content
263
+ EOF
264
+
265
+ # Test 1: Parse exitoso
266
+ print_test "Parse CONTRATO.md válido"
267
+ run_test
268
+ if bash "$PARSE_SCRIPT" parse "$test_dir/CONTRATO.md" "$test_dir/output.json" > /dev/null 2>&1; then
269
+ if [[ -f "$test_dir/output.json" ]]; then
270
+ print_pass
271
+ else
272
+ print_fail "No se generó output.json"
273
+ fi
274
+ else
275
+ print_fail "Fallo al parsear"
276
+ fi
277
+
278
+ # Test 2: Validación estructura
279
+ print_test "Validar estructura CONTRATO.md"
280
+ run_test
281
+ if bash "$PARSE_SCRIPT" validate "$test_dir/CONTRATO.md" > /dev/null 2>&1; then
282
+ print_pass
283
+ else
284
+ print_fail "Validación debería pasar"
285
+ fi
286
+
287
+ # Test 3: Extraer nombre
288
+ print_test "Extraer project.name"
289
+ run_test
290
+ local extracted_name=$(bash "$PARSE_SCRIPT" get-name "$test_dir/CONTRATO.md" 2>/dev/null)
291
+ if [[ "$extracted_name" == "test-project" ]]; then
292
+ print_pass
293
+ else
294
+ print_fail "Debería extraer 'test-project', obtuvo: $extracted_name"
295
+ fi
296
+
297
+ # Cleanup
298
+ rm -rf "$test_dir"
299
+ }
300
+
301
+ # ============================================================================
302
+ # TESTS DE GENERACIÓN JIRA
303
+ # ============================================================================
304
+
305
+ test_jira_generation() {
306
+ print_test_header "Generación Backlog Jira"
307
+
308
+ # Crear CONTRATO.md de prueba
309
+ local test_dir="/tmp/specleap-test-jira-$$"
310
+ mkdir -p "$test_dir"
311
+
312
+ cat > "$test_dir/CONTRATO.md" <<'EOF'
313
+ ---
314
+ project:
315
+ name: test-jira
316
+ display_name: Test Jira Project
317
+ identity:
318
+ objective: Test Jira integration
319
+ problem_solved: Generate Jira backlog
320
+ stack:
321
+ backend:
322
+ framework: laravel
323
+ features:
324
+ core:
325
+ - Authentication
326
+ - Dashboard
327
+ - Reports
328
+ ---
329
+
330
+ # Test Content
331
+ EOF
332
+
333
+ # Test 1: Generar backlog
334
+ print_test "Generar backlog.json"
335
+ run_test
336
+ if bash "$JIRA_SCRIPT" "$test_dir/CONTRATO.md" > /dev/null 2>&1; then
337
+ if [[ -f "$test_dir/.jira/backlog.json" ]]; then
338
+ print_pass
339
+ else
340
+ print_fail "No se generó backlog.json"
341
+ fi
342
+ else
343
+ print_fail "Fallo al generar backlog"
344
+ fi
345
+
346
+ # Test 2: Estructura JSON válida
347
+ print_test "Estructura JSON válida"
348
+ run_test
349
+ if [[ -f "$test_dir/.jira/backlog.json" ]]; then
350
+ if jq empty "$test_dir/.jira/backlog.json" 2>/dev/null; then
351
+ print_pass
352
+ else
353
+ print_fail "JSON inválido"
354
+ fi
355
+ else
356
+ print_fail "Backlog no existe"
357
+ fi
358
+
359
+ # Test 3: Épicas generadas (debería ser 3, una por feature)
360
+ print_test "Épicas generadas (3 esperadas)"
361
+ run_test
362
+ if [[ -f "$test_dir/.jira/backlog.json" ]]; then
363
+ local epic_count=$(jq '.epics | length' "$test_dir/.jira/backlog.json")
364
+ if [[ "$epic_count" == "3" ]]; then
365
+ print_pass
366
+ else
367
+ print_fail "Esperado 3 épicas, obtuvo: $epic_count"
368
+ fi
369
+ else
370
+ print_fail "Backlog no existe"
371
+ fi
372
+
373
+ # Test 4: Stories por épica (debería ser 4 por épica)
374
+ print_test "Stories por épica (4 esperadas)"
375
+ run_test
376
+ if [[ -f "$test_dir/.jira/backlog.json" ]]; then
377
+ local story_count=$(jq '.epics[0].stories | length' "$test_dir/.jira/backlog.json")
378
+ if [[ "$story_count" == "4" ]]; then
379
+ print_pass
380
+ else
381
+ print_fail "Esperado 4 stories por épica, obtuvo: $story_count"
382
+ fi
383
+ else
384
+ print_fail "Backlog no existe"
385
+ fi
386
+
387
+ # Cleanup
388
+ rm -rf "$test_dir"
389
+ }
390
+
391
+ # ============================================================================
392
+ # MAIN
393
+ # ============================================================================
394
+
395
+ main() {
396
+ echo -e "${CYAN}${BOLD}"
397
+ echo "════════════════════════════════════════════════════════════════"
398
+ echo " 🧪 SpecLeap — Test Suite"
399
+ echo "════════════════════════════════════════════════════════════════"
400
+ echo -e "${RESET}"
401
+
402
+ test_validate_string
403
+ test_validate_select
404
+ test_validate_boolean
405
+ test_validate_number
406
+ test_parser
407
+ test_jira_generation
408
+
409
+ # Resumen
410
+ echo ""
411
+ echo -e "${CYAN}${BOLD}════════════════════════════════════════════════════════════════${RESET}"
412
+ echo -e "${BOLD}RESUMEN${RESET}"
413
+ echo -e "${CYAN} Tests ejecutados: ${BOLD}$TESTS_RUN${RESET}"
414
+ echo -e "${GREEN} Tests pasados: ${BOLD}$TESTS_PASSED${RESET}"
415
+ echo -e "${RED} Tests fallidos: ${BOLD}$TESTS_FAILED${RESET}"
416
+ echo -e "${CYAN}${BOLD}════════════════════════════════════════════════════════════════${RESET}"
417
+
418
+ if [[ $TESTS_FAILED -eq 0 ]]; then
419
+ echo -e "\n${GREEN}${BOLD}✅ Todos los tests pasaron!${RESET}\n"
420
+ exit 0
421
+ else
422
+ echo -e "\n${RED}${BOLD}❌ Algunos tests fallaron${RESET}\n"
423
+ exit 1
424
+ fi
425
+ }
426
+
427
+ # Ejecutar
428
+ main "$@"