claude-git-hooks 1.2.1 → 1.2.4

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/CHANGELOG.md CHANGED
@@ -5,6 +5,40 @@ Todos los cambios notables en este proyecto se documentarán en este archivo.
5
5
  El formato está basado en [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  y este proyecto adhiere a [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [1.2.4] - 2025-08-22
9
+
10
+ ### Fixed
11
+ - 🐛 Corregido el análisis de SonarQube para mostrar correctamente el formato detallado
12
+ - 📊 Arreglado el parsing de JSON para buscar `QUALITY_GATE` en mayúsculas según las pautas
13
+ - 🔧 Actualizado el mapeo de campos JSON para coincidir con la estructura esperada
14
+
15
+ ### Changed
16
+ - 📈 Añadidas métricas de coverage, duplications y complexity al formato SonarQube
17
+ - 📝 Actualizado el archivo de pautas SonarQube para incluir todas las métricas
18
+
19
+ ## [1.2.3] - 2025-08-22
20
+
21
+ ### Added
22
+ - 🚀 Actualización automática de `.gitignore` durante la instalación
23
+ - 📝 Claude Hooks ahora agrega automáticamente las entradas necesarias a `.gitignore`
24
+ - 🔍 El comando `status` ahora muestra el estado de las entradas en `.gitignore`
25
+
26
+ ### Changed
27
+ - 🎯 Mejorado el proceso de instalación para ser más completo y automatizado
28
+ - 📊 El comando `status` ahora proporciona información más detallada sobre la configuración
29
+
30
+ ## [1.2.2] - 2025-08-22
31
+
32
+ ### Fixed
33
+ - 🐛 Corregido problema donde los archivos markdown de pautas no se instalaban correctamente desde npm
34
+ - 📁 Los archivos de pautas ahora se instalan en el directorio `.claude/` en lugar de la raíz del proyecto
35
+ - 🔧 Actualizado el hook pre-commit para buscar los archivos de pautas en la nueva ubicación `.claude/`
36
+
37
+ ### Changed
38
+ - 📂 Los archivos `CLAUDE_PRE_COMMIT.md` y `CLAUDE_PRE_COMMIT_SONAR.md` ahora se almacenan en `.claude/`
39
+ - 🎯 Mejorada la organización del proyecto manteniendo los archivos de configuración separados del código fuente
40
+ - 📝 Actualizada la documentación para reflejar la nueva estructura de directorios
41
+
8
42
  ## [1.2.1] - 2024-07-24
9
43
 
10
44
  ### Fixed
package/LICENSE CHANGED
File without changes
package/README.md CHANGED
@@ -8,8 +8,8 @@ Este directorio contiene un pre-commit hook que utiliza Claude CLI para revisar
8
8
  - **`pre-commit`** - Hook principal para análisis de código (con auto-actualización)
9
9
  - **`prepare-commit-msg`** - Hook para generar mensajes de commit automáticos
10
10
  - **`.gitattributes`** - Configuración para mantener line endings correctos
11
- - **`CLAUDE_PRE_COMMIT.md`** - Pautas de evaluación formato estándar
12
- - **`CLAUDE_PRE_COMMIT_SONAR.md`** - Pautas de evaluación formato SonarQube
11
+ - **`.claude/CLAUDE_PRE_COMMIT.md`** - Pautas de evaluación formato estándar
12
+ - **`.claude/CLAUDE_PRE_COMMIT_SONAR.md`** - Pautas de evaluación formato SonarQube
13
13
 
14
14
  ## 🔧 Configuración Previa Importante
15
15
 
@@ -69,6 +69,7 @@ El comando `claude-hooks install` ahora incluye:
69
69
  - ✅ Configuración de Git (line endings WSL/Windows)
70
70
  - ✅ Verificación de autenticación Claude con entretenimiento
71
71
  - ✅ Instalación de hooks y archivos de pautas
72
+ - ✅ Actualización automática de .gitignore con archivos de Claude
72
73
 
73
74
  #### Añadir como Dependencia de Desarrollo
74
75
 
@@ -99,6 +100,37 @@ Luego añade esto a tu `package.json`:
99
100
  - `pre-commit`: Análisis de código con Claude (solo archivos Java/config)
100
101
  - `prepare-commit-msg`: Generación automática de mensajes de commit
101
102
 
103
+ ## 📁 Gestión de Archivos
104
+
105
+ ### Archivos creados durante la instalación
106
+
107
+ El comando `claude-hooks install` crea los siguientes archivos y directorios:
108
+
109
+ 1. **`.git/hooks/pre-commit`** - Hook de análisis de código
110
+ 2. **`.git/hooks/prepare-commit-msg`** - Hook de generación de mensajes
111
+ 3. **`.claude/`** - Directorio para archivos de configuración
112
+ - `CLAUDE_PRE_COMMIT.md` - Pautas de evaluación estándar
113
+ - `CLAUDE_PRE_COMMIT_SONAR.md` - Pautas de evaluación SonarQube
114
+ 4. **`.claude-analysis-mode`** - Archivo de preferencia de modo (creado al primer uso)
115
+
116
+ ### Actualización automática de .gitignore
117
+
118
+ Durante la instalación, Claude Hooks actualiza automáticamente tu `.gitignore` para incluir:
119
+
120
+ ```gitignore
121
+ # Claude Git Hooks
122
+ .claude/
123
+ .claude-analysis-mode
124
+ debug-claude-response.json
125
+ ```
126
+
127
+ Esto asegura que:
128
+ - Los archivos de configuración de Claude específicos del proyecto no se suban al repositorio
129
+ - Los archivos de debug temporales se ignoren
130
+ - Cada desarrollador pueda tener sus propias preferencias de análisis
131
+
132
+ Si no existe un `.gitignore`, se creará uno nuevo. Si ya existe, las entradas se agregarán al final solo si no están presentes.
133
+
102
134
  ## 🎯 Funcionamiento
103
135
 
104
136
  ### Hook pre-commit (Análisis de código)
@@ -112,7 +144,7 @@ Luego añade esto a tu `package.json`:
112
144
  - **Estándar**: Formato clásico con score y recomendaciones detalladas
113
145
  - **SonarQube**: Simula salida de SonarQube con Quality Gate, métricas y clasificación de issues
114
146
  4. **Construye prompt inteligente**:
115
- - Lee las pautas desde `CLAUDE_PRE_COMMIT.md` o `CLAUDE_PRE_COMMIT_SONAR.md`
147
+ - Lee las pautas desde `.claude/CLAUDE_PRE_COMMIT.md` o `.claude/CLAUDE_PRE_COMMIT_SONAR.md`
116
148
  - Incluye el diff completo para archivos nuevos
117
149
  - Muestra solo cambios para archivos existentes
118
150
  5. **Envía a Claude CLI para revisión**
@@ -284,8 +316,8 @@ En el archivo `pre-commit`:
284
316
  - **`MAX_FILE_SIZE`**: Tamaño máximo de archivo a analizar (default: 100KB)
285
317
  - **`MAX_FILES`**: Número máximo de archivos por commit (default: 10)
286
318
  - **`CLAUDE_CLI`**: Comando de Claude CLI (default: "claude")
287
- - **`GUIDELINES_FILE`**: Archivo de pautas para modo estándar (default: "CLAUDE_PRE_COMMIT.md")
288
- - **`GUIDELINES_FILE_SONAR`**: Archivo de pautas para modo SonarQube (default: "CLAUDE_PRE_COMMIT_SONAR.md")
319
+ - **`GUIDELINES_FILE`**: Archivo de pautas para modo estándar (default: ".claude/CLAUDE_PRE_COMMIT.md")
320
+ - **`GUIDELINES_FILE_SONAR`**: Archivo de pautas para modo SonarQube (default: ".claude/CLAUDE_PRE_COMMIT_SONAR.md")
289
321
 
290
322
  En el archivo `prepare-commit-msg`:
291
323
 
@@ -351,7 +383,11 @@ Este problema suele ocurrir por conflictos de configuración de line endings:
351
383
 
352
384
  ## 📝 Personalización
353
385
 
354
- Puedes modificar las pautas de evaluación editando `CLAUDE_PRE_COMMIT.md` para adaptarlas a los estándares de tu equipo.
386
+ Puedes modificar las pautas de evaluación editando los archivos en el directorio `.claude/`:
387
+ - `.claude/CLAUDE_PRE_COMMIT.md` - Para el modo estándar
388
+ - `.claude/CLAUDE_PRE_COMMIT_SONAR.md` - Para el modo SonarQube
389
+
390
+ Estos archivos son específicos de tu proyecto y puedes adaptarlos a los estándares de tu equipo.
355
391
 
356
392
  ## 🔄 Arquitectura del Sistema
357
393
 
@@ -394,6 +430,9 @@ claude-git-hooks/
394
430
  │ ├── prepare-commit-msg # Hook de generación de mensajes
395
431
  │ ├── CLAUDE_PRE_COMMIT.md # Pautas estándar
396
432
  │ └── CLAUDE_PRE_COMMIT_SONAR.md # Pautas SonarQube
433
+ ├── .claude/ # Directorio creado en el repo del usuario
434
+ │ ├── CLAUDE_PRE_COMMIT.md # Pautas copiadas aquí durante la instalación
435
+ │ └── CLAUDE_PRE_COMMIT_SONAR.md
397
436
  ├── package.json # Configuración NPM
398
437
  ├── README.md # Este archivo
399
438
  ├── CHANGELOG.md # Historial de versiones
package/bin/claude-hooks CHANGED
@@ -308,14 +308,22 @@ async function install(args) {
308
308
  success(`${hook} instalado`);
309
309
  });
310
310
 
311
- // Copiar archivos de pautas si no existen
311
+ // Crear directorio .claude si no existe
312
+ const claudeDir = '.claude';
313
+ if (!fs.existsSync(claudeDir)) {
314
+ fs.mkdirSync(claudeDir, { recursive: true });
315
+ success('.claude directory created');
316
+ }
317
+
318
+ // Copiar archivos de pautas a .claude si no existen
312
319
  const guidelines = ['CLAUDE_PRE_COMMIT.md', 'CLAUDE_PRE_COMMIT_SONAR.md'];
313
320
  guidelines.forEach(guideline => {
314
- if (!fs.existsSync(guideline)) {
321
+ const destPath = path.join(claudeDir, guideline);
322
+ if (!fs.existsSync(destPath)) {
315
323
  const sourcePath = path.join(templatesPath, guideline);
316
324
  if (fs.existsSync(sourcePath)) {
317
- fs.copyFileSync(sourcePath, guideline);
318
- success(`${guideline} creado`);
325
+ fs.copyFileSync(sourcePath, destPath);
326
+ success(`${guideline} creado en .claude/`);
319
327
  }
320
328
  }
321
329
  });
@@ -323,6 +331,9 @@ async function install(args) {
323
331
  // Configurar Git
324
332
  configureGit();
325
333
 
334
+ // Actualizar .gitignore
335
+ updateGitignore();
336
+
326
337
  success('¡Claude Git Hooks instalado exitosamente! 🎉');
327
338
  console.log('\nUso:');
328
339
  console.log(' git commit -m "auto" # Genera mensaje automáticamente');
@@ -503,6 +514,79 @@ async function checkClaudeAuth() {
503
514
  }
504
515
  }
505
516
 
517
+ // Actualizar .gitignore con las entradas de Claude
518
+ function updateGitignore() {
519
+ info('Actualizando .gitignore...');
520
+
521
+ const gitignorePath = '.gitignore';
522
+ const claudeEntries = [
523
+ '# Claude Git Hooks',
524
+ '.claude/',
525
+ '.claude-analysis-mode',
526
+ 'debug-claude-response.json'
527
+ ];
528
+
529
+ let gitignoreContent = '';
530
+ let fileExists = false;
531
+
532
+ // Leer .gitignore existente si existe
533
+ if (fs.existsSync(gitignorePath)) {
534
+ gitignoreContent = fs.readFileSync(gitignorePath, 'utf8');
535
+ fileExists = true;
536
+ }
537
+
538
+ // Verificar qué entradas faltan
539
+ const missingEntries = [];
540
+ claudeEntries.forEach(entry => {
541
+ if (entry.startsWith('#')) {
542
+ // Para comentarios, verificar si ya existe algún comentario de Claude
543
+ if (!gitignoreContent.includes('# Claude')) {
544
+ missingEntries.push(entry);
545
+ }
546
+ } else {
547
+ // Para entradas normales, verificar si ya están presentes
548
+ const regex = new RegExp(`^${entry.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}$`, 'm');
549
+ if (!regex.test(gitignoreContent)) {
550
+ missingEntries.push(entry);
551
+ }
552
+ }
553
+ });
554
+
555
+ // Si hay entradas faltantes, agregarlas
556
+ if (missingEntries.length > 0) {
557
+ // Asegurar que hay una nueva línea al final si el archivo existe y no está vacío
558
+ if (fileExists && gitignoreContent.length > 0 && !gitignoreContent.endsWith('\n')) {
559
+ gitignoreContent += '\n';
560
+ }
561
+
562
+ // Si el archivo no está vacío, agregar una línea en blanco antes
563
+ if (gitignoreContent.length > 0) {
564
+ gitignoreContent += '\n';
565
+ }
566
+
567
+ // Agregar las entradas faltantes
568
+ gitignoreContent += missingEntries.join('\n') + '\n';
569
+
570
+ // Escribir el archivo actualizado
571
+ fs.writeFileSync(gitignorePath, gitignoreContent);
572
+
573
+ if (fileExists) {
574
+ success('.gitignore actualizado con entradas de Claude');
575
+ } else {
576
+ success('.gitignore creado con entradas de Claude');
577
+ }
578
+
579
+ // Mostrar qué se agregó
580
+ missingEntries.forEach(entry => {
581
+ if (!entry.startsWith('#')) {
582
+ info(` + ${entry}`);
583
+ }
584
+ });
585
+ } else {
586
+ info('.gitignore ya contiene todas las entradas necesarias');
587
+ }
588
+ }
589
+
506
590
  // Configurar Git (line endings, etc.)
507
591
  function configureGit() {
508
592
  info('Configurando Git...');
@@ -631,12 +715,40 @@ function status() {
631
715
  console.log('\nArchivos de pautas:');
632
716
  const guidelines = ['CLAUDE_PRE_COMMIT.md', 'CLAUDE_PRE_COMMIT_SONAR.md'];
633
717
  guidelines.forEach(guideline => {
634
- if (fs.existsSync(guideline)) {
635
- success(`${guideline}: presente`);
718
+ const claudePath = path.join('.claude', guideline);
719
+ if (fs.existsSync(claudePath)) {
720
+ success(`${guideline}: presente en .claude/`);
721
+ } else if (fs.existsSync(guideline)) {
722
+ warning(`${guideline}: presente en raíz (debería estar en .claude/)`);
636
723
  } else {
637
724
  warning(`${guideline}: faltante`);
638
725
  }
639
726
  });
727
+
728
+ // Verificar entradas en .gitignore
729
+ console.log('\n.gitignore:');
730
+ const gitignorePath = '.gitignore';
731
+ if (fs.existsSync(gitignorePath)) {
732
+ const gitignoreContent = fs.readFileSync(gitignorePath, 'utf8');
733
+ const claudeIgnores = ['.claude/', '.claude-analysis-mode', 'debug-claude-response.json'];
734
+ let allPresent = true;
735
+
736
+ claudeIgnores.forEach(entry => {
737
+ const regex = new RegExp(`^${entry.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}$`, 'm');
738
+ if (regex.test(gitignoreContent)) {
739
+ success(`${entry}: incluido`);
740
+ } else {
741
+ warning(`${entry}: faltante`);
742
+ allPresent = false;
743
+ }
744
+ });
745
+
746
+ if (!allPresent) {
747
+ info('\nEjecuta "claude-hooks install" para actualizar .gitignore');
748
+ }
749
+ } else {
750
+ warning('.gitignore no existe');
751
+ }
640
752
  }
641
753
 
642
754
  // Comando set-mode
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-git-hooks",
3
- "version": "1.2.1",
3
+ "version": "1.2.4",
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": {
@@ -44,7 +44,8 @@ Responde ÚNICAMENTE con un JSON válido siguiendo esta estructura:
44
44
  ],
45
45
  "blockingIssues": [
46
46
  "Problema crítico 1 (si existe)"
47
- ]
47
+ ],
48
+ "details": "Información adicional detallada (opcional)"
48
49
  }
49
50
  ```
50
51
 
@@ -23,6 +23,11 @@ Evaluar el código modificado siguiendo métricas similares a SonarQube para ase
23
23
  - Duplicación de código
24
24
  - Deuda técnica
25
25
 
26
+ ### Métricas Adicionales
27
+ - **Coverage**: Porcentaje estimado de cobertura de pruebas (0-100)
28
+ - **Duplications**: Porcentaje estimado de código duplicado (0-100)
29
+ - **Complexity**: Complejidad ciclomática promedio del código
30
+
26
31
  ## Clasificación de Issues
27
32
 
28
33
  ### Severidad
@@ -42,7 +47,10 @@ Responde ÚNICAMENTE con un JSON válido siguiendo esta estructura:
42
47
  "metrics": {
43
48
  "reliability": "A/B/C/D/E",
44
49
  "security": "A/B/C/D/E",
45
- "maintainability": "A/B/C/D/E"
50
+ "maintainability": "A/B/C/D/E",
51
+ "coverage": 75,
52
+ "duplications": 5,
53
+ "complexity": 15
46
54
  },
47
55
  "issues": {
48
56
  "blocker": 0,
@@ -60,7 +68,9 @@ Responde ÚNICAMENTE con un JSON válido siguiendo esta estructura:
60
68
  "line": 42
61
69
  }
62
70
  ],
63
- "securityHotspots": 0
71
+ "securityHotspots": 0,
72
+ "approved": true/false,
73
+ "blockingIssues": ["Lista de problemas bloqueantes si existen"]
64
74
  }
65
75
  ```
66
76
 
@@ -64,10 +64,10 @@ if [ "$ANALYSIS_MODE" != "standard" ] && [ "$ANALYSIS_MODE" != "sonar" ]; then
64
64
 
65
65
  if [ "$REPLY" = "2" ]; then
66
66
  ANALYSIS_MODE="sonar"
67
- GUIDELINES_FILE="CLAUDE_PRE_COMMIT_SONAR.md"
67
+ GUIDELINES_FILE=".claude/CLAUDE_PRE_COMMIT_SONAR.md"
68
68
  else
69
69
  ANALYSIS_MODE="standard"
70
- GUIDELINES_FILE="CLAUDE_PRE_COMMIT.md"
70
+ GUIDELINES_FILE=".claude/CLAUDE_PRE_COMMIT.md"
71
71
  fi
72
72
 
73
73
  # Guardar preferencia para futuros commits
@@ -78,10 +78,10 @@ if [ "$ANALYSIS_MODE" != "standard" ] && [ "$ANALYSIS_MODE" != "sonar" ]; then
78
78
  else
79
79
  # Usar modo guardado
80
80
  if [ "$ANALYSIS_MODE" = "sonar" ]; then
81
- GUIDELINES_FILE="CLAUDE_PRE_COMMIT_SONAR.md"
81
+ GUIDELINES_FILE=".claude/CLAUDE_PRE_COMMIT_SONAR.md"
82
82
  log "Usando modo de análisis: SonarQube"
83
83
  else
84
- GUIDELINES_FILE="CLAUDE_PRE_COMMIT.md"
84
+ GUIDELINES_FILE=".claude/CLAUDE_PRE_COMMIT.md"
85
85
  log "Usando modo de análisis: Estándar"
86
86
  fi
87
87
  fi
@@ -233,7 +233,7 @@ if $CLAUDE_CLI < "$PROMPT_FILE" > "$RESPONSE_FILE" 2>&1; then
233
233
  BLOCKING_ISSUES=$(echo "$JSON_RESPONSE" | jq -r '.blockingIssues[]?' 2>/dev/null | sed '/^$/d')
234
234
 
235
235
  # Verificar si estamos en modo SonarQube
236
- QUALITY_GATE=$(echo "$JSON_RESPONSE" | jq -r '.qualityGate // ""' 2>/dev/null)
236
+ QUALITY_GATE=$(echo "$JSON_RESPONSE" | jq -r '.QUALITY_GATE // ""' 2>/dev/null)
237
237
 
238
238
  if [ "$ANALYSIS_MODE" = "sonar" ] && [ -n "$QUALITY_GATE" ] && [ "$QUALITY_GATE" != "null" ]; then
239
239
  # Mostrar resultados estilo SonarQube
@@ -265,15 +265,15 @@ if $CLAUDE_CLI < "$PROMPT_FILE" > "$RESPONSE_FILE" 2>&1; then
265
265
  fi
266
266
 
267
267
  # Issues Summary
268
- SUMMARY=$(echo "$JSON_RESPONSE" | jq -r '.summary // {}' 2>/dev/null)
269
- if [ "$SUMMARY" != "{}" ] && [ "$SUMMARY" != "null" ]; then
268
+ ISSUES=$(echo "$JSON_RESPONSE" | jq -r '.issues // {}' 2>/dev/null)
269
+ if [ "$ISSUES" != "{}" ] && [ "$ISSUES" != "null" ]; then
270
270
  echo "📋 ISSUES SUMMARY"
271
- TOTAL=$(echo "$SUMMARY" | jq -r '.total // 0' 2>/dev/null)
272
- BLOCKER=$(echo "$SUMMARY" | jq -r '.blocker // 0' 2>/dev/null)
273
- CRITICAL=$(echo "$SUMMARY" | jq -r '.critical // 0' 2>/dev/null)
274
- MAJOR=$(echo "$SUMMARY" | jq -r '.major // 0' 2>/dev/null)
275
- MINOR=$(echo "$SUMMARY" | jq -r '.minor // 0' 2>/dev/null)
276
- INFO=$(echo "$SUMMARY" | jq -r '.info // 0' 2>/dev/null)
271
+ BLOCKER=$(echo "$ISSUES" | jq -r '.blocker // 0' 2>/dev/null)
272
+ CRITICAL=$(echo "$ISSUES" | jq -r '.critical // 0' 2>/dev/null)
273
+ MAJOR=$(echo "$ISSUES" | jq -r '.major // 0' 2>/dev/null)
274
+ MINOR=$(echo "$ISSUES" | jq -r '.minor // 0' 2>/dev/null)
275
+ INFO=$(echo "$ISSUES" | jq -r '.info // 0' 2>/dev/null)
276
+ TOTAL=$((BLOCKER + CRITICAL + MAJOR + MINOR + INFO))
277
277
 
278
278
  echo "Total: $TOTAL issues found"
279
279
  [ "$BLOCKER" -gt 0 ] && echo -e " ${RED}🔴 Blocker: $BLOCKER${NC}"
@@ -285,18 +285,19 @@ if $CLAUDE_CLI < "$PROMPT_FILE" > "$RESPONSE_FILE" 2>&1; then
285
285
  fi
286
286
 
287
287
  # Detailed Issues
288
- ISSUES_COUNT=$(echo "$JSON_RESPONSE" | jq -r '.issues | length' 2>/dev/null)
289
- if [ "$ISSUES_COUNT" -gt 0 ] 2>/dev/null; then
288
+ DETAILS_COUNT=$(echo "$JSON_RESPONSE" | jq -r '.details | length' 2>/dev/null)
289
+ if [ "$DETAILS_COUNT" -gt 0 ] 2>/dev/null; then
290
290
  echo "🔍 DETAILED ISSUES"
291
- echo "$JSON_RESPONSE" | jq -r '.issues[]? |
292
- "[\(.severity)] \(.type) in \(.file):\(.line // "?")\n \(.message)\n Rule: \(.rule // "N/A") | Effort: \(.effort // "?")\n"' 2>/dev/null
291
+ echo "$JSON_RESPONSE" | jq -r '.details[]? |
292
+ "[\(.severity)] \(.type) in \(.file):\(.line // "?")\n \(.message)\n"' 2>/dev/null
293
293
  fi
294
294
 
295
295
  # Security Hotspots
296
- HOTSPOTS_COUNT=$(echo "$JSON_RESPONSE" | jq -r '.hotspots | length' 2>/dev/null)
297
- if [ "$HOTSPOTS_COUNT" -gt 0 ] 2>/dev/null; then
298
- echo "🔥 SECURITY HOTSPOTS"
299
- echo "$JSON_RESPONSE" | jq -r '.hotspots[]? | " • \(.file): \(.message)"' 2>/dev/null
296
+ HOTSPOTS=$(echo "$JSON_RESPONSE" | jq -r '.securityHotspots // 0' 2>/dev/null)
297
+ if [ "$HOTSPOTS" -gt 0 ] 2>/dev/null; then
298
+ echo "🔥 SECURITY HOTSPOTS: $HOTSPOTS found"
299
+ echo " Review security-sensitive code carefully"
300
+
300
301
  echo
301
302
  fi
302
303
 
@@ -332,11 +333,18 @@ if $CLAUDE_CLI < "$PROMPT_FILE" > "$RESPONSE_FILE" 2>&1; then
332
333
  exit 1
333
334
  fi
334
335
 
335
- DETAILS=$(echo "$JSON_RESPONSE" | jq -r '.details // {}')
336
- if [ -n "$DETAILS" ] && [ "$DETAILS" != "{}" ] && [ "$DETAILS" != "null" ]; then
336
+ # Mostrar detalles adicionales si existen
337
+ DETAILS=$(echo "$JSON_RESPONSE" | jq -r '.details // null')
338
+ if [ -n "$DETAILS" ] && [ "$DETAILS" != "null" ]; then
337
339
  echo
338
- echo "=== DETALLES POR CATEGORÍA ==="
339
- echo "$DETAILS" | jq
340
+ echo "=== DETALLES ADICIONALES ==="
341
+ # Si details es un string, imprimirlo directamente
342
+ if echo "$DETAILS" | jq -e 'type == "string"' >/dev/null 2>&1; then
343
+ echo "$DETAILS" | jq -r '.'
344
+ # Si es un objeto o array, formatearlo
345
+ else
346
+ echo "$DETAILS" | jq '.'
347
+ fi
340
348
  fi
341
349
 
342
350
  log "✅ Revisión completada. Commit aprobado (Score: $SCORE/10)"
File without changes