fix: bugs install.sh — cleanup destructif, clé état, tableau vide, eval npm_prefix

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-16 04:22:47 +02:00
parent 6d5ab9f23a
commit 3fde00c6ee
+87 -30
View File
@@ -36,6 +36,7 @@ ICO_SKIP="○"
# ── Configuration ─────────────────────────────────────────────────
REPO_URL="https://gitea.maison43.duckdns.org/gilles/mes_skills.git"
REPO_DIR="/tmp/mes_skills_$$"
_CLONED_REPO_DIR=""
STATE_FILE="/tmp/skills_state_$$"
SKILLS_DEBUG="${SKILLS_DEBUG:-0}"
@@ -54,8 +55,8 @@ header() { echo -e "\n${GRV_PURPLE}╔══ $* ══╗${RESET}\n"; }
# ── Nettoyage automatique ─────────────────────────────────────────
cleanup() {
debug "Nettoyage $REPO_DIR et $STATE_FILE"
[[ -d "$REPO_DIR" ]] && rm -rf "$REPO_DIR"
debug "Nettoyage $_CLONED_REPO_DIR et $STATE_FILE"
[[ -n "$_CLONED_REPO_DIR" && -d "$_CLONED_REPO_DIR" ]] && rm -rf "$_CLONED_REPO_DIR"
[[ -f "$STATE_FILE" ]] && rm -f "$STATE_FILE"
}
trap cleanup EXIT
@@ -101,27 +102,57 @@ DETECTED_AGENTS=()
detect_agents() {
header "Détection des agents IA"
_check_agent() {
local name="$1" primary="$2" secondary="$3"
_add_agent() {
local name="$1"
if [[ -n "$SKILLS_AGENT" && "$SKILLS_AGENT" != "$name" ]]; then
debug "Agent $name ignoré (SKILLS_AGENT=$SKILLS_AGENT)"
return
fi
if eval "$primary" &>/dev/null 2>&1 || eval "$secondary" &>/dev/null 2>&1; then
DETECTED_AGENTS+=("$name")
ok "Agent détecté : $name"
else
DETECTED_AGENTS+=("$name")
ok "Agent détecté : $name"
}
_skip_agent() {
local name="$1"
if [[ -z "$SKILLS_AGENT" || "$SKILLS_AGENT" == "$name" ]]; then
echo -e "${GRV_GRAY}${ICO_NA} Agent absent : $name${RESET}"
fi
}
local npm_prefix
npm_prefix=$(npm config get prefix 2>/dev/null || echo "")
_detect_gemini() {
command -v gemini &>/dev/null && return 0
local prefix
prefix=$(npm config get prefix 2>/dev/null) || return 1
[[ -n "$prefix" && -f "${prefix}/bin/gemini" ]]
}
_check_agent "claude-code" "test -d $HOME/.claude" "command -v claude"
_check_agent "gemini-cli" "command -v gemini" "test -f ${npm_prefix}/bin/gemini"
_check_agent "codex" "command -v codex" "test -f $HOME/.npm-global/bin/codex"
_check_agent "hermes" "command -v hermes" "test -f $HOME/.local/bin/hermes"
# claude-code
if [[ -d "$HOME/.claude" ]] || command -v claude &>/dev/null; then
_add_agent "claude-code"
else
_skip_agent "claude-code"
fi
# gemini-cli
if _detect_gemini; then
_add_agent "gemini-cli"
else
_skip_agent "gemini-cli"
fi
# codex
if command -v codex &>/dev/null || [[ -f "$HOME/.npm-global/bin/codex" ]]; then
_add_agent "codex"
else
_skip_agent "codex"
fi
# hermes
if command -v hermes &>/dev/null || [[ -f "$HOME/.local/bin/hermes" ]]; then
_add_agent "hermes"
else
_skip_agent "hermes"
fi
if [[ ${#DETECTED_AGENTS[@]} -eq 0 ]]; then
warn "Aucun agent IA détecté. L'installation continuera mais aucun skill ne sera filtré."
@@ -138,6 +169,7 @@ clone_repo() {
fi
info "Clonage depuis $REPO_URL..."
git clone --depth=1 "$REPO_URL" "$REPO_DIR" &>/dev/null
_CLONED_REPO_DIR="$REPO_DIR"
ok "Dépôt cloné dans $REPO_DIR"
}
@@ -194,9 +226,11 @@ scan_skills() {
# Filtre agent
local agent_detected=0
for a in "${DETECTED_AGENTS[@]:-}"; do
[[ "$a" == "$agent" ]] && agent_detected=1
done
if [[ ${#DETECTED_AGENTS[@]} -gt 0 ]]; then
for a in "${DETECTED_AGENTS[@]}"; do
[[ "$a" == "$agent" ]] && agent_detected=1
done
fi
[[ "$agent_detected" -eq 0 && ${#DETECTED_AGENTS[@]} -gt 0 ]] && continue
# Filtre tag
@@ -223,11 +257,21 @@ scan_skills() {
ok "${#SKILLS_LIST[@]} skill(s) trouvé(s)"
}
# ── Clé d'état normalisée ────────────────────────────────────────
make_key() {
# Entrée : "cat|skill|agent|..." — Sortie : clé normalisée pour STATE_FILE
local entry="$1"
local cat skill agent
IFS='|' read -r cat skill agent _ <<< "$entry"
# Normalise en remplaçant - et / par _ pour éviter les collisions
printf '%s_%s_%s' "${cat//-/_}" "${skill//-/_}" "${agent//-/_}"
}
# ── État du menu ──────────────────────────────────────────────────
state_init() {
: > "$STATE_FILE"
for entry in "${SKILLS_LIST[@]}"; do
local key="${entry//|/_}"
local key; key=$(make_key "$entry")
echo "${key}=local" >> "$STATE_FILE"
done
}
@@ -255,7 +299,7 @@ format_skill_line() {
local entry="$1"
local cat skill agent etat repo_ver local_ver
IFS='|' read -r cat skill agent etat repo_ver local_ver <<< "$entry"
local key="${cat}_${skill}_${agent}"
local key; key=$(make_key "$entry")
local action; action=$(state_get "$key")
local ico_etat color_etat
@@ -296,23 +340,34 @@ run_menu() {
cat > "$cycle_script" << 'CYCLE_EOF'
#!/usr/bin/env bash
STATE_FILE="$1"
KEY="$2"
ETAT="$3"
current=$(grep "^${KEY}=" "$STATE_FILE" 2>/dev/null | cut -d'=' -f2)
SKILLS_FNS="$2"
LINE_NUM="$3" # numéro de ligne fzf (1-based)
source "$SKILLS_FNS"
# Récupère l'entrée correspondante (0-based dans SKILLS_LIST)
idx=$(( LINE_NUM - 1 ))
entry="${SKILLS_LIST[$idx]:-}"
[[ -z "$entry" ]] && exit 0
key=$(make_key "$entry")
etat=$(echo "$entry" | cut -d'|' -f4)
current=$(grep "^${key}=" "$STATE_FILE" 2>/dev/null | cut -d'=' -f2)
case "$current" in
local) next="global" ;;
global) next="skip" ;;
skip) [[ "$ETAT" == "upd" ]] && next="update" || next="local" ;;
skip) [[ "$etat" == "upd" ]] && next="update" || next="local" ;;
update) next="local" ;;
*) next="local" ;;
esac
sed -i "s|^${KEY}=.*|${KEY}=${next}|" "$STATE_FILE"
sed -i "s|^${key}=.*|${key}=${next}|" "$STATE_FILE"
CYCLE_EOF
chmod +x "$cycle_script"
# Exporter fonctions et variables dans un fichier source
{
declare -f format_skill_line state_get
declare -f format_skill_line state_get make_key
declare -p GRV_GREEN GRV_YELLOW GRV_AQUA GRV_GRAY GRV_BLUE RESET \
ICO_OK ICO_UPD ICO_NEW ICO_NA ICO_LOCAL ICO_GLOBAL ICO_SKIP
echo "STATE_FILE='$STATE_FILE'"
@@ -336,7 +391,7 @@ LIST_EOF
--ansi \
--prompt="Skills > " \
--header="$legend" \
--bind="tab:execute-silent($cycle_script '$STATE_FILE' \$(echo {} | awk '{print \$2}' | tr '/' '_' | sed 's/-/_/g')_\$(echo {} | awk '{print \$3}' | tr -d '[]') \$(echo {} | awk '{print \$4}'))+reload($list_script)" \
--bind="tab:execute-silent($cycle_script '$STATE_FILE' '$fns_file' {n})+reload($list_script)" \
< <(bash "$list_script") > /dev/null || true
rm -f "$cycle_script" "$list_script" "$fns_file"
@@ -350,7 +405,7 @@ install_selected() {
for entry in "${SKILLS_LIST[@]}"; do
local cat skill agent etat repo_ver local_ver
IFS='|' read -r cat skill agent etat repo_ver local_ver <<< "$entry"
local key="${cat}_${skill}_${agent}"
local key; key=$(make_key "$entry")
local action; action=$(state_get "$key")
if [[ "$action" == "skip" ]]; then
@@ -396,12 +451,14 @@ print_summary() {
for entry in "${SKILLS_LIST[@]}"; do
local cat skill agent etat repo_ver local_ver
IFS='|' read -r cat skill agent etat repo_ver local_ver <<< "$entry"
local key="${cat}_${skill}_${agent}"
local key; key=$(make_key "$entry")
local action; action=$(state_get "$key")
[[ "$action" == "skip" ]] && continue
local already=0
for s in "${shown[@]:-}"; do [[ "$s" == "${skill}|${agent}" ]] && already=1; done
if [[ ${#shown[@]} -gt 0 ]]; then
for s in "${shown[@]}"; do [[ "$s" == "${skill}|${agent}" ]] && already=1; done
fi
[[ "$already" -eq 1 ]] && continue
shown+=("${skill}|${agent}")
@@ -414,7 +471,7 @@ print_summary() {
done
echo -e "\n${GRV_PURPLE}╔══ Documentation agents ══╗${RESET}\n"
for agent in "${DETECTED_AGENTS[@]:-}"; do
for agent in "${DETECTED_AGENTS[@]}"; do
case "$agent" in
claude-code) echo -e " ${GRV_BLUE}Claude Code${RESET} → https://code.claude.com/docs/en/skills" ;;
gemini-cli) echo -e " ${GRV_BLUE}Gemini CLI ${RESET} → https://github.com/google-gemini/gemini-cli/blob/main/docs/cli/skills.md" ;;