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.
- package/agents/elsabro-orchestrator.md +113 -0
- package/commands/elsabro/add-phase.md +17 -0
- package/commands/elsabro/add-todo.md +111 -53
- package/commands/elsabro/audit-milestone.md +19 -0
- package/commands/elsabro/check-todos.md +210 -31
- package/commands/elsabro/complete-milestone.md +20 -1
- package/commands/elsabro/debug.md +19 -0
- package/commands/elsabro/discuss-phase.md +18 -1
- package/commands/elsabro/execute.md +511 -58
- package/commands/elsabro/insert-phase.md +18 -1
- package/commands/elsabro/list-phase-assumptions.md +17 -0
- package/commands/elsabro/new-milestone.md +19 -0
- package/commands/elsabro/new.md +19 -0
- package/commands/elsabro/pause-work.md +19 -0
- package/commands/elsabro/plan-milestone-gaps.md +20 -1
- package/commands/elsabro/plan.md +264 -36
- package/commands/elsabro/progress.md +203 -79
- package/commands/elsabro/quick.md +19 -0
- package/commands/elsabro/remove-phase.md +17 -0
- package/commands/elsabro/research-phase.md +18 -1
- package/commands/elsabro/resume-work.md +19 -0
- package/commands/elsabro/start.md +399 -98
- package/commands/elsabro/verify-work.md +138 -5
- package/hooks/confirm-destructive.sh +145 -0
- package/hooks/hooks-config.json +81 -0
- package/hooks/lint-check.sh +238 -0
- package/hooks/post-edit-test.sh +189 -0
- package/package.json +3 -2
- package/references/SYSTEM_INDEX.md +241 -0
- package/references/command-flow.md +352 -0
- package/references/enforcement-rules.md +331 -0
- package/references/error-contracts-tests.md +1171 -0
- package/references/error-contracts.md +3102 -0
- package/references/error-handling-instructions.md +26 -12
- package/references/parallel-worktrees.md +293 -0
- package/references/state-sync.md +381 -0
- package/references/task-dispatcher.md +388 -0
- package/references/tasks-integration.md +380 -0
- package/scripts/setup-parallel-worktrees.sh +319 -0
- package/skills/api-microservice.md +765 -0
- package/skills/api-setup.md +76 -3
- package/skills/auth-setup.md +46 -6
- package/skills/chrome-extension.md +584 -0
- package/skills/cicd-setup.md +1206 -0
- package/skills/cli-tool.md +884 -0
- package/skills/database-setup.md +41 -5
- package/skills/desktop-app.md +1351 -0
- package/skills/expo-app.md +35 -2
- package/skills/full-stack-app.md +543 -0
- package/skills/memory-update.md +207 -0
- package/skills/mobile-app.md +813 -0
- package/skills/nextjs-app.md +33 -2
- package/skills/payments-setup.md +76 -1
- package/skills/review.md +331 -0
- package/skills/saas-starter.md +639 -0
- package/skills/sentry-setup.md +41 -7
- package/skills/techdebt.md +289 -0
- package/skills/testing-setup.md +1218 -0
- package/skills/tutor.md +219 -0
- package/templates/.planning/notes/.gitkeep +0 -0
- package/templates/CLAUDE.md.template +48 -0
- package/templates/error-handling-config.json +79 -2
- package/templates/mistakes.md.template +52 -0
- 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(
|
|
209
|
-
|
|
210
|
-
|
|
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 "$@"
|