503 lines
17 KiB
Bash
503 lines
17 KiB
Bash
|
|
#!/usr/bin/env bash
|
|||
|
|
#
|
|||
|
|
# VEZA — Script d'audit automatique overnight
|
|||
|
|
# Lance Claude Code sur chaque prompt d'audit, avec reprise sur erreur.
|
|||
|
|
#
|
|||
|
|
# Usage:
|
|||
|
|
# ./run-audit.sh # Lance depuis le début (ou reprend)
|
|||
|
|
# ./run-audit.sh --reset # Repart de zéro
|
|||
|
|
# ./run-audit.sh --from 15 # Force le démarrage au prompt 15
|
|||
|
|
# ./run-audit.sh --only 38 # N'exécute qu'un seul prompt
|
|||
|
|
# ./run-audit.sh --dry-run # Affiche ce qui serait fait sans exécuter
|
|||
|
|
# ./run-audit.sh --status # Affiche l'état actuel
|
|||
|
|
# ./run-audit.sh --model sonnet # Utilise Sonnet au lieu d'Opus (moins cher)
|
|||
|
|
#
|
|||
|
|
# Coût estimé (Opus): ~$150–400 pour les 58 prompts
|
|||
|
|
# Coût estimé (Sonnet): ~$30–80 pour les 58 prompts
|
|||
|
|
# Durée estimée: 4–8 heures selon le modèle et la charge API
|
|||
|
|
#
|
|||
|
|
set -euo pipefail
|
|||
|
|
|
|||
|
|
# ─────────────────────────────────────────────
|
|||
|
|
# Configuration
|
|||
|
|
# ─────────────────────────────────────────────
|
|||
|
|
|
|||
|
|
REPO_ROOT="$(cd "$(dirname "$0")" && pwd)"
|
|||
|
|
PROMPTS_DIR="$REPO_ROOT/prompts"
|
|||
|
|
STATE_DIR="$REPO_ROOT/.audit-state"
|
|||
|
|
STATE_FILE="$STATE_DIR/progress.json"
|
|||
|
|
LOG_DIR="$STATE_DIR/logs"
|
|||
|
|
BRANCH_NAME="audit/full-page-audit-$(date +%Y%m%d)"
|
|||
|
|
|
|||
|
|
# Claude CLI settings
|
|||
|
|
MODEL="${VEZA_AUDIT_MODEL:-opus}"
|
|||
|
|
MAX_BUDGET_PER_PROMPT="${VEZA_AUDIT_BUDGET_PER_PROMPT:-8}" # USD par prompt
|
|||
|
|
MAX_RETRIES=3
|
|||
|
|
RETRY_BACKOFF_BASE=60 # secondes, doublé à chaque retry
|
|||
|
|
COOLDOWN_BETWEEN_PROMPTS=10 # secondes entre chaque prompt
|
|||
|
|
RATE_LIMIT_PAUSE=300 # 5 min de pause si rate limit détecté
|
|||
|
|
|
|||
|
|
# Couleurs
|
|||
|
|
RED='\033[0;31m'
|
|||
|
|
GREEN='\033[0;32m'
|
|||
|
|
YELLOW='\033[1;33m'
|
|||
|
|
BLUE='\033[0;34m'
|
|||
|
|
CYAN='\033[0;36m'
|
|||
|
|
NC='\033[0m'
|
|||
|
|
|
|||
|
|
# ─────────────────────────────────────────────
|
|||
|
|
# Fonctions utilitaires
|
|||
|
|
# ─────────────────────────────────────────────
|
|||
|
|
|
|||
|
|
log() { echo -e "${CYAN}[$(date '+%H:%M:%S')]${NC} $*"; }
|
|||
|
|
info() { echo -e "${GREEN}[$(date '+%H:%M:%S')] ✓${NC} $*"; }
|
|||
|
|
warn() { echo -e "${YELLOW}[$(date '+%H:%M:%S')] ⚠${NC} $*"; }
|
|||
|
|
error() { echo -e "${RED}[$(date '+%H:%M:%S')] ✗${NC} $*"; }
|
|||
|
|
|
|||
|
|
die() { error "$*"; exit 1; }
|
|||
|
|
|
|||
|
|
# ─────────────────────────────────────────────
|
|||
|
|
# State management (fichier JSON simple via jq)
|
|||
|
|
# ─────────────────────────────────────────────
|
|||
|
|
|
|||
|
|
ensure_deps() {
|
|||
|
|
command -v claude >/dev/null 2>&1 || die "claude CLI non trouvé. Installe-le d'abord."
|
|||
|
|
command -v jq >/dev/null 2>&1 || die "jq non trouvé. Installe: sudo dnf install jq"
|
|||
|
|
command -v git >/dev/null 2>&1 || die "git non trouvé."
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
init_state() {
|
|||
|
|
mkdir -p "$STATE_DIR" "$LOG_DIR"
|
|||
|
|
|
|||
|
|
if [[ ! -f "$STATE_FILE" ]]; then
|
|||
|
|
cat > "$STATE_FILE" <<'ENDJSON'
|
|||
|
|
{
|
|||
|
|
"started_at": null,
|
|||
|
|
"branch": null,
|
|||
|
|
"prompts": {},
|
|||
|
|
"current": null,
|
|||
|
|
"total_cost_estimate_usd": 0,
|
|||
|
|
"total_prompts": 0,
|
|||
|
|
"completed": 0,
|
|||
|
|
"failed": 0,
|
|||
|
|
"skipped": 0
|
|||
|
|
}
|
|||
|
|
ENDJSON
|
|||
|
|
log "State file initialisé: $STATE_FILE"
|
|||
|
|
fi
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
state_get() {
|
|||
|
|
jq -r "$1" "$STATE_FILE"
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
state_set() {
|
|||
|
|
local tmp
|
|||
|
|
tmp=$(mktemp)
|
|||
|
|
jq "$1" "$STATE_FILE" > "$tmp" && mv "$tmp" "$STATE_FILE"
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
get_prompt_status() {
|
|||
|
|
local num="$1"
|
|||
|
|
jq -r ".prompts[\"$num\"].status // \"pending\"" "$STATE_FILE"
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
set_prompt_status() {
|
|||
|
|
local num="$1" status="$2" detail="${3:-}"
|
|||
|
|
state_set ".prompts[\"$num\"] = {
|
|||
|
|
\"status\": \"$status\",
|
|||
|
|
\"updated_at\": \"$(date -Iseconds)\",
|
|||
|
|
\"detail\": \"$detail\"
|
|||
|
|
}"
|
|||
|
|
# Update counters
|
|||
|
|
local completed failed
|
|||
|
|
completed=$(jq '[.prompts[] | select(.status == "done")] | length' "$STATE_FILE")
|
|||
|
|
failed=$(jq '[.prompts[] | select(.status == "failed")] | length' "$STATE_FILE")
|
|||
|
|
state_set ".completed = $completed | .failed = $failed"
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
# ─────────────────────────────────────────────
|
|||
|
|
# Git helpers
|
|||
|
|
# ─────────────────────────────────────────────
|
|||
|
|
|
|||
|
|
setup_branch() {
|
|||
|
|
cd "$REPO_ROOT"
|
|||
|
|
local current_branch
|
|||
|
|
current_branch=$(git branch --show-current)
|
|||
|
|
local existing_branch
|
|||
|
|
existing_branch=$(state_get '.branch // empty')
|
|||
|
|
|
|||
|
|
if [[ -n "$existing_branch" ]] && git rev-parse --verify "$existing_branch" >/dev/null 2>&1; then
|
|||
|
|
# Reprendre sur la branche existante
|
|||
|
|
if [[ "$current_branch" != "$existing_branch" ]]; then
|
|||
|
|
log "Reprise sur branche existante: $existing_branch"
|
|||
|
|
git checkout "$existing_branch"
|
|||
|
|
fi
|
|||
|
|
BRANCH_NAME="$existing_branch"
|
|||
|
|
else
|
|||
|
|
# Créer nouvelle branche depuis l'état actuel
|
|||
|
|
if git rev-parse --verify "$BRANCH_NAME" >/dev/null 2>&1; then
|
|||
|
|
BRANCH_NAME="${BRANCH_NAME}-$(date +%H%M%S)"
|
|||
|
|
fi
|
|||
|
|
log "Création branche: $BRANCH_NAME"
|
|||
|
|
git checkout -b "$BRANCH_NAME"
|
|||
|
|
state_set ".branch = \"$BRANCH_NAME\""
|
|||
|
|
fi
|
|||
|
|
|
|||
|
|
state_set ".started_at = \"$(date -Iseconds)\""
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
commit_prompt_changes() {
|
|||
|
|
local num="$1" name="$2" path="$3"
|
|||
|
|
cd "$REPO_ROOT"
|
|||
|
|
|
|||
|
|
# Vérifier s'il y a des changements
|
|||
|
|
if git diff --quiet && git diff --cached --quiet && [[ -z "$(git ls-files --others --exclude-standard)" ]]; then
|
|||
|
|
warn "Prompt $num ($path): aucun changement à committer"
|
|||
|
|
return 0
|
|||
|
|
fi
|
|||
|
|
|
|||
|
|
# Stage tous les changements (sauf les fichiers d'état de l'audit)
|
|||
|
|
git add -A -- ':!.audit-state'
|
|||
|
|
|
|||
|
|
# Vérifier à nouveau après staging
|
|||
|
|
if git diff --cached --quiet; then
|
|||
|
|
warn "Prompt $num ($path): rien dans le staging"
|
|||
|
|
return 0
|
|||
|
|
fi
|
|||
|
|
|
|||
|
|
git commit -m "$(cat <<EOF
|
|||
|
|
audit($path): fix bugs and add e2e tests — $name
|
|||
|
|
|
|||
|
|
Automated audit via Claude Code + Playwright MCP.
|
|||
|
|
- Full page audit: loading, features, a11y, i18n, responsive, security
|
|||
|
|
- Bug fixes applied
|
|||
|
|
- E2E regression tests added
|
|||
|
|
|
|||
|
|
Prompt: prompts/$(printf '%02d' "$num")-*.md
|
|||
|
|
EOF
|
|||
|
|
)"
|
|||
|
|
|
|||
|
|
info "Commit créé pour prompt $num ($path)"
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
# ─────────────────────────────────────────────
|
|||
|
|
# Exécution d'un prompt
|
|||
|
|
# ─────────────────────────────────────────────
|
|||
|
|
|
|||
|
|
run_single_prompt() {
|
|||
|
|
local prompt_file="$1"
|
|||
|
|
local num
|
|||
|
|
num=$(basename "$prompt_file" | grep -oP '^\d+')
|
|||
|
|
# Enlever le zéro devant pour le numéro
|
|||
|
|
num=$((10#$num))
|
|||
|
|
local log_file="$LOG_DIR/prompt-$(printf '%02d' "$num").log"
|
|||
|
|
local route_name
|
|||
|
|
route_name=$(basename "$prompt_file" .md | sed 's/^[0-9]*-//')
|
|||
|
|
|
|||
|
|
log "━━━ Prompt $num/58: $route_name ━━━"
|
|||
|
|
|
|||
|
|
local status
|
|||
|
|
status=$(get_prompt_status "$num")
|
|||
|
|
if [[ "$status" == "done" ]]; then
|
|||
|
|
info "Déjà complété, skip"
|
|||
|
|
return 0
|
|||
|
|
fi
|
|||
|
|
|
|||
|
|
set_prompt_status "$num" "running"
|
|||
|
|
state_set ".current = $num"
|
|||
|
|
|
|||
|
|
local prompt_content
|
|||
|
|
prompt_content=$(cat "$prompt_file")
|
|||
|
|
|
|||
|
|
local attempt=0
|
|||
|
|
local success=false
|
|||
|
|
|
|||
|
|
while (( attempt < MAX_RETRIES )); do
|
|||
|
|
attempt=$((attempt + 1))
|
|||
|
|
log "Tentative $attempt/$MAX_RETRIES..."
|
|||
|
|
|
|||
|
|
local exit_code=0
|
|||
|
|
|
|||
|
|
# Exécuter Claude Code
|
|||
|
|
# --print: mode non-interactif
|
|||
|
|
# --dangerously-skip-permissions: aucune interaction
|
|||
|
|
# --max-budget-usd: garde-fou coût par prompt
|
|||
|
|
timeout 1800 claude \
|
|||
|
|
-p \
|
|||
|
|
--dangerously-skip-permissions \
|
|||
|
|
--model "$MODEL" \
|
|||
|
|
--max-budget-usd "$MAX_BUDGET_PER_PROMPT" \
|
|||
|
|
"$prompt_content" \
|
|||
|
|
> "$log_file" 2>&1 \
|
|||
|
|
|| exit_code=$?
|
|||
|
|
|
|||
|
|
if [[ $exit_code -eq 0 ]]; then
|
|||
|
|
success=true
|
|||
|
|
break
|
|||
|
|
fi
|
|||
|
|
|
|||
|
|
# Analyser l'erreur
|
|||
|
|
local last_lines
|
|||
|
|
last_lines=$(tail -20 "$log_file" 2>/dev/null || echo "")
|
|||
|
|
|
|||
|
|
if echo "$last_lines" | grep -qi "rate.limit\|429\|too many requests\|overloaded"; then
|
|||
|
|
warn "Rate limit détecté. Pause de ${RATE_LIMIT_PAUSE}s..."
|
|||
|
|
sleep "$RATE_LIMIT_PAUSE"
|
|||
|
|
elif echo "$last_lines" | grep -qi "context.window\|token.limit\|max.*token\|session.*limit"; then
|
|||
|
|
warn "Limite de session/contexte atteinte. Prompt trop lourd, on continue."
|
|||
|
|
break
|
|||
|
|
elif echo "$last_lines" | grep -qi "network\|connection\|ECONNRESET\|ETIMEDOUT\|fetch failed"; then
|
|||
|
|
local backoff=$((RETRY_BACKOFF_BASE * (2 ** (attempt - 1))))
|
|||
|
|
warn "Erreur réseau. Backoff ${backoff}s..."
|
|||
|
|
sleep "$backoff"
|
|||
|
|
elif [[ $exit_code -eq 124 ]]; then
|
|||
|
|
warn "Timeout (30min). Le prompt a pris trop de temps."
|
|||
|
|
break
|
|||
|
|
else
|
|||
|
|
local backoff=$((RETRY_BACKOFF_BASE * (2 ** (attempt - 1))))
|
|||
|
|
warn "Erreur inconnue (code $exit_code). Backoff ${backoff}s..."
|
|||
|
|
sleep "$backoff"
|
|||
|
|
fi
|
|||
|
|
done
|
|||
|
|
|
|||
|
|
if $success; then
|
|||
|
|
# Commit les changements
|
|||
|
|
commit_prompt_changes "$num" "$route_name" "$(head -1 "$prompt_file" | grep -oP '/[a-z/:-]+')" || true
|
|||
|
|
set_prompt_status "$num" "done"
|
|||
|
|
info "Prompt $num terminé avec succès"
|
|||
|
|
else
|
|||
|
|
set_prompt_status "$num" "failed" "after $attempt attempts, exit code $exit_code"
|
|||
|
|
error "Prompt $num échoué après $attempt tentatives"
|
|||
|
|
# On continue quand même avec le suivant
|
|||
|
|
fi
|
|||
|
|
|
|||
|
|
# Cooldown entre les prompts
|
|||
|
|
if (( COOLDOWN_BETWEEN_PROMPTS > 0 )); then
|
|||
|
|
log "Cooldown ${COOLDOWN_BETWEEN_PROMPTS}s..."
|
|||
|
|
sleep "$COOLDOWN_BETWEEN_PROMPTS"
|
|||
|
|
fi
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
# ─────────────────────────────────────────────
|
|||
|
|
# Collecte des prompts
|
|||
|
|
# ─────────────────────────────────────────────
|
|||
|
|
|
|||
|
|
get_prompt_files() {
|
|||
|
|
find "$PROMPTS_DIR" -name '*.md' -not -name 'ALL-PROMPTS.md' | sort
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
# ─────────────────────────────────────────────
|
|||
|
|
# Commandes principales
|
|||
|
|
# ─────────────────────────────────────────────
|
|||
|
|
|
|||
|
|
cmd_status() {
|
|||
|
|
if [[ ! -f "$STATE_FILE" ]]; then
|
|||
|
|
log "Aucun audit en cours."
|
|||
|
|
return
|
|||
|
|
fi
|
|||
|
|
|
|||
|
|
echo ""
|
|||
|
|
echo -e "${CYAN}═══ VEZA Audit Status ═══${NC}"
|
|||
|
|
echo ""
|
|||
|
|
echo -e " Branche: $(state_get '.branch // "non démarrée"')"
|
|||
|
|
echo -e " Démarré: $(state_get '.started_at // "—"')"
|
|||
|
|
echo -e " Complétés: ${GREEN}$(state_get '.completed')${NC}"
|
|||
|
|
echo -e " Échoués: ${RED}$(state_get '.failed')${NC}"
|
|||
|
|
echo -e " En cours: $(state_get '.current // "—"')"
|
|||
|
|
echo ""
|
|||
|
|
|
|||
|
|
# Détail par prompt
|
|||
|
|
local total=0 done=0 failed=0 pending=0
|
|||
|
|
for f in $(get_prompt_files); do
|
|||
|
|
total=$((total + 1))
|
|||
|
|
local num
|
|||
|
|
num=$((10#$(basename "$f" | grep -oP '^\d+')))
|
|||
|
|
local st
|
|||
|
|
st=$(get_prompt_status "$num")
|
|||
|
|
local icon="⏳"
|
|||
|
|
case "$st" in
|
|||
|
|
done) icon="✅"; done=$((done + 1)) ;;
|
|||
|
|
failed) icon="❌"; failed=$((failed + 1)) ;;
|
|||
|
|
running) icon="🔄" ;;
|
|||
|
|
*) pending=$((pending + 1)) ;;
|
|||
|
|
esac
|
|||
|
|
printf " %s %02d. %s\n" "$icon" "$num" "$(basename "$f" .md | sed 's/^[0-9]*-//')"
|
|||
|
|
done
|
|||
|
|
|
|||
|
|
echo ""
|
|||
|
|
echo -e " Total: $total | ✅ $done | ❌ $failed | ⏳ $pending"
|
|||
|
|
echo ""
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
cmd_reset() {
|
|||
|
|
warn "Reset de l'état d'audit..."
|
|||
|
|
rm -rf "$STATE_DIR"
|
|||
|
|
info "État supprimé. Relance ./run-audit.sh pour recommencer."
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
cmd_run() {
|
|||
|
|
local start_from="${1:-0}"
|
|||
|
|
local only="${2:-0}"
|
|||
|
|
|
|||
|
|
ensure_deps
|
|||
|
|
init_state
|
|||
|
|
|
|||
|
|
local prompt_files
|
|||
|
|
mapfile -t prompt_files < <(get_prompt_files)
|
|||
|
|
local total=${#prompt_files[@]}
|
|||
|
|
|
|||
|
|
state_set ".total_prompts = $total"
|
|||
|
|
|
|||
|
|
log "═══════════════════════════════════════════════════════"
|
|||
|
|
log " VEZA — Audit automatique de $total pages"
|
|||
|
|
log " Modèle: $MODEL"
|
|||
|
|
log " Budget max par prompt: \$${MAX_BUDGET_PER_PROMPT}"
|
|||
|
|
log " Budget max total estimé: \$$(echo "$total * $MAX_BUDGET_PER_PROMPT" | bc)"
|
|||
|
|
log "═══════════════════════════════════════════════════════"
|
|||
|
|
|
|||
|
|
setup_branch
|
|||
|
|
|
|||
|
|
for prompt_file in "${prompt_files[@]}"; do
|
|||
|
|
local num
|
|||
|
|
num=$((10#$(basename "$prompt_file" | grep -oP '^\d+')))
|
|||
|
|
|
|||
|
|
# --from: sauter les prompts avant
|
|||
|
|
if (( start_from > 0 && num < start_from )); then
|
|||
|
|
continue
|
|||
|
|
fi
|
|||
|
|
|
|||
|
|
# --only: n'exécuter qu'un seul
|
|||
|
|
if (( only > 0 && num != only )); then
|
|||
|
|
continue
|
|||
|
|
fi
|
|||
|
|
|
|||
|
|
run_single_prompt "$prompt_file"
|
|||
|
|
done
|
|||
|
|
|
|||
|
|
state_set ".current = null"
|
|||
|
|
|
|||
|
|
# Résumé final
|
|||
|
|
echo ""
|
|||
|
|
log "═══════════════════════════════════════════════════════"
|
|||
|
|
log " AUDIT TERMINÉ"
|
|||
|
|
log "═══════════════════════════════════════════════════════"
|
|||
|
|
cmd_status
|
|||
|
|
|
|||
|
|
local failed_count
|
|||
|
|
failed_count=$(state_get '.failed')
|
|||
|
|
if (( failed_count > 0 )); then
|
|||
|
|
warn "$failed_count prompts ont échoué. Relance pour retenter uniquement les échecs."
|
|||
|
|
warn "Les logs sont dans: $LOG_DIR/"
|
|||
|
|
fi
|
|||
|
|
|
|||
|
|
info "Branche: $BRANCH_NAME"
|
|||
|
|
info "Commits: $(git log --oneline "$BRANCH_NAME" --not main | wc -l) commits"
|
|||
|
|
info "Logs: $LOG_DIR/"
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
cmd_dry_run() {
|
|||
|
|
init_state
|
|||
|
|
local prompt_files
|
|||
|
|
mapfile -t prompt_files < <(get_prompt_files)
|
|||
|
|
|
|||
|
|
echo ""
|
|||
|
|
log "═══ DRY RUN — Voici ce qui serait exécuté ═══"
|
|||
|
|
echo ""
|
|||
|
|
|
|||
|
|
for prompt_file in "${prompt_files[@]}"; do
|
|||
|
|
local num
|
|||
|
|
num=$((10#$(basename "$prompt_file" | grep -oP '^\d+')))
|
|||
|
|
local st
|
|||
|
|
st=$(get_prompt_status "$num")
|
|||
|
|
local action="EXÉCUTER"
|
|||
|
|
[[ "$st" == "done" ]] && action="SKIP (déjà fait)"
|
|||
|
|
printf " %02d. %-40s → %s\n" "$num" "$(basename "$prompt_file")" "$action"
|
|||
|
|
done
|
|||
|
|
|
|||
|
|
local pending
|
|||
|
|
pending=$(jq '[.prompts[] | select(.status == "done")] | length' "$STATE_FILE" 2>/dev/null || echo 0)
|
|||
|
|
local total=${#prompt_files[@]}
|
|||
|
|
local to_run=$((total - pending))
|
|||
|
|
|
|||
|
|
echo ""
|
|||
|
|
echo " À exécuter: $to_run / $total prompts"
|
|||
|
|
echo " Modèle: $MODEL"
|
|||
|
|
echo " Budget max: \$$(echo "$to_run * $MAX_BUDGET_PER_PROMPT" | bc)"
|
|||
|
|
echo " Durée estimée: $(echo "$to_run * 8" | bc) min (≈$(echo "$to_run * 8 / 60" | bc)h)"
|
|||
|
|
echo ""
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
# ─────────────────────────────────────────────
|
|||
|
|
# CLI parsing
|
|||
|
|
# ─────────────────────────────────────────────
|
|||
|
|
|
|||
|
|
main() {
|
|||
|
|
cd "$REPO_ROOT"
|
|||
|
|
|
|||
|
|
local start_from=0
|
|||
|
|
local only=0
|
|||
|
|
local dry_run=false
|
|||
|
|
|
|||
|
|
while [[ $# -gt 0 ]]; do
|
|||
|
|
case "$1" in
|
|||
|
|
--reset)
|
|||
|
|
cmd_reset
|
|||
|
|
exit 0
|
|||
|
|
;;
|
|||
|
|
--status)
|
|||
|
|
cmd_status
|
|||
|
|
exit 0
|
|||
|
|
;;
|
|||
|
|
--dry-run)
|
|||
|
|
dry_run=true
|
|||
|
|
shift
|
|||
|
|
;;
|
|||
|
|
--from)
|
|||
|
|
start_from="$2"
|
|||
|
|
shift 2
|
|||
|
|
;;
|
|||
|
|
--only)
|
|||
|
|
only="$2"
|
|||
|
|
shift 2
|
|||
|
|
;;
|
|||
|
|
--model)
|
|||
|
|
MODEL="$2"
|
|||
|
|
shift 2
|
|||
|
|
;;
|
|||
|
|
--budget)
|
|||
|
|
MAX_BUDGET_PER_PROMPT="$2"
|
|||
|
|
shift 2
|
|||
|
|
;;
|
|||
|
|
-h|--help)
|
|||
|
|
echo "Usage: $0 [options]"
|
|||
|
|
echo ""
|
|||
|
|
echo "Options:"
|
|||
|
|
echo " --reset Supprime l'état et repart de zéro"
|
|||
|
|
echo " --status Affiche la progression actuelle"
|
|||
|
|
echo " --dry-run Montre ce qui serait fait sans exécuter"
|
|||
|
|
echo " --from N Commence au prompt N"
|
|||
|
|
echo " --only N N'exécute que le prompt N"
|
|||
|
|
echo " --model MODEL Modèle Claude (opus|sonnet|haiku) [défaut: opus]"
|
|||
|
|
echo " --budget N Budget max USD par prompt [défaut: 8]"
|
|||
|
|
echo ""
|
|||
|
|
echo "Variables d'environnement:"
|
|||
|
|
echo " VEZA_AUDIT_MODEL Modèle par défaut"
|
|||
|
|
echo " VEZA_AUDIT_BUDGET_PER_PROMPT Budget par prompt"
|
|||
|
|
exit 0
|
|||
|
|
;;
|
|||
|
|
*)
|
|||
|
|
die "Option inconnue: $1 (utilise --help)"
|
|||
|
|
;;
|
|||
|
|
esac
|
|||
|
|
done
|
|||
|
|
|
|||
|
|
if $dry_run; then
|
|||
|
|
cmd_dry_run
|
|||
|
|
else
|
|||
|
|
cmd_run "$start_from" "$only"
|
|||
|
|
fi
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
main "$@"
|