elsabro 2.1.0 → 2.3.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 (64) hide show
  1. package/agents/elsabro-orchestrator.md +113 -0
  2. package/commands/elsabro/add-phase.md +17 -0
  3. package/commands/elsabro/add-todo.md +111 -53
  4. package/commands/elsabro/audit-milestone.md +19 -0
  5. package/commands/elsabro/check-todos.md +210 -31
  6. package/commands/elsabro/complete-milestone.md +20 -1
  7. package/commands/elsabro/debug.md +19 -0
  8. package/commands/elsabro/discuss-phase.md +18 -1
  9. package/commands/elsabro/execute.md +511 -58
  10. package/commands/elsabro/insert-phase.md +18 -1
  11. package/commands/elsabro/list-phase-assumptions.md +17 -0
  12. package/commands/elsabro/new-milestone.md +19 -0
  13. package/commands/elsabro/new.md +19 -0
  14. package/commands/elsabro/pause-work.md +19 -0
  15. package/commands/elsabro/plan-milestone-gaps.md +20 -1
  16. package/commands/elsabro/plan.md +264 -36
  17. package/commands/elsabro/progress.md +203 -79
  18. package/commands/elsabro/quick.md +19 -0
  19. package/commands/elsabro/remove-phase.md +17 -0
  20. package/commands/elsabro/research-phase.md +18 -1
  21. package/commands/elsabro/resume-work.md +19 -0
  22. package/commands/elsabro/start.md +399 -98
  23. package/commands/elsabro/verify-work.md +138 -5
  24. package/hooks/confirm-destructive.sh +145 -0
  25. package/hooks/hooks-config.json +81 -0
  26. package/hooks/lint-check.sh +238 -0
  27. package/hooks/post-edit-test.sh +189 -0
  28. package/package.json +3 -2
  29. package/references/SYSTEM_INDEX.md +241 -0
  30. package/references/command-flow.md +352 -0
  31. package/references/enforcement-rules.md +331 -0
  32. package/references/error-contracts-tests.md +1171 -0
  33. package/references/error-contracts.md +3102 -0
  34. package/references/error-handling-instructions.md +26 -12
  35. package/references/parallel-worktrees.md +293 -0
  36. package/references/state-sync.md +381 -0
  37. package/references/task-dispatcher.md +388 -0
  38. package/references/tasks-integration.md +380 -0
  39. package/scripts/setup-parallel-worktrees.sh +319 -0
  40. package/skills/api-microservice.md +765 -0
  41. package/skills/api-setup.md +76 -3
  42. package/skills/auth-setup.md +46 -6
  43. package/skills/chrome-extension.md +584 -0
  44. package/skills/cicd-setup.md +1206 -0
  45. package/skills/cli-tool.md +884 -0
  46. package/skills/database-setup.md +41 -5
  47. package/skills/desktop-app.md +1351 -0
  48. package/skills/expo-app.md +35 -2
  49. package/skills/full-stack-app.md +543 -0
  50. package/skills/memory-update.md +207 -0
  51. package/skills/mobile-app.md +813 -0
  52. package/skills/nextjs-app.md +33 -2
  53. package/skills/payments-setup.md +76 -1
  54. package/skills/review.md +331 -0
  55. package/skills/saas-starter.md +639 -0
  56. package/skills/sentry-setup.md +41 -7
  57. package/skills/techdebt.md +289 -0
  58. package/skills/testing-setup.md +1218 -0
  59. package/skills/tutor.md +219 -0
  60. package/templates/.planning/notes/.gitkeep +0 -0
  61. package/templates/CLAUDE.md.template +48 -0
  62. package/templates/error-handling-config.json +79 -2
  63. package/templates/mistakes.md.template +52 -0
  64. package/templates/patterns.md.template +114 -0
@@ -3,6 +3,7 @@ name: verify-work
3
3
  description: Verificación completa del trabajo realizado usando agentes paralelos con Tasks
4
4
  allowed-tools:
5
5
  - Read
6
+ - Write
6
7
  - Bash
7
8
  - Glob
8
9
  - Grep
@@ -11,12 +12,127 @@ allowed-tools:
11
12
  - TaskUpdate
12
13
  - TaskList
13
14
  - TaskGet
15
+ - AskUserQuestion
16
+ sync:
17
+ reads: [".elsabro/state.json"]
18
+ writes: [".elsabro/state.json", ".elsabro/context.md", ".planning/VERIFICATION-REPORT.md"]
19
+ phases: ["initializing", "verifying", "aggregating", "done"]
20
+ passes_context_to: ["execute (si gaps)", "done"]
21
+ dispatcher:
22
+ verification:
23
+ agents: [pr-review-toolkit:code-reviewer, pr-review-toolkit:silent-failure-hunter, pr-review-toolkit:pr-test-analyzer]
24
+ model: opus
25
+ parallel: true
26
+ min_agents: 3
14
27
  ---
15
28
 
16
29
  # /elsabro:verify-work
17
30
 
18
31
  <command-name>verify-work</command-name>
19
32
 
33
+ <state_sync>
34
+ ## SINCRONIZACIÓN DE ESTADO (OBLIGATORIO)
35
+
36
+ **IMPORTAR**: Este comando DEBE seguir `/references/state-sync.md` y `/references/enforcement-rules.md`.
37
+
38
+ ### Al Iniciar (ANTES de cualquier operación)
39
+
40
+ ```javascript
41
+ // 1. Crear task de inicialización
42
+ TaskCreate({
43
+ subject: "Initialize verify-work command",
44
+ description: "Leer estado y preparar verificación",
45
+ activeForm: "Inicializando..."
46
+ })
47
+ TaskUpdate(id, status: "in_progress")
48
+
49
+ // 2. Leer estado existente
50
+ const state = Read(".elsabro/state.json") || createInitialState();
51
+
52
+ // 3. Verificar contexto de execute (archivos a verificar)
53
+ if (state.context.changed_files && state.context.changed_files.length > 0) {
54
+ console.log("Archivos a verificar:", state.context.changed_files);
55
+ console.log("Commits a revisar:", state.context.commits);
56
+ } else {
57
+ // No hay contexto de execute - verificar todo
58
+ console.log("Sin contexto de execute - verificación completa");
59
+ }
60
+
61
+ // 4. Actualizar estado
62
+ state.current_flow = { command: "verify-work", phase: "initializing", started_at: new Date().toISOString() };
63
+ Write(".elsabro/state.json", JSON.stringify(state, null, 2));
64
+
65
+ // 5. Completar task de inicialización
66
+ TaskUpdate(id, status: "completed")
67
+ ```
68
+
69
+ ### Al Cambiar de Fase
70
+
71
+ ```javascript
72
+ // Antes de verificación
73
+ state.current_flow.phase = "verifying";
74
+ Write(".elsabro/state.json", JSON.stringify(state, null, 2));
75
+
76
+ // Antes de agregación
77
+ state.current_flow.phase = "aggregating";
78
+ Write(".elsabro/state.json", JSON.stringify(state, null, 2));
79
+ ```
80
+
81
+ ### Al Completar
82
+
83
+ ```javascript
84
+ // Registrar en historial
85
+ state.history.push({
86
+ command: "verify-work",
87
+ completed_at: new Date().toISOString(),
88
+ result: verificationResult, // "PASS" | "FAIL" | "PARTIAL"
89
+ artifact: ".planning/VERIFICATION-REPORT.md"
90
+ });
91
+
92
+ // Actualizar contexto
93
+ state.context.verification_result = verificationResult;
94
+ state.context.ready_for_merge = verificationResult === "PASS";
95
+
96
+ // Limpiar flujo y sugerir siguiente
97
+ state.current_flow = null;
98
+ state.suggested_next = verificationResult === "PASS" ? null : "execute"; // null = done
99
+
100
+ Write(".elsabro/state.json", JSON.stringify(state, null, 2));
101
+
102
+ // Actualizar context.md legible
103
+ Write(".elsabro/context.md", generateHumanReadableContext(state));
104
+ ```
105
+ </state_sync>
106
+
107
+ <review_integration>
108
+ ## Integración con Code Review
109
+
110
+ **IMPORTAR**: Este comando puede invocar `/elsabro:review` para verificación detallada.
111
+
112
+ ### Opción: Review Profundo
113
+
114
+ Si el usuario solicita verificación exhaustiva, invocar:
115
+
116
+ ```javascript
117
+ // Verificación con code review profesional
118
+ Task({
119
+ subagent_type: "skill:review",
120
+ prompt: `
121
+ /elsabro:review --staged --save
122
+
123
+ Guarda el resultado en .planning/REVIEW.md
124
+ `
125
+ })
126
+ ```
127
+
128
+ ### Checklist de Verificación Extendido
129
+
130
+ Además de los checks estándar, verificar contra:
131
+ - `.planning/mistakes.md` - ¿Se cometieron errores conocidos?
132
+ - `.planning/patterns.md` - ¿Se siguieron los patrones preferidos?
133
+ - `.planning/CLAUDE.md` - ¿Se respetaron las reglas del proyecto?
134
+ </review_integration>
135
+
20
136
  ## Propósito
21
137
 
22
138
  Verificar que el trabajo completado cumple con los requirements, pasa todos los tests, y está listo para merge/deploy.
@@ -196,7 +312,9 @@ Para verificación, usamos `policy: fail_fast` porque todos los checks son crít
196
312
  └────────────────────────────────────────────────┘
197
313
  ```
198
314
 
199
- ### Lanzamiento de Agentes con Tasks
315
+ ### Lanzamiento de Agentes OPUS x3 con Tasks
316
+
317
+ **OBLIGATORIO:** Usar 3 agentes OPUS especializados para verificación profunda.
200
318
 
201
319
  ```javascript
202
320
  // 1. Marcar todos como in_progress
@@ -204,10 +322,25 @@ TaskUpdate({ taskId: "functional-id", status: "in_progress" })
204
322
  TaskUpdate({ taskId: "quality-id", status: "in_progress" })
205
323
  TaskUpdate({ taskId: "security-id", status: "in_progress" })
206
324
 
207
- // 2. Lanzar agentes EN UN SOLO MENSAJE (paralelo real)
208
- Task(elsabro-verifier, model: "opus"): Verify functional requirements |
209
- Task(elsabro-verifier, model: "opus"): Verify quality metrics |
210
- Task(elsabro-verifier, model: "opus"): Verify security and edge cases
325
+ // 2. Lanzar 3 agentes OPUS EN UN SOLO MENSAJE (paralelo real)
326
+ Task({
327
+ subagent_type: "pr-review-toolkit:code-reviewer",
328
+ model: "opus", // OPUS para análisis profundo
329
+ description: "Code review completo",
330
+ prompt: "Revisa los cambios buscando bugs, code smells, mejores prácticas, seguridad..."
331
+ }) |
332
+ Task({
333
+ subagent_type: "pr-review-toolkit:silent-failure-hunter",
334
+ model: "opus", // ← OPUS para edge cases
335
+ description: "Buscar errores ocultos",
336
+ prompt: "Busca errores silenciosos, try/catch que ocultan errores, fallbacks problemáticos..."
337
+ }) |
338
+ Task({
339
+ subagent_type: "pr-review-toolkit:pr-test-analyzer",
340
+ model: "opus", // ← OPUS para análisis de tests
341
+ description: "Analizar cobertura de tests",
342
+ prompt: "Verifica que los tests cubren los cambios, busca casos críticos sin test..."
343
+ })
211
344
 
212
345
  // 3. Al completar cada uno, marcar completed
213
346
  TaskUpdate({
@@ -0,0 +1,145 @@
1
+ #!/bin/bash
2
+ # confirm-destructive.sh - ELSABRO Hook: Confirmar antes de operaciones destructivas
3
+ # Uso: Este hook se ejecuta antes de comandos Bash que coinciden con patrones destructivos
4
+ # Patrones: rm -rf, git reset --hard, git clean -fd, git push --force, drop table, truncate
5
+
6
+ # Colores
7
+ RED='\033[0;31m'
8
+ GREEN='\033[0;32m'
9
+ YELLOW='\033[1;33m'
10
+ BLUE='\033[0;34m'
11
+ BOLD='\033[1m'
12
+ NC='\033[0m'
13
+
14
+ # Prefijo ELSABRO
15
+ PREFIX="[ELSABRO:hook]"
16
+
17
+ # Comando que se va a ejecutar (pasado como argumento)
18
+ COMMAND="${1:-}"
19
+
20
+ # Patrones destructivos y su descripcion
21
+ declare -A DESTRUCTIVE_PATTERNS=(
22
+ ["rm -rf"]="Eliminacion recursiva forzada de archivos/directorios"
23
+ ["rm -r"]="Eliminacion recursiva de archivos/directorios"
24
+ ["git reset --hard"]="Descarta TODOS los cambios locales sin posibilidad de recuperacion"
25
+ ["git clean -fd"]="Elimina archivos no rastreados y directorios"
26
+ ["git clean -f"]="Elimina archivos no rastreados"
27
+ ["git push --force"]="Sobreescribe historial remoto (puede perder commits de otros)"
28
+ ["git push -f"]="Sobreescribe historial remoto (puede perder commits de otros)"
29
+ ["DROP TABLE"]="Elimina tabla de base de datos permanentemente"
30
+ ["drop table"]="Elimina tabla de base de datos permanentemente"
31
+ ["TRUNCATE"]="Elimina todos los datos de una tabla"
32
+ ["truncate"]="Elimina todos los datos de una tabla"
33
+ ["DELETE FROM"]="Elimina registros de base de datos"
34
+ ["delete from"]="Elimina registros de base de datos"
35
+ ["> /dev/null"]="Redirige output (potencialmente peligroso si mal usado)"
36
+ ["chmod 777"]="Permisos inseguros - todos pueden leer/escribir/ejecutar"
37
+ ["chmod -R"]="Cambio recursivo de permisos"
38
+ ["dd if="]="Operacion de disco de bajo nivel"
39
+ ["mkfs"]="Formateo de sistema de archivos"
40
+ [":(){ :|:& };:"]="Fork bomb - puede crashear el sistema"
41
+ )
42
+
43
+ # Detectar patron destructivo
44
+ detect_destructive_pattern() {
45
+ local cmd="$1"
46
+
47
+ for pattern in "${!DESTRUCTIVE_PATTERNS[@]}"; do
48
+ if [[ "$cmd" == *"$pattern"* ]]; then
49
+ echo "$pattern"
50
+ return 0
51
+ fi
52
+ done
53
+
54
+ echo ""
55
+ return 1
56
+ }
57
+
58
+ # Mostrar advertencia
59
+ show_warning() {
60
+ local pattern="$1"
61
+ local description="${DESTRUCTIVE_PATTERNS[$pattern]}"
62
+
63
+ echo ""
64
+ echo -e "${RED}${BOLD}========================================${NC}"
65
+ echo -e "${RED}${BOLD} ADVERTENCIA: OPERACION DESTRUCTIVA${NC}"
66
+ echo -e "${RED}${BOLD}========================================${NC}"
67
+ echo ""
68
+ echo -e "${YELLOW}$PREFIX Comando detectado:${NC}"
69
+ echo -e "${BLUE} $COMMAND${NC}"
70
+ echo ""
71
+ echo -e "${YELLOW}$PREFIX Patron peligroso:${NC} ${RED}$pattern${NC}"
72
+ echo -e "${YELLOW}$PREFIX Riesgo:${NC} $description"
73
+ echo ""
74
+ echo -e "${RED}${BOLD}Este comando puede causar perdida de datos irreversible.${NC}"
75
+ echo ""
76
+ }
77
+
78
+ # Solicitar confirmacion
79
+ request_confirmation() {
80
+ # En modo no interactivo (CI/CD), rechazar automaticamente
81
+ if [ ! -t 0 ]; then
82
+ echo -e "${RED}$PREFIX Modo no interactivo detectado - rechazando comando destructivo${NC}"
83
+ echo -e "${YELLOW}$PREFIX Para ejecutar en CI, desactiva el hook 'confirm-destructive'${NC}"
84
+ return 1
85
+ fi
86
+
87
+ echo -e "${YELLOW}Para confirmar, escribe exactamente: ${BOLD}SI CONFIRMO${NC}"
88
+ echo -n "> "
89
+ read -r confirmation
90
+
91
+ if [ "$confirmation" = "SI CONFIRMO" ]; then
92
+ echo -e "${GREEN}$PREFIX Confirmado. Procediendo con el comando...${NC}"
93
+ return 0
94
+ else
95
+ echo -e "${RED}$PREFIX Cancelado. El comando NO se ejecutara.${NC}"
96
+ return 1
97
+ fi
98
+ }
99
+
100
+ # Registrar en log
101
+ log_destructive_attempt() {
102
+ local pattern="$1"
103
+ local confirmed="$2"
104
+ local log_dir=".planning/logs"
105
+ local log_file="$log_dir/destructive-commands.log"
106
+
107
+ # Crear directorio si no existe
108
+ mkdir -p "$log_dir" 2>/dev/null || true
109
+
110
+ local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
111
+ local status="REJECTED"
112
+ [ "$confirmed" = "true" ] && status="CONFIRMED"
113
+
114
+ echo "[$timestamp] $status | Pattern: $pattern | Command: $COMMAND" >> "$log_file" 2>/dev/null || true
115
+ }
116
+
117
+ # Main
118
+ main() {
119
+ if [ -z "$COMMAND" ]; then
120
+ # Sin comando, permitir (no hay nada que verificar)
121
+ exit 0
122
+ fi
123
+
124
+ # Detectar si es destructivo
125
+ local pattern=$(detect_destructive_pattern "$COMMAND")
126
+
127
+ if [ -z "$pattern" ]; then
128
+ # No es destructivo, permitir
129
+ exit 0
130
+ fi
131
+
132
+ # Es destructivo - mostrar advertencia
133
+ show_warning "$pattern"
134
+
135
+ # Solicitar confirmacion
136
+ if request_confirmation; then
137
+ log_destructive_attempt "$pattern" "true"
138
+ exit 0 # Permitir ejecucion
139
+ else
140
+ log_destructive_attempt "$pattern" "false"
141
+ exit 1 # Bloquear ejecucion
142
+ fi
143
+ }
144
+
145
+ main "$@"
@@ -0,0 +1,81 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "description": "ELSABRO Hooks Configuration - Sistema de hooks automaticos para flujos de trabajo",
4
+ "version": "1.0.0",
5
+ "hooks": {
6
+ "PostToolUse": [
7
+ {
8
+ "name": "auto-test-on-edit",
9
+ "description": "Ejecuta tests automaticamente despues de editar codigo",
10
+ "matcher": "Write|Edit",
11
+ "command": "./hooks/post-edit-test.sh",
12
+ "timeout": 30000,
13
+ "enabled": true
14
+ },
15
+ {
16
+ "name": "lint-on-save",
17
+ "description": "Ejecuta linter automaticamente despues de escribir",
18
+ "matcher": "Write",
19
+ "command": "./hooks/lint-check.sh",
20
+ "timeout": 10000,
21
+ "enabled": true
22
+ }
23
+ ],
24
+ "PreToolUse": [
25
+ {
26
+ "name": "confirm-destructive",
27
+ "description": "Confirmar antes de operaciones destructivas",
28
+ "matcher": "Bash",
29
+ "pattern": "rm -rf|git reset --hard|git clean -fd|git push --force|drop table|truncate",
30
+ "command": "./hooks/confirm-destructive.sh",
31
+ "timeout": 60000,
32
+ "enabled": true
33
+ }
34
+ ],
35
+ "Notification": [
36
+ {
37
+ "name": "task-complete-notify",
38
+ "description": "Notifica cuando una tarea larga termina",
39
+ "command": "./hooks/notify-complete.sh",
40
+ "enabled": false
41
+ }
42
+ ]
43
+ },
44
+ "profiles": {
45
+ "development": {
46
+ "description": "Perfil balanceado para desarrollo diario",
47
+ "auto-test-on-edit": true,
48
+ "lint-on-save": true,
49
+ "confirm-destructive": true
50
+ },
51
+ "fast": {
52
+ "description": "Perfil rapido sin verificaciones automaticas",
53
+ "auto-test-on-edit": false,
54
+ "lint-on-save": false,
55
+ "confirm-destructive": false
56
+ },
57
+ "careful": {
58
+ "description": "Perfil estricto con todas las verificaciones",
59
+ "auto-test-on-edit": true,
60
+ "lint-on-save": true,
61
+ "confirm-destructive": true
62
+ },
63
+ "ci": {
64
+ "description": "Perfil para integracion continua",
65
+ "auto-test-on-edit": true,
66
+ "lint-on-save": true,
67
+ "confirm-destructive": false
68
+ }
69
+ },
70
+ "settings": {
71
+ "defaultProfile": "development",
72
+ "logHookExecution": true,
73
+ "continueOnHookFailure": false,
74
+ "parallelHooks": false
75
+ },
76
+ "installation": {
77
+ "instructions": "Copia este archivo a ~/.claude/hooks/ o referencia desde settings.json",
78
+ "settingsPath": "~/.claude/settings.json",
79
+ "elsabroPath": ".planning/hooks/"
80
+ }
81
+ }
@@ -0,0 +1,238 @@
1
+ #!/bin/bash
2
+ # lint-check.sh - ELSABRO Hook: Ejecuta linter automaticamente despues de escribir
3
+ # Uso: Este hook se ejecuta automaticamente despues de Write
4
+ # Soporta: eslint, biome, prettier, ruff, flake8, black, clippy, gofmt
5
+
6
+ set -e
7
+
8
+ # Colores
9
+ RED='\033[0;31m'
10
+ GREEN='\033[0;32m'
11
+ YELLOW='\033[1;33m'
12
+ BLUE='\033[0;34m'
13
+ NC='\033[0m'
14
+
15
+ # Prefijo ELSABRO
16
+ PREFIX="[ELSABRO:hook]"
17
+
18
+ # Detectar linter disponible
19
+ detect_linter() {
20
+ # Node.js / JavaScript / TypeScript
21
+ if [ -f "package.json" ]; then
22
+ # Biome (mas rapido, preferido si disponible)
23
+ if grep -q '"@biomejs/biome"' package.json 2>/dev/null || grep -q '"biome"' package.json 2>/dev/null; then
24
+ echo "biome"
25
+ return
26
+ fi
27
+ # ESLint
28
+ if grep -q '"eslint"' package.json 2>/dev/null; then
29
+ echo "eslint"
30
+ return
31
+ fi
32
+ # Prettier (solo formato, no lint)
33
+ if grep -q '"prettier"' package.json 2>/dev/null; then
34
+ echo "prettier"
35
+ return
36
+ fi
37
+ fi
38
+
39
+ # Biome config file
40
+ if [ -f "biome.json" ] || [ -f "biome.jsonc" ]; then
41
+ echo "biome"
42
+ return
43
+ fi
44
+
45
+ # Python
46
+ if [ -f "pyproject.toml" ]; then
47
+ # Ruff (mas rapido, preferido)
48
+ if grep -q '\[tool.ruff\]' pyproject.toml 2>/dev/null || grep -q 'ruff' pyproject.toml 2>/dev/null; then
49
+ if command -v ruff &>/dev/null; then
50
+ echo "ruff"
51
+ return
52
+ fi
53
+ fi
54
+ # Black (formatter)
55
+ if grep -q '\[tool.black\]' pyproject.toml 2>/dev/null; then
56
+ if command -v black &>/dev/null; then
57
+ echo "black"
58
+ return
59
+ fi
60
+ fi
61
+ # Flake8
62
+ if grep -q 'flake8' pyproject.toml 2>/dev/null; then
63
+ if command -v flake8 &>/dev/null; then
64
+ echo "flake8"
65
+ return
66
+ fi
67
+ fi
68
+ fi
69
+
70
+ # Python setup.cfg
71
+ if [ -f "setup.cfg" ]; then
72
+ if grep -q '\[flake8\]' setup.cfg 2>/dev/null; then
73
+ if command -v flake8 &>/dev/null; then
74
+ echo "flake8"
75
+ return
76
+ fi
77
+ fi
78
+ fi
79
+
80
+ # Ruff config file
81
+ if [ -f "ruff.toml" ] || [ -f ".ruff.toml" ]; then
82
+ if command -v ruff &>/dev/null; then
83
+ echo "ruff"
84
+ return
85
+ fi
86
+ fi
87
+
88
+ # Rust
89
+ if [ -f "Cargo.toml" ]; then
90
+ echo "clippy"
91
+ return
92
+ fi
93
+
94
+ # Go
95
+ if [ -f "go.mod" ]; then
96
+ echo "gofmt"
97
+ return
98
+ fi
99
+
100
+ # No linter detected
101
+ echo ""
102
+ }
103
+
104
+ # Determinar extension del archivo
105
+ get_file_extension() {
106
+ local file="$1"
107
+ echo "${file##*.}"
108
+ }
109
+
110
+ # Verificar si archivo debe ser linteado
111
+ should_lint_file() {
112
+ local file="$1"
113
+ local linter="$2"
114
+ local ext=$(get_file_extension "$file")
115
+
116
+ case "$linter" in
117
+ eslint|biome|prettier)
118
+ [[ "$ext" =~ ^(js|jsx|ts|tsx|mjs|cjs|json)$ ]]
119
+ ;;
120
+ ruff|black|flake8)
121
+ [[ "$ext" == "py" ]]
122
+ ;;
123
+ clippy)
124
+ [[ "$ext" == "rs" ]]
125
+ ;;
126
+ gofmt)
127
+ [[ "$ext" == "go" ]]
128
+ ;;
129
+ *)
130
+ return 0
131
+ ;;
132
+ esac
133
+ }
134
+
135
+ # Ejecutar linter
136
+ run_linter() {
137
+ local linter="$1"
138
+ local file="$2"
139
+
140
+ case "$linter" in
141
+ eslint)
142
+ if [ -n "$file" ] && should_lint_file "$file" "$linter"; then
143
+ echo -e "${BLUE}$PREFIX Running eslint on $file...${NC}"
144
+ npx eslint "$file" --fix 2>/dev/null || true
145
+ else
146
+ echo -e "${BLUE}$PREFIX Running eslint (project)...${NC}"
147
+ npx eslint . --fix --ext .js,.jsx,.ts,.tsx 2>/dev/null || true
148
+ fi
149
+ ;;
150
+ biome)
151
+ if [ -n "$file" ] && should_lint_file "$file" "$linter"; then
152
+ echo -e "${BLUE}$PREFIX Running biome on $file...${NC}"
153
+ npx @biomejs/biome check --write "$file" 2>/dev/null || npx biome check --apply "$file" 2>/dev/null || true
154
+ else
155
+ echo -e "${BLUE}$PREFIX Running biome (project)...${NC}"
156
+ npx @biomejs/biome check --write . 2>/dev/null || npx biome check --apply 2>/dev/null || true
157
+ fi
158
+ ;;
159
+ prettier)
160
+ if [ -n "$file" ] && should_lint_file "$file" "$linter"; then
161
+ echo -e "${BLUE}$PREFIX Running prettier on $file...${NC}"
162
+ npx prettier --write "$file" 2>/dev/null || true
163
+ else
164
+ echo -e "${BLUE}$PREFIX Running prettier (project)...${NC}"
165
+ npx prettier --write . 2>/dev/null || true
166
+ fi
167
+ ;;
168
+ ruff)
169
+ if [ -n "$file" ] && should_lint_file "$file" "$linter"; then
170
+ echo -e "${BLUE}$PREFIX Running ruff on $file...${NC}"
171
+ ruff check --fix "$file" 2>/dev/null || true
172
+ ruff format "$file" 2>/dev/null || true
173
+ else
174
+ echo -e "${BLUE}$PREFIX Running ruff (project)...${NC}"
175
+ ruff check --fix . 2>/dev/null || true
176
+ ruff format . 2>/dev/null || true
177
+ fi
178
+ ;;
179
+ black)
180
+ if [ -n "$file" ] && should_lint_file "$file" "$linter"; then
181
+ echo -e "${BLUE}$PREFIX Running black on $file...${NC}"
182
+ black "$file" 2>/dev/null || true
183
+ else
184
+ echo -e "${BLUE}$PREFIX Running black (project)...${NC}"
185
+ black . 2>/dev/null || true
186
+ fi
187
+ ;;
188
+ flake8)
189
+ if [ -n "$file" ] && should_lint_file "$file" "$linter"; then
190
+ echo -e "${BLUE}$PREFIX Running flake8 on $file...${NC}"
191
+ flake8 "$file" 2>/dev/null
192
+ else
193
+ echo -e "${BLUE}$PREFIX Running flake8 (project)...${NC}"
194
+ flake8 . 2>/dev/null
195
+ fi
196
+ ;;
197
+ clippy)
198
+ echo -e "${BLUE}$PREFIX Running cargo clippy...${NC}"
199
+ cargo clippy --fix --allow-dirty --allow-staged 2>/dev/null || true
200
+ ;;
201
+ gofmt)
202
+ if [ -n "$file" ] && should_lint_file "$file" "$linter"; then
203
+ echo -e "${BLUE}$PREFIX Running gofmt on $file...${NC}"
204
+ gofmt -w "$file" 2>/dev/null || true
205
+ else
206
+ echo -e "${BLUE}$PREFIX Running gofmt (project)...${NC}"
207
+ gofmt -w . 2>/dev/null || true
208
+ fi
209
+ ;;
210
+ *)
211
+ return 0
212
+ ;;
213
+ esac
214
+ }
215
+
216
+ main() {
217
+ local changed_file="${1:-}"
218
+ local linter=$(detect_linter)
219
+
220
+ if [ -z "$linter" ]; then
221
+ echo -e "${YELLOW}$PREFIX No linter detected, skipping lint check${NC}"
222
+ exit 0
223
+ fi
224
+
225
+ echo -e "${YELLOW}$PREFIX Detected linter: $linter${NC}"
226
+
227
+ if run_linter "$linter" "$changed_file"; then
228
+ echo -e "${GREEN}$PREFIX Linting passed${NC}"
229
+ exit 0
230
+ else
231
+ echo -e "${RED}$PREFIX Linting found issues${NC}"
232
+ # No exit 1 para no bloquear el flujo
233
+ # Los linters con --fix ya arreglaron lo que pudieron
234
+ exit 0
235
+ fi
236
+ }
237
+
238
+ main "$@"