Initial commit

This commit is contained in:
Zhongwei Li
2025-11-29 17:59:01 +08:00
commit dbe64cbfbb
8 changed files with 568 additions and 0 deletions

View File

@@ -0,0 +1,159 @@
---
name: elegant-objects
description: >
Vérifie la conformité du code PHP aux principes Elegant Objects de Yegor Bugayenko.
Analyse un fichier spécifique ou tous les fichiers modifiés dans la branche.
allowed-tools: [Bash, Read, Grep, Glob]
model: sonnet
---
# Elegant Objects Reviewer Skill
## Variables
```bash
TARGET="$ARGUMENTS" # Fichier spécifique ou vide pour fichiers modifiés
```
## Workflow
### Étape 1: Déterminer les fichiers à analyser
```bash
if [ -n "$TARGET" ] && [ -f "$TARGET" ]; then
# Fichier spécifique fourni
FILES_TO_ANALYZE="$TARGET"
echo "📁 Analyse du fichier: $TARGET"
else
# Fichiers PHP modifiés dans la branche
BASE_BRANCH=$(git rev-parse --abbrev-ref HEAD@{upstream} 2>/dev/null || echo "main")
FILES_TO_ANALYZE=$(git diff --name-only "$BASE_BRANCH"...HEAD -- '*.php' 2>/dev/null || git diff --name-only HEAD -- '*.php')
if [ -z "$FILES_TO_ANALYZE" ]; then
echo "⚠️ Aucun fichier PHP modifié détecté"
exit 0
fi
echo "📁 Fichiers PHP modifiés dans la branche:"
echo "$FILES_TO_ANALYZE" | while read f; do echo " - $f"; done
fi
```
### Étape 2: Analyser chaque fichier
Pour chaque fichier PHP, vérifier les règles Elegant Objects.
#### Règles de conception des classes
1. **Classes final** - Toutes les classes doivent être `final` (sauf abstraites)
2. **Attributs max 4** - Chaque classe encapsule 1 à 4 attributs maximum
3. **Pas de getters** - Éviter les méthodes `getX()` (modèle anémique)
4. **Pas de setters** - Éviter les méthodes `setX()` (mutabilité)
5. **Pas de méthodes statiques** - Strictement interdites dans les classes
6. **Pas de classes utilitaires** - Classes avec uniquement des méthodes statiques interdites
7. **Noms sans -er** - Noms de classes ne finissant pas par -er (Manager, Handler, Helper...)
8. **Constructeur unique** - Un seul constructeur principal par classe
9. **Constructeurs simples** - Ne contiennent que des affectations
#### Règles de méthodes
1. **Pas de retour null** - Les méthodes ne doivent jamais retourner `null`
2. **Pas d'argument null** - `null` ne doit pas être passé en argument
3. **Corps sans lignes vides** - Les corps de méthodes sans lignes vides
4. **Corps sans commentaires** - Les corps de méthodes sans commentaires inline
5. **Noms verbes simples** - Noms de méthodes sont des verbes simples (pas composés)
6. **CQRS** - Séparation commandes (void) et queries (retour valeur)
#### Règles de style
1. **Messages sans point final** - Messages d'erreur/log sans point final
2. **Messages une phrase** - Messages d'erreur/log en une seule phrase
3. **Fail fast** - Exceptions lancées au plus tôt
#### Règles de tests
1. **Une assertion par test** - Chaque test ne contient qu'une assertion
2. **Assertion dernière** - L'assertion est la dernière instruction
3. **Pas de setUp/tearDown** - Ne pas utiliser ces méthodes
4. **Noms français** - Noms de tests en français décrivant le comportement
5. **Messages négatifs** - Assertions avec messages d'échec négatifs
6. **Pas de constantes partagées** - Pas de littéraux statiques partagés
### Étape 3: Générer le rapport
Format du rapport:
```
## Score de conformité Elegant Objects
Score global: X/100
## Violations critiques (bloquantes)
### [Règle violée]
- **Fichier:** /chemin/fichier.php:ligne
- **Problème:** Description précise
- **Suggestion:** Code corrigé ou approche
## Violations majeures (à corriger)
[Même format]
## Recommandations (améliorations)
[Même format]
## Statistiques
- Fichiers analysés: X
- Classes analysées: Y
- Méthodes analysées: Z
- Tests analysés: W
- Total violations: N
## Prochaines étapes
Liste priorisée des corrections à effectuer
```
## Calcul du score
- Violation critique: -10 points
- Violation majeure: -5 points
- Recommandation: -2 points
- Score de base: 100
## Patterns à détecter (regex)
```php
# Classes non-final
/^class\s+\w+/ # sans 'final' avant
# Getters
/public\s+function\s+get[A-Z]\w*\s*\(/
# Setters
/public\s+function\s+set[A-Z]\w*\s*\(/
# Méthodes statiques
/public\s+static\s+function/
# Noms en -er
/class\s+\w+(er|or|Manager|Handler|Helper|Builder|Factory|Provider|Controller|Processor)\b/
# Retour null
/return\s+null\s*;/
# Lignes vides dans méthodes
/\{\s*\n\s*\n/ # ouverture suivie de ligne vide
# Commentaires dans corps
/^\s+\/\// # à l'intérieur des méthodes
```
## Notes
- Ignorer fichiers vendor/, var/, cache/
- Contexte framework Symfony considéré (Controllers tolérés)
- Prioriser violations par criticité
- Proposer code corrigé quand possible

View File

@@ -0,0 +1,69 @@
# PHPStan Error Resolver Skill
Résout automatiquement les erreurs PHPStan en boucle jusqu'à zéro erreur ou stagnation.
## Fonctionnalités
- Détection automatique des erreurs PHPStan
- Groupement des erreurs par fichier
- Résolution par batch (5 erreurs max par fichier par itération)
- Boucle de résolution avec vérification après chaque correction
- Détection de stagnation (erreurs qui ne diminuent plus)
- Rapport détaillé avec taux de succès
## Usage
Via la commande délégante :
```bash
/qa:phpstan
```
Ou directement via le skill :
```bash
# Utiliser l'outil Task avec le skill phpstan-resolver
```
## Workflow
1. Analyse PHPStan initiale
2. Groupement erreurs par fichier
3. Pour chaque fichier avec erreurs :
- Batch de 5 erreurs max
- Délégation à agent `@phpstan-error-resolver`
- Correction via Edit tool
4. Re-exécution PHPStan pour vérification
5. Répétition jusqu'à :
- Zéro erreur (succès total)
- Stagnation (erreurs ne diminuent plus)
- Max itérations (10)
## Configuration
- `ERROR_BATCH_SIZE`: 5 erreurs par fichier par itération
- `MAX_ITERATIONS`: 10 itérations maximum
- `PHPSTAN_CONFIG`: phpstan.neon ou phpstan.neon.dist
## Dépendances
- PHPStan installé (`./vendor/bin/phpstan`)
- Configuration PHPStan valide
- Agent `@phpstan-error-resolver` disponible
- `jq` pour parsing JSON
## Rapport généré
```yaml
details:
total_errors_initial: [nombre]
total_errors_final: [nombre]
errors_fixed: [nombre]
success_rate: "[%]"
iterations: [nombre]
```
## Notes
- Utilise format JSON de PHPStan pour parsing précis
- Évite boucles infinies avec max itérations
- Détecte stagnation automatiquement
- Rapport détaillé même en cas d'échec partiel

View File

@@ -0,0 +1,250 @@
---
name: phpstan-resolver
description: >
Résout automatiquement les erreurs PHPStan détectées dans le projet en analysant
et corrigeant les problèmes de types stricts, annotations generics, array shapes
et collections Doctrine. Boucle jusqu'à zéro erreur ou stagnation.
allowed-tools: [Task, Bash, Read, Edit, Grep, Glob, TodoWrite]
model: claude-opus-4-1-20250805
---
# PHPStan Error Resolver Skill
## Variables
```bash
PHPSTAN_CONFIG="phpstan.neon" # ou phpstan.neon.dist
PHPSTAN_BIN="./vendor/bin/phpstan"
ERROR_BATCH_SIZE=5
MAX_ITERATIONS=10
```
## Workflow
### Étape 0: Timing
```bash
START_TIME=$(date +%s)
date
```
### Étape 1: Vérification Environnement
```bash
# Vérifier PHPStan installé
if [ ! -f "$PHPSTAN_BIN" ]; then
echo "❌ PHPStan non trouvé: $PHPSTAN_BIN"
exit 1
fi
# Vérifier config PHPStan
if [ ! -f "$PHPSTAN_CONFIG" ] && [ ! -f "phpstan.neon.dist" ]; then
echo "❌ Configuration PHPStan introuvable"
exit 1
fi
# Utiliser phpstan.neon.dist si phpstan.neon absent
if [ ! -f "$PHPSTAN_CONFIG" ]; then
PHPSTAN_CONFIG="phpstan.neon.dist"
fi
echo "✅ Environnement PHPStan valide"
echo " Config: $PHPSTAN_CONFIG"
```
### Étape 2: Exécution Initiale PHPStan
```bash
echo "🔍 Analyse PHPStan initiale..."
# Exécuter PHPStan
$PHPSTAN_BIN analyze --no-progress --error-format=json > /tmp/phpstan_initial.json
# Parser résultat
TOTAL_ERRORS_INITIAL=$(jq '.totals.file_errors' /tmp/phpstan_initial.json)
if [ "$TOTAL_ERRORS_INITIAL" -eq 0 ]; then
echo "✅ Aucune erreur PHPStan détectée"
exit 0
fi
echo "📊 Erreurs détectées: $TOTAL_ERRORS_INITIAL"
```
### Étape 3: TodoWrite Initialisation
```yaml
todos:
- content: "Analyser erreurs PHPStan"
status: "completed"
activeForm: "Analyse des erreurs PHPStan"
- content: "Grouper erreurs par fichier"
status: "pending"
activeForm: "Groupement des erreurs par fichier"
- content: "Résoudre erreurs (itération 1)"
status: "pending"
activeForm: "Résolution des erreurs (itération 1)"
- content: "Vérifier résolution"
status: "pending"
activeForm: "Vérification de la résolution"
```
### Étape 4: Groupement Erreurs par Fichier
Marquer todo #2 `in_progress`.
```bash
# Parser JSON et grouper par fichier
jq -r '.files | to_entries[] | "\(.key)|\(.value.messages | length)"' /tmp/phpstan_initial.json > /tmp/phpstan_files.txt
# Afficher groupement
echo "📁 Erreurs par fichier:"
cat /tmp/phpstan_files.txt | while IFS='|' read file count; do
echo " - $file: $count erreurs"
done
```
Marquer todo #2 `completed`.
### Étape 5: Boucle de Résolution
Marquer todo #3 `in_progress`.
```bash
ITERATION=1
ERRORS_CURRENT=$TOTAL_ERRORS_INITIAL
ERRORS_PREVIOUS=0
while [ $ITERATION -le $MAX_ITERATIONS ] && [ $ERRORS_CURRENT -gt 0 ] && [ $ERRORS_CURRENT -ne $ERRORS_PREVIOUS ]; do
echo ""
echo "🔄 Itération $ITERATION/$MAX_ITERATIONS"
echo " Erreurs: $ERRORS_CURRENT"
# Traiter chaque fichier avec erreurs
cat /tmp/phpstan_files.txt | while IFS='|' read file error_count; do
if [ "$error_count" -gt 0 ]; then
echo " 📝 Traitement: $file ($error_count erreurs)"
# Extraire erreurs pour ce fichier
jq -r --arg file "$file" '.files[$file].messages[] | "\(.line)|\(.message)"' /tmp/phpstan_initial.json > /tmp/phpstan_file_errors.txt
# Limiter batch size
head -n $ERROR_BATCH_SIZE /tmp/phpstan_file_errors.txt > /tmp/phpstan_batch.txt
# Déléguer à agent phpstan-error-resolver
echo "Utiliser agent @phpstan-error-resolver avec:"
echo "Fichier: $file"
echo "Erreurs:"
cat /tmp/phpstan_batch.txt
# L'agent lit le fichier, analyse erreurs, applique corrections via Edit
fi
done
# Re-exécuter PHPStan
echo " 🔍 Vérification post-correction..."
$PHPSTAN_BIN analyze --no-progress --error-format=json > /tmp/phpstan_iteration_${ITERATION}.json
ERRORS_PREVIOUS=$ERRORS_CURRENT
ERRORS_CURRENT=$(jq '.totals.file_errors' /tmp/phpstan_iteration_${ITERATION}.json)
echo " 📊 Résultat: $ERRORS_CURRENT erreurs restantes"
# Mettre à jour fichiers avec erreurs
jq -r '.files | to_entries[] | "\(.key)|\(.value.messages | length)"' /tmp/phpstan_iteration_${ITERATION}.json > /tmp/phpstan_files.txt
ITERATION=$((ITERATION + 1))
done
```
Marquer todo #3 `completed`.
### Étape 6: Analyse Résultat Final
Marquer todo #4 `in_progress`.
```bash
ERRORS_FIXED=$((TOTAL_ERRORS_INITIAL - ERRORS_CURRENT))
SUCCESS_RATE=$(awk "BEGIN {printf \"%.1f\", ($ERRORS_FIXED / $TOTAL_ERRORS_INITIAL) * 100}")
echo ""
echo "📊 Résumé Final:"
echo " - Erreurs initiales: $TOTAL_ERRORS_INITIAL"
echo " - Erreurs restantes: $ERRORS_CURRENT"
echo " - Erreurs corrigées: $ERRORS_FIXED"
echo " - Taux de succès: ${SUCCESS_RATE}%"
echo " - Itérations: $((ITERATION - 1))/$MAX_ITERATIONS"
# Identifier fichiers non résolus
if [ $ERRORS_CURRENT -gt 0 ]; then
echo ""
echo "⚠️ Fichiers avec erreurs restantes:"
cat /tmp/phpstan_files.txt | while IFS='|' read file count; do
if [ "$count" -gt 0 ]; then
echo " - $file: $count erreurs"
fi
done
fi
```
Marquer todo #4 `completed`.
### Étape 7: Rapport Final
```bash
END_TIME=$(date +%s)
DURATION=$((END_TIME - START_TIME))
if [ $DURATION -lt 60 ]; then
DURATION_STR="${DURATION}s"
elif [ $DURATION -lt 3600 ]; then
MINUTES=$((DURATION / 60))
SECONDS=$((DURATION % 60))
DURATION_STR="${MINUTES}m ${SECONDS}s"
else
HOURS=$((DURATION / 3600))
MINUTES=$(((DURATION % 3600) / 60))
SECONDS=$((DURATION % 60))
DURATION_STR="${HOURS}h ${MINUTES}m ${SECONDS}s"
fi
echo "⏱️ Durée: $DURATION_STR"
```
```yaml
task: "Résolution des erreurs PHPStan"
status: "terminé"
details:
total_errors_initial: $TOTAL_ERRORS_INITIAL
total_errors_final: $ERRORS_CURRENT
errors_fixed: $ERRORS_FIXED
success_rate: "${SUCCESS_RATE}%"
iterations: $((ITERATION - 1))
files:
fixed:
- [Liste des fichiers corrigés]
failed:
- [Liste des fichiers non résolus]
statistics:
success_rate: "${SUCCESS_RATE}%"
execution_time: "$DURATION_STR"
phpstan_level: "[Niveau détecté depuis config]"
notes:
- "Toutes les erreurs PHPStan ont été analysées"
- "Les corrections ont été appliquées automatiquement"
- "Relancer si erreurs restantes avec contexte différent"
```
## Error Handling
- PHPStan non trouvé → ARRÊT (exit 1)
- Config PHPStan absente → ARRÊT (exit 1)
- Stagnation (erreurs ne diminuent plus) → ARRÊT avec rapport
- Max itérations atteint → ARRÊT avec rapport
## Notes
- Utilise l'agent `@phpstan-error-resolver` pour corrections
- Batch size de 5 erreurs par fichier par itération
- Maximum 10 itérations pour éviter boucles infinies
- Parser JSON via `jq`
- Marquer CHAQUE todo completed immédiatement après succès