elsabro 2.3.0 → 3.8.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 (71) hide show
  1. package/README.md +698 -20
  2. package/bin/install.js +0 -0
  3. package/flows/development-flow.json +452 -0
  4. package/flows/quick-flow.json +118 -0
  5. package/hooks/hooks-config-updated.json +285 -0
  6. package/hooks/skill-discovery.sh +539 -0
  7. package/package.json +3 -2
  8. package/references/SYSTEM_INDEX.md +400 -5
  9. package/references/agent-marketplace.md +2274 -0
  10. package/references/agent-protocol.md +1126 -0
  11. package/references/ai-code-suggestions.md +2413 -0
  12. package/references/checkpointing.md +595 -0
  13. package/references/collaboration-patterns.md +851 -0
  14. package/references/collaborative-sessions.md +1081 -0
  15. package/references/configuration-management.md +1810 -0
  16. package/references/cost-tracking.md +1095 -0
  17. package/references/enterprise-sso.md +2001 -0
  18. package/references/error-contracts-v2.md +968 -0
  19. package/references/event-driven.md +1031 -0
  20. package/references/flow-orchestration.md +940 -0
  21. package/references/flow-visualization.md +1557 -0
  22. package/references/ide-integrations.md +3513 -0
  23. package/references/interrupt-system.md +681 -0
  24. package/references/kubernetes-deployment.md +3099 -0
  25. package/references/memory-system.md +683 -0
  26. package/references/mobile-companion.md +3236 -0
  27. package/references/multi-llm-providers.md +2494 -0
  28. package/references/multi-project-memory.md +1182 -0
  29. package/references/observability.md +793 -0
  30. package/references/output-schemas.md +858 -0
  31. package/references/performance-profiler.md +955 -0
  32. package/references/plugin-system.md +1526 -0
  33. package/references/prompt-management.md +292 -0
  34. package/references/sandbox-execution.md +303 -0
  35. package/references/security-system.md +1253 -0
  36. package/references/skill-marketplace-integration.md +3901 -0
  37. package/references/streaming.md +696 -0
  38. package/references/testing-framework.md +1151 -0
  39. package/references/time-travel.md +802 -0
  40. package/references/tool-registry.md +886 -0
  41. package/references/voice-commands.md +3296 -0
  42. package/templates/agent-marketplace-config.json +220 -0
  43. package/templates/agent-protocol-config.json +136 -0
  44. package/templates/ai-suggestions-config.json +100 -0
  45. package/templates/checkpoint-state.json +61 -0
  46. package/templates/collaboration-config.json +157 -0
  47. package/templates/collaborative-sessions-config.json +153 -0
  48. package/templates/configuration-config.json +245 -0
  49. package/templates/cost-tracking-config.json +148 -0
  50. package/templates/enterprise-sso-config.json +438 -0
  51. package/templates/events-config.json +148 -0
  52. package/templates/flow-visualization-config.json +196 -0
  53. package/templates/ide-integrations-config.json +442 -0
  54. package/templates/kubernetes-config.json +764 -0
  55. package/templates/memory-state.json +84 -0
  56. package/templates/mobile-companion-config.json +600 -0
  57. package/templates/multi-llm-config.json +544 -0
  58. package/templates/multi-project-memory-config.json +145 -0
  59. package/templates/observability-config.json +109 -0
  60. package/templates/performance-profiler-config.json +125 -0
  61. package/templates/plugin-config.json +170 -0
  62. package/templates/prompt-management-config.json +86 -0
  63. package/templates/sandbox-config.json +185 -0
  64. package/templates/schemas-config.json +65 -0
  65. package/templates/security-config.json +120 -0
  66. package/templates/skill-marketplace-config.json +441 -0
  67. package/templates/streaming-config.json +72 -0
  68. package/templates/testing-config.json +81 -0
  69. package/templates/timetravel-config.json +62 -0
  70. package/templates/tool-registry-config.json +109 -0
  71. package/templates/voice-commands-config.json +658 -0
@@ -0,0 +1,539 @@
1
+ #!/bin/bash
2
+ # skill-discovery.sh - ELSABRO Hook para descubrir skills externos antes del planning
3
+ #
4
+ # Uso: bash ./hooks/skill-discovery.sh "descripción de tarea" "complejidad"
5
+ # Output: JSON con skills descubiertos, validados y rankeados
6
+ #
7
+ # Responsabilidades:
8
+ # 1. Extraer keywords de la descripción
9
+ # 2. Buscar skills en ELSABRO interno
10
+ # 3. Buscar skills en marketplace externo (skills.sh)
11
+ # 4. Validar y rankear resultados
12
+ # 5. Retornar JSON con estructura normalizada
13
+
14
+ set -e
15
+
16
+ # ============================================================================
17
+ # CONFIGURACIÓN Y CONSTANTES
18
+ # ============================================================================
19
+
20
+ # Directorios
21
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
22
+ PROJECT_ROOT="$(dirname "$SCRIPT_DIR")"
23
+ ELSABRO_SKILLS_DIR="${PROJECT_ROOT}/skills"
24
+ SKILLS_CACHE_FILE="${PROJECT_ROOT}/.cache/skills-discovery-cache.json"
25
+ SKILLS_REGISTRY="${HOME}/.elsabro/skills-registry.json"
26
+
27
+ # Configuración de descubrimiento
28
+ KEYWORDS_MIN_MATCH=1
29
+ MAX_SKILLS_RETURN=10
30
+ EXTERNAL_API_TIMEOUT=15
31
+ CACHE_TTL_SECONDS=3600
32
+
33
+ # Colores para stderr (feedback visual)
34
+ RED='\033[0;31m'
35
+ GREEN='\033[0;32m'
36
+ YELLOW='\033[1;33m'
37
+ BLUE='\033[0;34m'
38
+ CYAN='\033[0;36m'
39
+ NC='\033[0m'
40
+
41
+ # Prefijo de logs
42
+ PREFIX="[ELSABRO:skill-discovery]"
43
+
44
+ # ============================================================================
45
+ # UTILIDADES
46
+ # ============================================================================
47
+
48
+ log_info() {
49
+ echo -e "${BLUE}${PREFIX}${NC} $1" >&2
50
+ }
51
+
52
+ log_success() {
53
+ echo -e "${GREEN}${PREFIX}${NC} ✓ $1" >&2
54
+ }
55
+
56
+ log_warn() {
57
+ echo -e "${YELLOW}${PREFIX}${NC} ⚠ $1" >&2
58
+ }
59
+
60
+ log_error() {
61
+ echo -e "${RED}${PREFIX}${NC} ✗ $1" >&2
62
+ }
63
+
64
+ # Crear directorios si no existen
65
+ ensure_dirs() {
66
+ mkdir -p "$(dirname "$SKILLS_CACHE_FILE")" 2>/dev/null || true
67
+ }
68
+
69
+ # Verificar si caché es válido
70
+ is_cache_valid() {
71
+ local cache_file="$1"
72
+
73
+ if [ ! -f "$cache_file" ]; then
74
+ return 1
75
+ fi
76
+
77
+ # Verificar edad del caché (en segundos)
78
+ local file_age=$(($(date +%s) - $(stat -f%m "$cache_file" 2>/dev/null || echo 0)))
79
+
80
+ if [ "$file_age" -gt "$CACHE_TTL_SECONDS" ]; then
81
+ return 1
82
+ fi
83
+
84
+ return 0
85
+ }
86
+
87
+ # ============================================================================
88
+ # 1. EXTRACCIÓN DE KEYWORDS
89
+ # ============================================================================
90
+
91
+ # Extrae palabras clave de la descripción de tarea
92
+ # Entrada: string (descripción)
93
+ # Salida: JSON array con keywords encontradas
94
+ extract_keywords() {
95
+ local task_description="$1"
96
+
97
+ # Convertir a lowercase para búsqueda insensible
98
+ local lowercase=$(echo "$task_description" | tr '[:upper:]' '[:lower:]')
99
+
100
+ # Definir patrones de keywords por categoría
101
+ # Formato: categoria|sinónimo1|sinónimo2|sinónimo3
102
+ local keyword_patterns=(
103
+ "api|api|backend|endpoint|rest|graphql|http|server"
104
+ "auth|auth|login|signin|oauth|jwt|session|password|signup|credential"
105
+ "db|database|db|postgres|postgresql|mysql|mongodb|firebase|sql|orm"
106
+ "payments|payment|stripe|paypal|billing|checkout|commerce|transaction"
107
+ "mobile|mobile|expo|react-native|ios|android|app|swift|kotlin"
108
+ "web|website|web|nextjs|react|vue|angular|frontend|ui|ux|html|css"
109
+ "devops|devops|docker|kubernetes|k8s|ci|cd|github|gitlab|deploy"
110
+ "testing|test|jest|vitest|mocha|pytest|coverage|unit|e2e|qa"
111
+ "security|security|encrypt|https|cors|ssl|tls|hash|salt|breach"
112
+ "monitoring|monitor|sentry|logging|logs|error|analytics|observability"
113
+ "cli|cli|command|tool|script|automation|terminal|bash|shell"
114
+ "ai|ai|machine-learning|ml|gpt|claude|llm|nlp|transformer"
115
+ )
116
+
117
+ # Array para guardar keywords encontrados
118
+ local found_keywords=()
119
+ local found_categories=()
120
+
121
+ # Buscar cada patrón en la descripción
122
+ for pattern in "${keyword_patterns[@]}"; do
123
+ IFS='|' read -r category synmap <<< "$pattern"
124
+
125
+ # Crear regex de sinónimos
126
+ local regex=$(echo "$synmap" | sed 's/|/\\|/g')
127
+
128
+ # Buscar con grep case-insensitive
129
+ if echo "$lowercase" | grep -qiE "\b($regex)\b"; then
130
+ found_keywords+=("\"$category\"")
131
+ found_categories+=("$category")
132
+ fi
133
+ done
134
+
135
+ # Retornar como JSON array
136
+ # Si no encontró keywords, retornar array vacío
137
+ if [ ${#found_keywords[@]} -eq 0 ]; then
138
+ echo "[]"
139
+ else
140
+ printf "["
141
+ printf "%s" "${found_keywords[0]}"
142
+ for kw in "${found_keywords[@]:1}"; do
143
+ printf ",$kw"
144
+ done
145
+ printf "]\n"
146
+ fi
147
+ }
148
+
149
+ # ============================================================================
150
+ # 2. DESCUBRIMIENTO DE SKILLS - FUENTE 1: ELSABRO INTERNO
151
+ # ============================================================================
152
+
153
+ # Busca skills en ./skills/*.md
154
+ # Entrada: JSON array de keywords
155
+ # Salida: JSON array con skills ELSABRO encontrados
156
+ discover_elsabro_skills() {
157
+ local keywords="$1"
158
+
159
+ local skills_found=()
160
+
161
+ # Verificar que directorio existe
162
+ if [ ! -d "$ELSABRO_SKILLS_DIR" ]; then
163
+ echo "[]"
164
+ return
165
+ fi
166
+
167
+ # Iterar sobre cada archivo .md en skills/
168
+ for skill_file in "$ELSABRO_SKILLS_DIR"/*.md; do
169
+ [ -f "$skill_file" ] || continue
170
+
171
+ local skill_name=$(basename "$skill_file" .md)
172
+ local skill_content=$(cat "$skill_file")
173
+
174
+ # ---- Extraer metadata YAML ----
175
+ # Buscar secciones YAML en el front matter
176
+
177
+ local description=$(
178
+ echo "$skill_content" | sed -n '/^description:/s/^description: *//p' | head -1
179
+ )
180
+ description="${description:0:80}" # Limitar a 80 caracteres
181
+
182
+ local difficulty=$(
183
+ echo "$skill_content" | sed -n '/^difficulty:/s/^difficulty: *//p' | head -1
184
+ )
185
+ difficulty="${difficulty:-intermediate}"
186
+
187
+ local estimated_time=$(
188
+ echo "$skill_content" | sed -n '/^estimated_time:/s/^estimated_time: *//p' | head -1
189
+ )
190
+
191
+ # Extraer tags (múltiples líneas)
192
+ local tags=$(
193
+ echo "$skill_content" |
194
+ sed -n '/^tags:/,/^[^ -]/p' |
195
+ grep "^ - " |
196
+ sed 's/^ - //' |
197
+ head -10
198
+ )
199
+
200
+ # ---- Calcular match score ----
201
+ # Score = cantidad de keywords que coinciden con tags/description
202
+
203
+ local match_score=0
204
+
205
+ # Convertir keywords de JSON array a array bash
206
+ local kw_array=()
207
+ if command -v jq &> /dev/null; then
208
+ while IFS= read -r kw; do
209
+ kw_array+=("$kw")
210
+ done < <(echo "$keywords" | jq -r '.[]' 2>/dev/null)
211
+ fi
212
+
213
+ # Buscar keywords en tags y descripción
214
+ for keyword in "${kw_array[@]}"; do
215
+ if echo "$tags" | grep -qi "$keyword"; then
216
+ ((match_score++))
217
+ fi
218
+ if echo "$description" | grep -qi "$keyword"; then
219
+ ((match_score++))
220
+ fi
221
+ done
222
+
223
+ # Solo incluir si hay al menos un match
224
+ if [ "$match_score" -ge "$KEYWORDS_MIN_MATCH" ]; then
225
+ # Construir objeto skill JSON
226
+ local tags_json=$(echo "$tags" | jq -R -s -c 'split("\n") | map(select(length > 0))')
227
+
228
+ local skill_obj=$(cat <<EOF
229
+ {
230
+ "id": "$skill_name",
231
+ "source": "elsabro",
232
+ "status": "available",
233
+ "match_score": $match_score,
234
+ "description": "$description",
235
+ "difficulty": "$difficulty",
236
+ "estimated_time": "$estimated_time",
237
+ "tags": $tags_json,
238
+ "rank": 0
239
+ }
240
+ EOF
241
+ )
242
+
243
+ skills_found+=("$skill_obj")
244
+ fi
245
+ done
246
+
247
+ # Retornar como JSON array
248
+ if [ ${#skills_found[@]} -eq 0 ]; then
249
+ echo "[]"
250
+ else
251
+ # Usar jq para construir array válido
252
+ printf '%s\n' "${skills_found[@]}" | jq -s '.'
253
+ fi
254
+ }
255
+
256
+ # ============================================================================
257
+ # 3. DESCUBRIMIENTO DE SKILLS - FUENTE 2: MARKETPLACE EXTERNO
258
+ # ============================================================================
259
+
260
+ # Consulta API de skills.sh para encontrar skills externos
261
+ # Entrada: JSON array de keywords
262
+ # Salida: JSON array con skills de marketplace
263
+ discover_external_skills() {
264
+ local keywords="$1"
265
+
266
+ # Si no está disponible curl o jq, retornar array vacío
267
+ if ! command -v curl &> /dev/null || ! command -v jq &> /dev/null; then
268
+ log_warn "curl o jq no disponible, saltando external skills"
269
+ echo "[]"
270
+ return
271
+ fi
272
+
273
+ # URL de la API
274
+ local api_url="https://api.skills.sh/v1/discover"
275
+
276
+ # Payload: array de keywords
277
+ local payload=$(echo "$keywords" | jq -c '.')
278
+
279
+ log_info "Consultando API: $api_url con keywords: $payload"
280
+
281
+ # Hacer petición HTTP con timeout
282
+ local response=$(
283
+ timeout "$EXTERNAL_API_TIMEOUT" curl -s \
284
+ -X POST "$api_url" \
285
+ -H "Content-Type: application/json" \
286
+ -d "{\"keywords\": $payload}" \
287
+ 2>/dev/null || echo "[]"
288
+ )
289
+
290
+ # Procesar respuesta (asumir estructura: { "skills": [...] })
291
+ if echo "$response" | jq empty 2>/dev/null; then
292
+ # Extractar y enriquecer skills
293
+ echo "$response" | jq -c '
294
+ .skills[]? // empty |
295
+ . + {
296
+ status: "available",
297
+ rank: 0,
298
+ install_command: ("curl -s https://skills.sh/install/" + .id + " | bash")
299
+ }
300
+ ' | jq -s '.'
301
+ else
302
+ log_warn "API response inválido, retornando array vacío"
303
+ echo "[]"
304
+ fi
305
+ }
306
+
307
+ # ============================================================================
308
+ # 4. VALIDACIÓN Y RANKING
309
+ # ============================================================================
310
+
311
+ # Valida y rankea todos los skills descubiertos
312
+ # Entrada: JSON array de skills
313
+ # Salida: JSON array validado y ordenado por rank
314
+ validate_and_rank_skills() {
315
+ local all_skills="$1"
316
+
317
+ if ! command -v jq &> /dev/null; then
318
+ log_warn "jq no disponible, retornando skills sin validación"
319
+ echo "$all_skills"
320
+ return
321
+ fi
322
+
323
+ # Validar y rankear con jq
324
+ echo "$all_skills" | jq -c '
325
+ # Filtrar skills válidos
326
+ map(
327
+ select(
328
+ .id != null and
329
+ .source != null and
330
+ (.status == "available" or .status == "installable")
331
+ )
332
+ ) |
333
+ # Agregar score de ranking
334
+ map(
335
+ . + {
336
+ rank: (
337
+ # Base: match_score
338
+ (.match_score // 0) * 100 +
339
+ # Bonus por dificultad (beginner > advanced)
340
+ (if .difficulty == "beginner" then 50 else
341
+ if .difficulty == "intermediate" then 30 else
342
+ if .difficulty == "advanced" then 10 else 0 end end) +
343
+ # Bonus por source (elsabro es más confiable)
344
+ (if .source == "elsabro" then 20 else 0 end) +
345
+ # Penalty por external que requiere instalación
346
+ (if (.install_command != null) then 0 else 5 end)
347
+ )
348
+ }
349
+ ) |
350
+ # Ordenar por ranking descendente
351
+ sort_by(.rank) | reverse |
352
+ # Limitar a top 10
353
+ .[0:10]
354
+ '
355
+ }
356
+
357
+ # ============================================================================
358
+ # 5. CACHÉ
359
+ # ============================================================================
360
+
361
+ # Intenta obtener skills del caché
362
+ # Entrada: keywords (string)
363
+ # Salida: JSON array con skills si caché válido, "null" si no
364
+ get_from_cache() {
365
+ local keywords="$1"
366
+ local keywords_hash=$(echo -n "$keywords" | md5 2>/dev/null || echo "$keywords" | md5sum | awk '{print $1}')
367
+
368
+ if ! is_cache_valid "$SKILLS_CACHE_FILE"; then
369
+ return 1
370
+ fi
371
+
372
+ # Buscar en caché con jq
373
+ if command -v jq &> /dev/null; then
374
+ local cached=$(
375
+ jq --arg hash "$keywords_hash" '.cache[$hash]?' "$SKILLS_CACHE_FILE" 2>/dev/null
376
+ )
377
+
378
+ if [ "$cached" != "null" ] && [ -n "$cached" ]; then
379
+ log_success "Skill cache hit"
380
+ echo "$cached"
381
+ return 0
382
+ fi
383
+ fi
384
+
385
+ return 1
386
+ }
387
+
388
+ # Guardar resultado en caché
389
+ save_to_cache() {
390
+ local keywords="$1"
391
+ local skills="$2"
392
+ local keywords_hash=$(echo -n "$keywords" | md5 2>/dev/null || echo "$keywords" | md5sum | awk '{print $1}')
393
+
394
+ ensure_dirs
395
+
396
+ # Crear o actualizar caché
397
+ if [ -f "$SKILLS_CACHE_FILE" ]; then
398
+ jq --arg hash "$keywords_hash" --argjson skills "$skills" \
399
+ '.cache[$hash] = $skills' "$SKILLS_CACHE_FILE" > "$SKILLS_CACHE_FILE.tmp"
400
+ mv "$SKILLS_CACHE_FILE.tmp" "$SKILLS_CACHE_FILE"
401
+ else
402
+ # Crear caché nuevo
403
+ jq -n --arg hash "$keywords_hash" --argjson skills "$skills" \
404
+ '{cache: {($hash): $skills}}' > "$SKILLS_CACHE_FILE"
405
+ fi
406
+ }
407
+
408
+ # ============================================================================
409
+ # 6. OUTPUT Y FORMATEO
410
+ # ============================================================================
411
+
412
+ # Formatea output final como JSON normalizado
413
+ # Entrada: keywords, skills de cada fuente, skills rankeados
414
+ # Salida: JSON con estructura completa
415
+ format_discovery_output() {
416
+ local keywords="$1"
417
+ local elsabro_skills="$2"
418
+ local external_skills="$3"
419
+ local ranked_skills="$4"
420
+
421
+ if ! command -v jq &> /dev/null; then
422
+ # Fallback si jq no está disponible
423
+ cat <<EOF
424
+ {
425
+ "timestamp": "$(date -u +%Y-%m-%dT%H:%M:%SZ)",
426
+ "status": "error",
427
+ "message": "jq not available"
428
+ }
429
+ EOF
430
+ return 1
431
+ fi
432
+
433
+ # Contar elementos
434
+ local elsabro_count=$(echo "$elsabro_skills" | jq 'length')
435
+ local external_count=$(echo "$external_skills" | jq 'length')
436
+ local ranked_count=$(echo "$ranked_skills" | jq 'length')
437
+
438
+ # Extraer top 3 recomendaciones
439
+ local recommendations=$(
440
+ echo "$ranked_skills" | jq -r '.[0:3] | map(.id) | .[]' | jq -Rs 'split("\n") | map(select(length > 0))'
441
+ )
442
+
443
+ # Construir output final
444
+ cat <<EOF | jq -c '.'
445
+ {
446
+ "timestamp": "$(date -u +%Y-%m-%dT%H:%M:%SZ)",
447
+ "keywords_detected": $keywords,
448
+ "discovery": {
449
+ "elsabro": {
450
+ "count": $elsabro_count,
451
+ "skills": $elsabro_skills
452
+ },
453
+ "external": {
454
+ "count": $external_count,
455
+ "skills": $external_skills
456
+ }
457
+ },
458
+ "ranked": {
459
+ "count": $ranked_count,
460
+ "skills": $ranked_skills,
461
+ "recommendations": $recommendations
462
+ },
463
+ "status": "success"
464
+ }
465
+ EOF
466
+ }
467
+
468
+ # ============================================================================
469
+ # 7. FUNCIÓN PRINCIPAL
470
+ # ============================================================================
471
+
472
+ main() {
473
+ local task_description="${1:-}"
474
+ local complexity="${2:-medium}"
475
+
476
+ # Validación de entrada
477
+ if [ -z "$task_description" ]; then
478
+ cat <<EOF | jq -c '.'
479
+ {
480
+ "status": "error",
481
+ "message": "Task description required",
482
+ "timestamp": "$(date -u +%Y-%m-%dT%H:%M:%SZ)"
483
+ }
484
+ EOF
485
+ exit 1
486
+ fi
487
+
488
+ log_info "Analizando: $task_description (complejidad: $complexity)"
489
+
490
+ # ---- FASE 1: Extraer keywords ----
491
+ log_info "Extrayendo keywords..."
492
+ local keywords=$(extract_keywords "$task_description")
493
+ log_success "Keywords: $(echo $keywords | jq -r 'join(", ")')"
494
+
495
+ # ---- FASE 2: Buscar skills (con caché) ----
496
+ local keywords_str=$(echo "$keywords" | jq -r 'join(",")')
497
+ local cached_result=""
498
+
499
+ if cached_result=$(get_from_cache "$keywords_str"); then
500
+ log_success "Usando resultados del caché"
501
+ # Output y exit
502
+ echo "$cached_result"
503
+ exit 0
504
+ fi
505
+
506
+ # ---- FASE 3: Descubrir skills de múltiples fuentes ----
507
+ log_info "Descubriendo skills internos (ELSABRO)..."
508
+ local elsabro_skills=$(discover_elsabro_skills "$keywords")
509
+ log_success "ELSABRO skills encontrados: $(echo $elsabro_skills | jq 'length')"
510
+
511
+ log_info "Descubriendo skills externos (skills.sh)..."
512
+ local external_skills=$(discover_external_skills "$keywords")
513
+ log_success "External skills encontrados: $(echo $external_skills | jq 'length')"
514
+
515
+ # ---- FASE 4: Combinar y rankear ----
516
+ log_info "Combinando y rankeando skills..."
517
+ local all_skills=$(echo "[$elsabro_skills, $external_skills]" | jq -s 'add // []')
518
+ local ranked=$(validate_and_rank_skills "$all_skills")
519
+ log_success "Skills rankeados: $(echo $ranked | jq 'length')"
520
+
521
+ # ---- FASE 5: Formatear output ----
522
+ log_info "Formateando output..."
523
+ local output=$(format_discovery_output "$keywords" "$elsabro_skills" "$external_skills" "$ranked")
524
+
525
+ # Guardar en caché
526
+ save_to_cache "$keywords_str" "$output"
527
+
528
+ # Output final (STDOUT) - esto es lo que captura el Flow Engine
529
+ echo "$output"
530
+
531
+ log_success "Discovery completado"
532
+ exit 0
533
+ }
534
+
535
+ # ============================================================================
536
+ # EJECUCIÓN
537
+ # ============================================================================
538
+
539
+ main "$@"
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "elsabro",
3
- "version": "2.3.0",
4
- "description": "Sistema de desarrollo AI-powered para Claude Code - El mejor asistente para crear apps sin experiencia previa",
3
+ "version": "3.8.0",
4
+ "description": "Sistema de desarrollo AI-powered para Claude Code - Orquestación avanzada con checkpointing, memoria multi-nivel y flows declarativos",
5
5
  "bin": {
6
6
  "elsabro": "bin/install.js"
7
7
  },
@@ -12,6 +12,7 @@
12
12
  "skills",
13
13
  "templates",
14
14
  "workflows",
15
+ "flows",
15
16
  "references",
16
17
  "hooks",
17
18
  "scripts"