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 ───────────────────────────────────────────────── # ── Configuration ─────────────────────────────────────────────────
REPO_URL="https://gitea.maison43.duckdns.org/gilles/mes_skills.git" REPO_URL="https://gitea.maison43.duckdns.org/gilles/mes_skills.git"
REPO_DIR="/tmp/mes_skills_$$" REPO_DIR="/tmp/mes_skills_$$"
_CLONED_REPO_DIR=""
STATE_FILE="/tmp/skills_state_$$" STATE_FILE="/tmp/skills_state_$$"
SKILLS_DEBUG="${SKILLS_DEBUG:-0}" SKILLS_DEBUG="${SKILLS_DEBUG:-0}"
@@ -54,8 +55,8 @@ header() { echo -e "\n${GRV_PURPLE}╔══ $* ══╗${RESET}\n"; }
# ── Nettoyage automatique ───────────────────────────────────────── # ── Nettoyage automatique ─────────────────────────────────────────
cleanup() { cleanup() {
debug "Nettoyage $REPO_DIR et $STATE_FILE" debug "Nettoyage $_CLONED_REPO_DIR et $STATE_FILE"
[[ -d "$REPO_DIR" ]] && rm -rf "$REPO_DIR" [[ -n "$_CLONED_REPO_DIR" && -d "$_CLONED_REPO_DIR" ]] && rm -rf "$_CLONED_REPO_DIR"
[[ -f "$STATE_FILE" ]] && rm -f "$STATE_FILE" [[ -f "$STATE_FILE" ]] && rm -f "$STATE_FILE"
} }
trap cleanup EXIT trap cleanup EXIT
@@ -101,27 +102,57 @@ DETECTED_AGENTS=()
detect_agents() { detect_agents() {
header "Détection des agents IA" header "Détection des agents IA"
_check_agent() { _add_agent() {
local name="$1" primary="$2" secondary="$3" local name="$1"
if [[ -n "$SKILLS_AGENT" && "$SKILLS_AGENT" != "$name" ]]; then if [[ -n "$SKILLS_AGENT" && "$SKILLS_AGENT" != "$name" ]]; then
debug "Agent $name ignoré (SKILLS_AGENT=$SKILLS_AGENT)" debug "Agent $name ignoré (SKILLS_AGENT=$SKILLS_AGENT)"
return return
fi fi
if eval "$primary" &>/dev/null 2>&1 || eval "$secondary" &>/dev/null 2>&1; then DETECTED_AGENTS+=("$name")
DETECTED_AGENTS+=("$name") ok "Agent détecté : $name"
ok "Agent détecté : $name" }
else
_skip_agent() {
local name="$1"
if [[ -z "$SKILLS_AGENT" || "$SKILLS_AGENT" == "$name" ]]; then
echo -e "${GRV_GRAY}${ICO_NA} Agent absent : $name${RESET}" echo -e "${GRV_GRAY}${ICO_NA} Agent absent : $name${RESET}"
fi fi
} }
local npm_prefix _detect_gemini() {
npm_prefix=$(npm config get prefix 2>/dev/null || echo "") 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" # claude-code
_check_agent "gemini-cli" "command -v gemini" "test -f ${npm_prefix}/bin/gemini" if [[ -d "$HOME/.claude" ]] || command -v claude &>/dev/null; then
_check_agent "codex" "command -v codex" "test -f $HOME/.npm-global/bin/codex" _add_agent "claude-code"
_check_agent "hermes" "command -v hermes" "test -f $HOME/.local/bin/hermes" 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 if [[ ${#DETECTED_AGENTS[@]} -eq 0 ]]; then
warn "Aucun agent IA détecté. L'installation continuera mais aucun skill ne sera filtré." warn "Aucun agent IA détecté. L'installation continuera mais aucun skill ne sera filtré."
@@ -138,6 +169,7 @@ clone_repo() {
fi fi
info "Clonage depuis $REPO_URL..." info "Clonage depuis $REPO_URL..."
git clone --depth=1 "$REPO_URL" "$REPO_DIR" &>/dev/null git clone --depth=1 "$REPO_URL" "$REPO_DIR" &>/dev/null
_CLONED_REPO_DIR="$REPO_DIR"
ok "Dépôt cloné dans $REPO_DIR" ok "Dépôt cloné dans $REPO_DIR"
} }
@@ -194,9 +226,11 @@ scan_skills() {
# Filtre agent # Filtre agent
local agent_detected=0 local agent_detected=0
for a in "${DETECTED_AGENTS[@]:-}"; do if [[ ${#DETECTED_AGENTS[@]} -gt 0 ]]; then
[[ "$a" == "$agent" ]] && agent_detected=1 for a in "${DETECTED_AGENTS[@]}"; do
done [[ "$a" == "$agent" ]] && agent_detected=1
done
fi
[[ "$agent_detected" -eq 0 && ${#DETECTED_AGENTS[@]} -gt 0 ]] && continue [[ "$agent_detected" -eq 0 && ${#DETECTED_AGENTS[@]} -gt 0 ]] && continue
# Filtre tag # Filtre tag
@@ -223,11 +257,21 @@ scan_skills() {
ok "${#SKILLS_LIST[@]} skill(s) trouvé(s)" 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 ────────────────────────────────────────────────── # ── État du menu ──────────────────────────────────────────────────
state_init() { state_init() {
: > "$STATE_FILE" : > "$STATE_FILE"
for entry in "${SKILLS_LIST[@]}"; do for entry in "${SKILLS_LIST[@]}"; do
local key="${entry//|/_}" local key; key=$(make_key "$entry")
echo "${key}=local" >> "$STATE_FILE" echo "${key}=local" >> "$STATE_FILE"
done done
} }
@@ -255,7 +299,7 @@ format_skill_line() {
local entry="$1" local entry="$1"
local cat skill agent etat repo_ver local_ver local cat skill agent etat repo_ver local_ver
IFS='|' read -r cat skill agent etat repo_ver local_ver <<< "$entry" 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 action; action=$(state_get "$key")
local ico_etat color_etat local ico_etat color_etat
@@ -296,23 +340,34 @@ run_menu() {
cat > "$cycle_script" << 'CYCLE_EOF' cat > "$cycle_script" << 'CYCLE_EOF'
#!/usr/bin/env bash #!/usr/bin/env bash
STATE_FILE="$1" STATE_FILE="$1"
KEY="$2" SKILLS_FNS="$2"
ETAT="$3" LINE_NUM="$3" # numéro de ligne fzf (1-based)
current=$(grep "^${KEY}=" "$STATE_FILE" 2>/dev/null | cut -d'=' -f2)
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 case "$current" in
local) next="global" ;; local) next="global" ;;
global) next="skip" ;; global) next="skip" ;;
skip) [[ "$ETAT" == "upd" ]] && next="update" || next="local" ;; skip) [[ "$etat" == "upd" ]] && next="update" || next="local" ;;
update) next="local" ;; update) next="local" ;;
*) next="local" ;; *) next="local" ;;
esac esac
sed -i "s|^${KEY}=.*|${KEY}=${next}|" "$STATE_FILE" sed -i "s|^${key}=.*|${key}=${next}|" "$STATE_FILE"
CYCLE_EOF CYCLE_EOF
chmod +x "$cycle_script" chmod +x "$cycle_script"
# Exporter fonctions et variables dans un fichier source # 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 \ 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 ICO_OK ICO_UPD ICO_NEW ICO_NA ICO_LOCAL ICO_GLOBAL ICO_SKIP
echo "STATE_FILE='$STATE_FILE'" echo "STATE_FILE='$STATE_FILE'"
@@ -336,7 +391,7 @@ LIST_EOF
--ansi \ --ansi \
--prompt="Skills > " \ --prompt="Skills > " \
--header="$legend" \ --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 < <(bash "$list_script") > /dev/null || true
rm -f "$cycle_script" "$list_script" "$fns_file" rm -f "$cycle_script" "$list_script" "$fns_file"
@@ -350,7 +405,7 @@ install_selected() {
for entry in "${SKILLS_LIST[@]}"; do for entry in "${SKILLS_LIST[@]}"; do
local cat skill agent etat repo_ver local_ver local cat skill agent etat repo_ver local_ver
IFS='|' read -r cat skill agent etat repo_ver local_ver <<< "$entry" 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 action; action=$(state_get "$key")
if [[ "$action" == "skip" ]]; then if [[ "$action" == "skip" ]]; then
@@ -396,12 +451,14 @@ print_summary() {
for entry in "${SKILLS_LIST[@]}"; do for entry in "${SKILLS_LIST[@]}"; do
local cat skill agent etat repo_ver local_ver local cat skill agent etat repo_ver local_ver
IFS='|' read -r cat skill agent etat repo_ver local_ver <<< "$entry" 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 action; action=$(state_get "$key")
[[ "$action" == "skip" ]] && continue [[ "$action" == "skip" ]] && continue
local already=0 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 [[ "$already" -eq 1 ]] && continue
shown+=("${skill}|${agent}") shown+=("${skill}|${agent}")
@@ -414,7 +471,7 @@ print_summary() {
done done
echo -e "\n${GRV_PURPLE}╔══ Documentation agents ══╗${RESET}\n" echo -e "\n${GRV_PURPLE}╔══ Documentation agents ══╗${RESET}\n"
for agent in "${DETECTED_AGENTS[@]:-}"; do for agent in "${DETECTED_AGENTS[@]}"; do
case "$agent" in case "$agent" in
claude-code) echo -e " ${GRV_BLUE}Claude Code${RESET} → https://code.claude.com/docs/en/skills" ;; 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" ;; gemini-cli) echo -e " ${GRV_BLUE}Gemini CLI ${RESET} → https://github.com/google-gemini/gemini-cli/blob/main/docs/cli/skills.md" ;;