claude-git-hooks 1.5.0 → 1.5.2

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-git-hooks",
3
- "version": "1.5.0",
3
+ "version": "1.5.2",
4
4
  "description": "Git hooks con Claude CLI para análisis de código y generación automática de mensajes de commit",
5
5
  "main": "lib/index.js",
6
6
  "bin": {
@@ -1,23 +1,23 @@
1
1
  #!/bin/bash
2
2
 
3
- # Git Pre-commit Hook para evaluación de código con Claude CLI
3
+ # Git Pre-commit Hook for code evaluation with Claude CLI
4
4
  # Archivo: .git/hooks/pre-commit
5
5
 
6
6
  set -e
7
7
 
8
- # Configuración
8
+ # Configuration
9
9
  CLAUDE_CLI="claude"
10
10
  TEMP_DIR="/tmp/code-review-$$"
11
- MAX_FILE_SIZE=100000 # 100KB máximo por archivo
11
+ MAX_FILE_SIZE=100000 # 100KB maximum per file
12
12
 
13
- # Colores para output
13
+ # Colors for output
14
14
  RED='\033[0;31m'
15
15
  GREEN='\033[0;32m'
16
16
  YELLOW='\033[1;33m'
17
17
  BLUE='\033[0;34m'
18
18
  NC='\033[0m' # No Color
19
19
 
20
- # Función para logging
20
+ # Function for logging
21
21
  log() {
22
22
  echo -e "${GREEN}[PRE-COMMIT]${NC} $1"
23
23
  }
@@ -30,10 +30,10 @@ warning() {
30
30
  echo -e "${YELLOW}[WARNING]${NC} $1"
31
31
  }
32
32
 
33
- # Verificar versión al inicio (antes de cualquier análisis)
34
- # Intentar encontrar el script check-version.sh
33
+ # Check version at start (before any analysis)
34
+ # Try to find the check-version.sh script
35
35
  CHECK_VERSION_SCRIPT=""
36
- # Buscar en múltiples ubicaciones posibles
36
+ # Search in multiple possible locations
37
37
  SCRIPT_PATHS=(
38
38
  "$(dirname "$0")/check-version.sh"
39
39
  "/usr/local/lib/node_modules/claude-git-hooks/templates/check-version.sh"
@@ -49,37 +49,37 @@ for path in "${SCRIPT_PATHS[@]}"; do
49
49
  fi
50
50
  done
51
51
 
52
- # Si encontramos el script, ejecutarlo
52
+ # If we find the script, execute it
53
53
  if [ -n "$CHECK_VERSION_SCRIPT" ]; then
54
- # Source el script para tener acceso a la función
54
+ # Source the script to have access to the function
55
55
  source "$CHECK_VERSION_SCRIPT"
56
56
  check_version
57
57
  fi
58
58
 
59
- # Función para generar prompt de resolución AI-friendly
59
+ # Function to generate AI-friendly resolution prompt
60
60
  generate_resolution_prompt() {
61
61
  local RESOLUTION_FILE="./claude_resolution_prompt.md"
62
62
  local RESOLUTION_TEMPLATE=".claude/CLAUDE_RESOLUTION_PROMPT.md"
63
63
 
64
64
  if [ ! -f "$RESOLUTION_TEMPLATE" ]; then
65
- warning "No se encontró template de resolución: $RESOLUTION_TEMPLATE"
65
+ warning "Resolution template not found: $RESOLUTION_TEMPLATE"
66
66
  return
67
67
  fi
68
68
 
69
- # Obtener información del contexto
69
+ # Get context information
70
70
  local REPO_NAME=$(basename $(git rev-parse --show-toplevel))
71
71
  local BRANCH_NAME=$(git rev-parse --abbrev-ref HEAD)
72
72
  local COMMIT_SHA="pending"
73
73
  local FILE_COUNT=$(echo "$JAVA_FILES" | wc -l)
74
74
 
75
- # Formatear los blocking issues para el prompt de resolución
75
+ # Format the blocking issues for the resolution prompt
76
76
  local ISSUES_FORMATTED=""
77
77
  local issue_num=1
78
78
 
79
- # Usar un archivo temporal para acumular los issues
79
+ # Use a temporary file to accumulate the issues
80
80
  local TEMP_ISSUES=$(mktemp)
81
81
 
82
- # Parsear cada blocking issue como objeto JSON
82
+ # Parse each blocking issue as JSON object
83
83
  echo "$JSON_RESPONSE" | jq -c '.blockingIssues[]?' 2>/dev/null | while IFS= read -r issue; do
84
84
  if [ -n "$issue" ]; then
85
85
  local desc=$(echo "$issue" | jq -r '.description')
@@ -97,32 +97,31 @@ generate_resolution_prompt() {
97
97
  fi
98
98
  done
99
99
 
100
- # Leer el contenido acumulado
100
+ # Read the accumulated content
101
101
  ISSUES_FORMATTED=$(cat "$TEMP_ISSUES")
102
102
  rm -f "$TEMP_ISSUES"
103
103
 
104
- # Generar el prompt desde el template
104
+ # Generate the prompt from the template
105
105
  cp "$RESOLUTION_TEMPLATE" "$RESOLUTION_FILE"
106
106
 
107
- # Reemplazar placeholders - usar comillas dobles y escapar caracteres especiales
107
+ # Replace placeholders - use double quotes and escape special characters
108
108
  sed -i "s|{{REPO_NAME}}|${REPO_NAME}|g" "$RESOLUTION_FILE"
109
109
  sed -i "s|{{BRANCH_NAME}}|${BRANCH_NAME}|g" "$RESOLUTION_FILE"
110
110
  sed -i "s|{{COMMIT_SHA}}|${COMMIT_SHA}|g" "$RESOLUTION_FILE"
111
111
  sed -i "s|{{FILE_COUNT}}|${FILE_COUNT}|g" "$RESOLUTION_FILE"
112
- sed -i "s|{{ANALYSIS_MODE}}|sonar|g" "$RESOLUTION_FILE"
113
112
 
114
- # Crear archivo temporal para issues formateados
113
+ # Create temporary file for formatted issues
115
114
  local TEMP_ISSUES_FILE=$(mktemp)
116
115
  echo "$ISSUES_FORMATTED" > "$TEMP_ISSUES_FILE"
117
116
 
118
- # Reemplazar {{BLOCKING_ISSUES}} con el contenido
117
+ # Replace {{BLOCKING_ISSUES}} with content
119
118
  if [ -n "$ISSUES_FORMATTED" ]; then
120
119
  sed -i "/{{BLOCKING_ISSUES}}/r $TEMP_ISSUES_FILE" "$RESOLUTION_FILE"
121
120
  fi
122
121
  sed -i "s|{{BLOCKING_ISSUES}}||g" "$RESOLUTION_FILE"
123
122
  rm -f "$TEMP_ISSUES_FILE"
124
123
 
125
- # Agregar contenido de archivos afectados
124
+ # Add content from affected files
126
125
  local TEMP_FILES=$(mktemp)
127
126
  echo "$JSON_RESPONSE" | jq -r '.blockingIssues[].file' 2>/dev/null | sort -u | while IFS= read -r file; do
128
127
  if [ -f "$file" ]; then
@@ -135,7 +134,7 @@ generate_resolution_prompt() {
135
134
  fi
136
135
  done
137
136
 
138
- # Reemplazar {{FILE_CONTENTS}} con el contenido
137
+ # Replace {{FILE_CONTENTS}} with content
139
138
  if [ -s "$TEMP_FILES" ]; then
140
139
  sed -i "/{{FILE_CONTENTS}}/r $TEMP_FILES" "$RESOLUTION_FILE"
141
140
  fi
@@ -143,70 +142,62 @@ generate_resolution_prompt() {
143
142
  rm -f "$TEMP_FILES"
144
143
 
145
144
  echo
146
- echo -e "${YELLOW}=== PROMPT DE RESOLUCIÓN AI GENERADO ===${NC}"
147
- echo -e "${GREEN}Se ha generado un prompt AI-friendly en: ${BLUE}$RESOLUTION_FILE${NC}"
148
- echo -e "${YELLOW}Copia este archivo a una nueva instancia de Claude para resolver los problemas automáticamente.${NC}"
145
+ echo -e "${YELLOW}=== AI RESOLUTION PROMPT GENERATED ===${NC}"
146
+ echo -e "${GREEN}An AI-friendly prompt has been generated at: ${BLUE}$RESOLUTION_FILE${NC}"
147
+ echo -e "${YELLOW}Copy this file to a new Claude instance to resolve problems automatically.${NC}"
149
148
  echo
150
149
  }
151
150
 
152
- # Usar siempre modo SonarQube
153
- ANALYSIS_MODE="sonar"
154
-
155
- # Configurar archivos para modo SonarQube
151
+ # Configure files for SonarQube mode
156
152
  GUIDELINES_FILE=".claude/CLAUDE_PRE_COMMIT_SONAR.md"
157
153
  PROMPT_TEMPLATE=".claude/CLAUDE_ANALYSIS_PROMPT_SONAR.md"
158
- log "Usando modo de análisis: SonarQube"
159
154
 
160
- # Guardar preferencia si no existe
161
- if [ ! -f ".claude-analysis-mode" ]; then
162
- echo "sonar" > .claude-analysis-mode
163
- fi
164
155
 
165
- # Verificar que el template de prompt existe
156
+ # Check that the prompt template exists
166
157
  if [ ! -f "$PROMPT_TEMPLATE" ]; then
167
- error "No se encontró el template de prompt: $PROMPT_TEMPLATE"
168
- error "Los archivos de configuración de Claude parecen estar incompletos."
169
- error "Por favor, reinstala claude-git-hooks ejecutando:"
158
+ error "Prompt template not found: $PROMPT_TEMPLATE"
159
+ error "Claude configuration files appear to be incomplete."
160
+ error "Please reinstall claude-git-hooks by running:"
170
161
  error " claude-hooks install --force"
171
162
  exit 1
172
163
  fi
173
- # Función para limpiar archivos temporales
164
+ # Function to clean temporary files
174
165
  cleanup() {
175
166
  rm -rf "$TEMP_DIR"
176
167
  }
177
168
 
178
- # Configurar limpieza al salir
169
+ # Configure cleanup on exit
179
170
  trap cleanup EXIT
180
171
 
181
- # Crear directorio temporal
172
+ # Create temporary directory
182
173
  mkdir -p "$TEMP_DIR"
183
174
 
184
- # Verificar si Claude CLI está instalado (solo para análisis de código)
175
+ # Check if Claude CLI is installed (only for code analysis)
185
176
  if ! command -v "$CLAUDE_CLI" &> /dev/null; then
186
- error "Claude CLI no está instalado o no se encuentra en el PATH"
187
- error "Instala Claude CLI desde: https://github.com/anthropics/claude-cli"
177
+ error "Claude CLI is not installed or not found in PATH"
178
+ error "Install Claude CLI from: https://github.com/anthropics/claude-cli"
188
179
  exit 1
189
180
  fi
190
181
 
191
- # Ahora verificar si hay archivos Java para analizar
182
+ # Now check if there are Java files to analyze
192
183
  JAVA_FILES=$(git diff --cached --name-only --diff-filter=ACM | grep -E '\.(java|xml|properties|yml|yaml)$' || true)
193
184
 
194
185
  if [ -z "$JAVA_FILES" ]; then
195
- log "No hay archivos Java/configuración para revisar"
186
+ log "No Java/configuration files to review"
196
187
  exit 0
197
188
  fi
198
189
 
199
- # Verificar si existe el archivo de pautas
190
+ # Check if the guidelines file exists
200
191
  if [ ! -f "$GUIDELINES_FILE" ]; then
201
- error "No se encontró el archivo de pautas: $GUIDELINES_FILE"
202
- error "Por favor, reinstala claude-git-hooks ejecutando:"
192
+ error "Guidelines file not found: $GUIDELINES_FILE"
193
+ error "Please reinstall claude-git-hooks by running:"
203
194
  error " claude-hooks install --force"
204
195
  exit 1
205
196
  fi
206
197
 
207
- log "Archivos Java/config a revisar: $(echo "$JAVA_FILES" | wc -l)"
198
+ log "Java/config files to review: $(echo "$JAVA_FILES" | wc -l)"
208
199
 
209
- # Función para filtrar contenido con SKIP-ANALYSIS
200
+ # Function to filter content with SKIP-ANALYSIS
210
201
  filter_skip_analysis() {
211
202
  local file_content="$1"
212
203
  local filtered_content=""
@@ -214,73 +205,77 @@ filter_skip_analysis() {
214
205
  local inside_skip_block=false
215
206
 
216
207
  while IFS= read -r line; do
217
- # Detectar inicio de bloque SKIP-ANALYSIS
208
+ # Detect SKIP-ANALYSIS for single line
218
209
  if echo "$line" | grep -q "// SKIP-ANALYSIS"; then
210
+ skip_next_line=true
211
+ continue
212
+ fi
213
+
214
+ # Detect start/end of SKIP_ANALYSIS_BLOCK
215
+ if echo "$line" | grep -q "// SKIP_ANALYSIS_BLOCK"; then
219
216
  if [ "$inside_skip_block" = true ]; then
220
- # Fin del bloque
217
+ # End of block
221
218
  inside_skip_block=false
222
219
  else
223
- # Inicio del bloque o línea única
220
+ # Start of block
224
221
  inside_skip_block=true
225
- skip_next_line=true
226
222
  fi
227
223
  continue
228
224
  fi
229
225
 
230
- # Si estamos dentro de un bloque, saltar la línea
226
+ # If we're inside a block, skip the line
231
227
  if [ "$inside_skip_block" = true ]; then
232
228
  continue
233
229
  fi
234
230
 
235
- # Si debemos saltar la siguiente línea (comentario único)
231
+ # If we should skip the next line (single comment)
236
232
  if [ "$skip_next_line" = true ]; then
237
233
  skip_next_line=false
238
- inside_skip_block=false
239
234
  continue
240
235
  fi
241
236
 
242
- # Agregar línea al contenido filtrado
237
+ # Add line to filtered content
243
238
  filtered_content="${filtered_content}${line}"$'\n'
244
239
  done <<< "$file_content"
245
240
 
246
241
  echo "$filtered_content"
247
242
  }
248
243
 
249
- # Construir el prompt para análisis de código
244
+ # Build the prompt for code analysis
250
245
  PROMPT_FILE="$TEMP_DIR/code_review_prompt.txt"
251
246
 
252
- # Copiar el template de prompt
247
+ # Copy the prompt template
253
248
  cat "$PROMPT_TEMPLATE" > "$PROMPT_FILE"
254
249
 
255
- # Agregar las pautas
256
- echo "=== PAUTAS DE EVALUACIÓN ===" >> "$PROMPT_FILE"
250
+ # Add the guidelines
251
+ echo "=== EVALUATION GUIDELINES ===" >> "$PROMPT_FILE"
257
252
  cat "$GUIDELINES_FILE" >> "$PROMPT_FILE"
258
- echo -e "\n\n=== CAMBIOS A REVISAR ===\n" >> "$PROMPT_FILE"
253
+ echo -e "\n\n=== CHANGES TO REVIEW ===\n" >> "$PROMPT_FILE"
259
254
 
260
- # Procesar cada archivo Java
255
+ # Process each Java file
261
256
  FILE_COUNT=0
262
257
  for FILE in $JAVA_FILES; do
263
258
  if [ -f "$FILE" ]; then
264
259
  FILE_SIZE=$(stat -c%s "$FILE" 2>/dev/null || stat -f%z "$FILE" 2>/dev/null || echo "0")
265
260
 
266
261
  if [ "$FILE_SIZE" -gt "$MAX_FILE_SIZE" ]; then
267
- warning "Archivo $FILE demasiado grande ($FILE_SIZE bytes), saltando..."
262
+ warning "File $FILE too large ($FILE_SIZE bytes), skipping..."
268
263
  continue
269
264
  fi
270
265
 
271
266
  echo -e "\n--- Archivo: $FILE ---" >> "$PROMPT_FILE"
272
267
 
273
- # Obtener el diff y filtrarlo
274
- DIFF_CONTENT=$(git diff --cached "$FILE" 2>/dev/null || echo "No se pudo obtener diff")
268
+ # Get the diff and filter it
269
+ DIFF_CONTENT=$(git diff --cached "$FILE" 2>/dev/null || echo "Could not get diff")
275
270
  FILTERED_DIFF=$(filter_skip_analysis "$DIFF_CONTENT")
276
271
 
277
- # Mostrar el diff filtrado del archivo
272
+ # Show the filtered diff of the file
278
273
  echo -e "\nDiff:" >> "$PROMPT_FILE"
279
274
  echo "$FILTERED_DIFF" >> "$PROMPT_FILE"
280
275
 
281
- # Si es un archivo nuevo, mostrar contenido completo filtrado
276
+ # If it's a new file, show complete filtered content
282
277
  if git diff --cached --name-status | grep "^A.*$FILE" > /dev/null; then
283
- echo -e "\nContenido completo (archivo nuevo):" >> "$PROMPT_FILE"
278
+ echo -e "\nComplete content (new file):" >> "$PROMPT_FILE"
284
279
  FILE_CONTENT=$(git show ":$FILE" 2>/dev/null || cat "$FILE")
285
280
  FILTERED_CONTENT=$(filter_skip_analysis "$FILE_CONTENT")
286
281
  echo "$FILTERED_CONTENT" >> "$PROMPT_FILE"
@@ -291,45 +286,45 @@ for FILE in $JAVA_FILES; do
291
286
  done
292
287
 
293
288
  if [ "$FILE_COUNT" -eq 0 ]; then
294
- log "No se encontraron archivos válidos para revisar"
289
+ log "No valid files found to review"
295
290
  exit 0
296
291
  fi
297
292
 
298
293
  if [ "$FILE_COUNT" -gt 10 ]; then
299
- warning "Demasiados archivos para revisar ($FILE_COUNT)"
300
- warning "Considera dividir el commit en partes más pequeñas"
294
+ warning "Too many files to review ($FILE_COUNT)"
295
+ warning "Consider splitting the commit into smaller parts"
301
296
  exit 0
302
297
  fi
303
298
 
304
- log "Enviando $FILE_COUNT archivos para revisión con Claude..."
299
+ log "Sending $FILE_COUNT files for review with Claude..."
305
300
 
306
- # Enviar a Claude y capturar respuesta
301
+ # Send to Claude and capture response
307
302
  RESPONSE_FILE="$TEMP_DIR/code_review_response.txt"
308
303
 
309
- # Ejecutar Claude CLI y capturar la respuesta
304
+ # Execute Claude CLI and capture the response
310
305
  if $CLAUDE_CLI < "$PROMPT_FILE" > "$RESPONSE_FILE" 2>&1; then
311
- # Extraer el JSON de la respuesta
306
+ # Extract the JSON from the response
312
307
  JSON_RESPONSE=$(sed -n '/^{/,/^}/p' "$RESPONSE_FILE" | head -n 1000)
313
308
 
314
309
  if [ -z "$JSON_RESPONSE" ]; then
315
- error "No se recibió una respuesta JSON válida de Claude"
316
- error "Respuesta completa:"
310
+ error "Did not receive a valid JSON response from Claude"
311
+ error "Complete response:"
317
312
  cat "$RESPONSE_FILE"
318
313
  exit 1
319
314
  fi
320
315
 
321
- # Guardar JSON para debug si está activado
316
+ # Save JSON for debug if activated
322
317
  if [ -n "$DEBUG" ]; then
323
318
  echo "$JSON_RESPONSE" > ./debug-claude-response.json
324
- log "Respuesta guardada en debug-claude-response.json"
319
+ log "Response saved to debug-claude-response.json"
325
320
  fi
326
321
 
327
- # Parsear la respuesta usando jq
322
+ # Parse the response using jq
328
323
  APPROVED=$(echo "$JSON_RESPONSE" | jq -r '.approved // false')
329
324
  SCORE=$(echo "$JSON_RESPONSE" | jq -r '.score // 0')
330
325
  RECOMMENDATIONS=$(echo "$JSON_RESPONSE" | jq -r '.recommendations[]?' 2>/dev/null | sed '/^$/d')
331
326
 
332
- # Parsear blockingIssues como objetos y extraer las descripciones
327
+ # Parse blockingIssues as objects and extract descriptions
333
328
  BLOCKING_ISSUES=""
334
329
  BLOCKING_COUNT=$(echo "$JSON_RESPONSE" | jq '.blockingIssues | length' 2>/dev/null || echo "0")
335
330
 
@@ -337,11 +332,10 @@ if $CLAUDE_CLI < "$PROMPT_FILE" > "$RESPONSE_FILE" 2>&1; then
337
332
  BLOCKING_ISSUES=$(echo "$JSON_RESPONSE" | jq -r '.blockingIssues[].description' 2>/dev/null | sed '/^$/d')
338
333
  fi
339
334
 
340
- # Verificar si estamos en modo SonarQube
341
335
  QUALITY_GATE=$(echo "$JSON_RESPONSE" | jq -r '.QUALITY_GATE // ""' 2>/dev/null)
342
336
 
343
- if [ "$ANALYSIS_MODE" = "sonar" ] && [ -n "$QUALITY_GATE" ] && [ "$QUALITY_GATE" != "null" ]; then
344
- # Mostrar resultados estilo SonarQube
337
+ if [ -n "$QUALITY_GATE" ] && [ "$QUALITY_GATE" != "null" ]; then
338
+ # Show SonarQube style results
345
339
  echo
346
340
  echo "╔════════════════════════════════════════════════════════════════════╗"
347
341
  echo "║ CODE QUALITY ANALYSIS ║"
@@ -416,51 +410,51 @@ if $CLAUDE_CLI < "$PROMPT_FILE" > "$RESPONSE_FILE" 2>&1; then
416
410
  echo
417
411
  log "✅ Code analysis completed. Quality gate passed."
418
412
  else
419
- # Mostrar resultados en formato clásico
413
+ # Show results in classic format
420
414
  echo
421
- echo "=== RESULTADO DE LA REVISIÓN ==="
415
+ echo "=== REVIEW RESULTS ==="
422
416
  echo "Score: $SCORE/10"
423
417
 
424
418
  if [ -n "$RECOMMENDATIONS" ] && [ "$RECOMMENDATIONS" != "null" ]; then
425
419
  echo
426
- echo "=== RECOMENDACIONES ==="
420
+ echo "=== RECOMMENDATIONS ==="
427
421
  echo "$RECOMMENDATIONS" | sed 's/^/- /'
428
422
  fi
429
423
 
430
- # Verificar si el commit debe ser bloqueado
424
+ # Check if the commit should be blocked
431
425
  if [ "$APPROVED" = "false" ]; then
432
- error "❌ Commit rechazado por problemas críticos"
426
+ error "❌ Commit rejected due to critical issues"
433
427
  if [ -n "$BLOCKING_ISSUES" ] && [ "$BLOCKING_ISSUES" != "null" ]; then
434
428
  echo
435
- echo "=== PROBLEMAS CRÍTICOS ==="
429
+ echo "=== CRITICAL ISSUES ==="
436
430
  echo "$BLOCKING_ISSUES" | sed 's/^/- /'
437
431
 
438
- # Generar prompt de resolución AI-friendly
432
+ # Generate AI-friendly resolution prompt
439
433
  generate_resolution_prompt
440
434
  fi
441
435
  exit 1
442
436
  fi
443
437
 
444
- # Mostrar detalles adicionales si existen
438
+ # Show additional details if they exist
445
439
  DETAILS=$(echo "$JSON_RESPONSE" | jq -r '.details // null')
446
440
  if [ -n "$DETAILS" ] && [ "$DETAILS" != "null" ]; then
447
441
  echo
448
- echo "=== DETALLES ADICIONALES ==="
449
- # Si details es un string, imprimirlo directamente
442
+ echo "=== ADDITIONAL DETAILS ==="
443
+ # If details is a string, print it directly
450
444
  if echo "$DETAILS" | jq -e 'type == "string"' >/dev/null 2>&1; then
451
445
  echo "$DETAILS" | jq -r '.'
452
- # Si es un objeto o array, formatearlo
446
+ # If it's an object or array, format it
453
447
  else
454
448
  echo "$DETAILS" | jq '.'
455
449
  fi
456
450
  fi
457
451
 
458
- log "✅ Revisión completada. Commit aprobado (Score: $SCORE/10)"
452
+ log "✅ Review completed. Commit approved (Score: $SCORE/10)"
459
453
  fi
460
454
 
461
455
  else
462
- error "Error al ejecutar Claude CLI"
463
- error "Verifica que Claude CLI esté configurado correctamente"
456
+ error "Error executing Claude CLI"
457
+ error "Check that Claude CLI is configured correctly"
464
458
  cat "$RESPONSE_FILE"
465
459
  exit 1
466
460
  fi
@@ -1,23 +1,23 @@
1
1
  #!/bin/bash
2
2
 
3
- # Git Prepare-commit-msg Hook para generar mensajes automáticos con Claude
3
+ # Git Prepare-commit-msg Hook to generate automatic messages with Claude
4
4
  # Archivo: .git/hooks/prepare-commit-msg
5
5
 
6
6
  set -e
7
7
 
8
- # Configuración
8
+ # Configuration
9
9
  CLAUDE_CLI="claude"
10
10
  TEMP_DIR="/tmp/commit-msg-$$"
11
11
  MAX_FILE_SIZE=100000
12
12
  AUTO_COMMIT_ENABLED=true
13
13
 
14
- # Colores para output
14
+ # Colors for output
15
15
  RED='\033[0;31m'
16
16
  GREEN='\033[0;32m'
17
17
  YELLOW='\033[1;33m'
18
18
  NC='\033[0m'
19
19
 
20
- # Función para logging
20
+ # Function for logging
21
21
  log() {
22
22
  printf "${GREEN}[PREPARE-MSG]${NC} %s\n" "$1" >&2
23
23
  }
@@ -26,35 +26,35 @@ warning() {
26
26
  printf "${YELLOW}[WARNING]${NC} %s\n" "$1" >&2
27
27
  }
28
28
 
29
- # Función para limpiar archivos temporales
29
+ # Function to clean temporary files
30
30
  cleanup() {
31
31
  rm -rf "$TEMP_DIR"
32
32
  }
33
33
  trap cleanup EXIT
34
34
 
35
- # Argumentos del hook
35
+ # Hook arguments
36
36
  COMMIT_MSG_FILE="$1"
37
37
  COMMIT_SOURCE="$2"
38
38
 
39
- # Solo procesar si es un commit normal
39
+ # Only process if it's a normal commit
40
40
  if [ "$COMMIT_SOURCE" != "" ] && [ "$COMMIT_SOURCE" != "message" ]; then
41
41
  exit 0
42
42
  fi
43
43
 
44
- # Leer el mensaje actual
44
+ # Read the current message
45
45
  CURRENT_MSG=$(head -n 1 "$COMMIT_MSG_FILE" 2>/dev/null || echo "")
46
46
 
47
- # Verificar si necesitamos generar mensaje
47
+ # Check if we need to generate a message
48
48
  if [ "$CURRENT_MSG" = "auto" ]; then
49
- log "Intentando generar mensaje..."
49
+ log "Trying to generate message..."
50
50
  else
51
51
  exit 0
52
52
  fi
53
53
 
54
- # Verificar si Claude CLI está instalado
54
+ # Check if Claude CLI is installed
55
55
  if ! command -v "$CLAUDE_CLI" &> /dev/null; then
56
- warning "Claude CLI no está instalado"
57
- warning "Commit cancelado. Ejecuta nuevamente sin 'auto' para escribir mensaje manual"
56
+ warning "Claude CLI is not installed"
57
+ warning "Commit canceled. Run again without 'auto' to write manual message"
58
58
  exit 1
59
59
  fi
60
60
 
@@ -62,49 +62,49 @@ mkdir -p "$TEMP_DIR"
62
62
  PROMPT_FILE="$TEMP_DIR/commit_msg_prompt.txt"
63
63
 
64
64
  cat > "$PROMPT_FILE" << 'EOF'
65
- Analiza los siguientes cambios y genera un mensaje de commit siguiendo el formato Conventional Commits.
65
+ Analyze the following changes and generate a commit message following the Conventional Commits format.
66
66
 
67
- Responde SOLO con un JSON válido:
67
+ Respond ONLY with a valid JSON:
68
68
 
69
69
  {
70
70
  "type": "feat|fix|docs|style|refactor|test|chore|ci|perf",
71
- "scope": "alcance opcional (ej: api, frontend, db)",
72
- "title": "descripción corta en presente (max 50 chars)",
73
- "body": "descripción detallada opcional"
71
+ "scope": "optional scope (e.g.: api, frontend, db)",
72
+ "title": "short description in present tense (max 50 chars)",
73
+ "body": "optional detailed description"
74
74
  }
75
75
 
76
- CAMBIOS A ANALIZAR:
76
+ CHANGES TO ANALYZE:
77
77
  EOF
78
78
 
79
- # Obtener archivos staged
79
+ # Get staged files
80
80
  ALL_STAGED_FILES=$(git diff --cached --name-only --diff-filter=ACM 2>/dev/null || echo "")
81
81
 
82
82
  if [ -z "$ALL_STAGED_FILES" ]; then
83
- warning "No hay archivos staged"
84
- warning "Commit cancelado. Ejecuta nuevamente sin 'auto' para escribir mensaje manual"
83
+ warning "No staged files"
84
+ warning "Commit canceled. Run again without 'auto' to write manual message"
85
85
  exit 1
86
86
  fi
87
87
 
88
- printf "\nArchivos modificados:\n" >> "$PROMPT_FILE"
88
+ printf "\nModified files:\n" >> "$PROMPT_FILE"
89
89
  echo "$ALL_STAGED_FILES" >> "$PROMPT_FILE"
90
90
 
91
- printf "\nResumen de cambios:\n" >> "$PROMPT_FILE"
92
- git diff --cached --stat >> "$PROMPT_FILE" 2>/dev/null || echo "No se pudo obtener estadísticas"
91
+ printf "\nSummary of changes:\n" >> "$PROMPT_FILE"
92
+ git diff --cached --stat >> "$PROMPT_FILE" 2>/dev/null || echo "Could not get statistics"
93
93
 
94
- # Mostrar diffs de archivos pequeños
94
+ # Show diffs of small files
95
95
  for FILE in $ALL_STAGED_FILES; do
96
96
  if [ -f "$FILE" ]; then
97
97
  FILE_SIZE=$(stat -c%s "$FILE" 2>/dev/null || stat -f%z "$FILE" 2>/dev/null || echo "0")
98
98
 
99
99
  if [ "$FILE_SIZE" -lt "$MAX_FILE_SIZE" ]; then
100
- printf "\n--- Diff de %s ---\n" "$FILE" >> "$PROMPT_FILE"
101
- git diff --cached "$FILE" >> "$PROMPT_FILE" 2>/dev/null || echo "No se pudo obtener diff"
100
+ printf "\n--- Diff of %s ---\n" "$FILE" >> "$PROMPT_FILE"
101
+ git diff --cached "$FILE" >> "$PROMPT_FILE" 2>/dev/null || echo "Could not get diff"
102
102
  fi
103
103
  fi
104
104
  done
105
105
 
106
106
  RESPONSE_FILE="$TEMP_DIR/commit_msg_response.txt"
107
- log "Generando mensaje de commit con Claude..."
107
+ log "Generating commit message with Claude..."
108
108
 
109
109
  if $CLAUDE_CLI < "$PROMPT_FILE" > "$RESPONSE_FILE" 2>&1; then
110
110
  JSON_MSG=$(sed -n '/^{/,/^}/p' "$RESPONSE_FILE" | head -n 1000)
@@ -127,12 +127,12 @@ if $CLAUDE_CLI < "$PROMPT_FILE" > "$RESPONSE_FILE" 2>&1; then
127
127
  fi
128
128
 
129
129
  printf "%s\n" "$FULL_MESSAGE" > "$COMMIT_MSG_FILE"
130
- log "📝 Mensaje generado: $(echo "$FULL_MESSAGE" | head -n 1)"
130
+ log "📝 Message generated: $(echo "$FULL_MESSAGE" | head -n 1)"
131
131
  exit 0
132
132
  fi
133
133
  fi
134
134
  fi
135
135
 
136
- warning "No se pudo generar el mensaje automáticamente con Claude"
137
- warning "Commit cancelado. Ejecuta nuevamente sin 'auto' para escribir mensaje manual"
136
+ warning "Could not generate message automatically with Claude"
137
+ warning "Commit canceled. Run again without 'auto' to write manual message"
138
138
  exit 1