diff --git a/docs/superpowers/plans/2026-05-16-repo-et-installeur.md b/docs/superpowers/plans/2026-05-16-repo-et-installeur.md new file mode 100644 index 0000000..9706d6c --- /dev/null +++ b/docs/superpowers/plans/2026-05-16-repo-et-installeur.md @@ -0,0 +1,1566 @@ +# Dépôt Skills IA + Installeur Bash — Plan d'implémentation + +> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. + +**Goal:** Créer la structure complète du dépôt de skills multi-agents et le script `install.sh` interactif (fzf + couleurs Gruvbox). + +**Architecture:** Dépôt Gitea avec skills organisés par catégorie puis par agent. Script bash autonome avec menu fzf, état par skill dans un fichier temporaire, palette Gruvbox Dark 256 couleurs. Aucun sudo requis, zéro dépendance hors git+fzf. + +**Tech Stack:** Bash 5+, fzf, git, sort -V (semver), ANSI 256 couleurs. + +**Spec de référence:** `docs/superpowers/specs/2026-05-16-mes-skills-design.md` + +--- + +## Fichiers à créer / modifier + +| Fichier | Rôle | +|---------|------| +| `skills/dev/debugging/claude-code.md` | Skill démo Claude Code | +| `skills/dev/debugging/gemini-cli.md` | Skill démo Gemini CLI | +| `skills/dev/debugging/codex.md` | Skill démo Codex | +| `skills/dev/debugging/hermes.md` | Skill démo Hermes | +| `templates/claude-code.md` | Squelette vierge Claude Code | +| `templates/gemini-cli.md` | Squelette vierge Gemini CLI | +| `templates/codex.md` | Squelette vierge Codex | +| `templates/hermes.md` | Squelette vierge Hermes | +| `web/.gitkeep` | Réserve le dossier web pour le plan 2 | +| `docs/structure_skill.md` | Référence format SKILL.md par agent | +| `docs/structure_repo.md` | Référence structure bibliothèque | +| `docs/structure_script_install.md` | Référence architecture install.sh | +| `README.md` | Guide d'utilisation | +| `evolution.md` | Améliorations prévues | +| `install.sh` | Script principal (exécutable) | +| `tests/test_install.sh` | Tests bash (assertions simples) | + +--- + +## Task 1 : Structure des dossiers et templates + +**Files:** +- Create: `skills/dev/debugging/claude-code.md` +- Create: `skills/dev/debugging/gemini-cli.md` +- Create: `skills/dev/debugging/codex.md` +- Create: `skills/dev/debugging/hermes.md` +- Create: `templates/claude-code.md` +- Create: `templates/gemini-cli.md` +- Create: `templates/codex.md` +- Create: `templates/hermes.md` +- Create: `web/.gitkeep` + +- [ ] **Étape 1 : Créer l'arborescence des dossiers** + +```bash +mkdir -p skills/{dev,infra,ai,tools,jardinage,electronique,diy,task} +mkdir -p skills/dev/debugging +mkdir -p templates +mkdir -p web +touch web/.gitkeep +mkdir -p tests +``` + +- [ ] **Étape 2 : Créer le template Claude Code** + +Créer `templates/claude-code.md` : + +```markdown +--- +name: mon-skill +version: 1.0.0 +description: Décris clairement ce que fait ce skill et quand il se déclenche. +agents: [claude-code] +category: dev +tags: [tag1, tag2] +--- + +# Mon Skill + +## Objectif + +Décris l'objectif du skill en une phrase. + +## Quand l'utiliser + +- Cas d'usage 1 +- Cas d'usage 2 + +## Instructions + +Écris ici les instructions que Claude Code doit suivre. +``` + +- [ ] **Étape 3 : Créer le template Gemini CLI** + +Créer `templates/gemini-cli.md` : + +```markdown +--- +name: mon-skill +version: 1.0.0 +description: Décris clairement ce que fait ce skill et quand il se déclenche. +agents: [gemini-cli] +category: dev +tags: [tag1, tag2] +--- + +# Mon Skill + +## Objectif + +Décris l'objectif du skill en une phrase. + +## Quand l'utiliser + +- Cas d'usage 1 +- Cas d'usage 2 + +## Instructions + +Écris ici les instructions que Gemini CLI doit suivre. +``` + +- [ ] **Étape 4 : Créer le template Codex** + +Créer `templates/codex.md` : + +```markdown +--- +name: mon-skill +version: 1.0.0 +description: Décris clairement ce que fait ce skill et quand il se déclenche. +allow_implicit_invocation: true +agents: [codex] +category: dev +tags: [tag1, tag2] +--- + +# Mon Skill + +## Objectif + +Décris l'objectif du skill en une phrase. + +## Quand l'utiliser + +- Cas d'usage 1 +- Cas d'usage 2 + +## Instructions + +Écris ici les instructions que Codex doit suivre. +``` + +- [ ] **Étape 5 : Créer le template Hermes** + +Créer `templates/hermes.md` : + +```markdown +--- +name: mon-skill +version: 1.0.0 +description: Décris clairement ce que fait ce skill et quand il se déclenche. +agents: [hermes] +category: dev +tags: [tag1, tag2] +metadata: + hermes: + tags: [tag1, tag2] + category: dev +--- + +# Mon Skill + +## Quand utiliser ce skill + +- Cas d'usage 1 + +## Référence rapide + +| Élément | Valeur | +|---------|--------| +| Commande | `exemple` | + +## Procédure + +1. Étape 1 +2. Étape 2 + +## Pièges connus + +- Piège 1 + +## Vérification + +- [ ] Résultat attendu 1 +``` + +- [ ] **Étape 6 : Créer le skill de démo `debugging` pour Claude Code** + +Créer `skills/dev/debugging/claude-code.md` : + +```markdown +--- +name: debugging +version: 1.0.0 +description: Systématise le processus de débogage. Utiliser quand un bug est détecté, un test échoue ou un comportement inattendu est observé. +agents: [claude-code] +category: dev +tags: [debug, test, bug] +--- + +# Debugging Systématique + +## Objectif + +Fournir une approche structurée et reproductible pour identifier et corriger les bugs. + +## Quand l'utiliser + +- Un test échoue +- Un comportement inattendu est observé +- Une erreur apparaît dans les logs + +## Instructions + +1. **Reproduire** : Isoler le cas minimal qui déclenche le bug +2. **Observer** : Lire le message d'erreur complet sans supposer +3. **Hypothèse** : Formuler une seule hypothèse à la fois +4. **Tester** : Vérifier l'hypothèse avec une modification minimale +5. **Corriger** : Appliquer la correction et vérifier que le test passe +6. **Régression** : S'assurer qu'aucun autre test n'est cassé +``` + +- [ ] **Étape 7 : Créer le skill démo pour Gemini CLI, Codex, Hermes** + +Créer `skills/dev/debugging/gemini-cli.md` : + +```markdown +--- +name: debugging +version: 1.0.0 +description: Systématise le débogage. Utiliser quand un bug ou comportement inattendu est observé. +agents: [gemini-cli] +category: dev +tags: [debug, test, bug] +--- + +# Debugging Systématique + +## Instructions + +1. Reproduire le bug avec le cas minimal +2. Lire le message d'erreur complet +3. Formuler une hypothèse unique +4. Tester et corriger +5. Vérifier les régressions +``` + +Créer `skills/dev/debugging/codex.md` : + +```markdown +--- +name: debugging +version: 1.0.0 +description: Systématise le débogage. Utiliser quand un bug ou comportement inattendu est observé. +allow_implicit_invocation: true +agents: [codex] +category: dev +tags: [debug, test, bug] +--- + +# Debugging Systématique + +## Instructions + +1. Reproduire le bug avec le cas minimal +2. Lire le message d'erreur complet +3. Formuler une hypothèse unique +4. Tester et corriger +5. Vérifier les régressions +``` + +Créer `skills/dev/debugging/hermes.md` : + +```markdown +--- +name: debugging +version: 1.0.0 +description: Systématise le débogage. Utiliser quand un bug ou comportement inattendu est observé. +agents: [hermes] +category: dev +tags: [debug, test, bug] +metadata: + hermes: + tags: [debug, test, bug] + category: dev +--- + +# Debugging Systématique + +## Quand utiliser ce skill + +- Un test échoue +- Un comportement inattendu est observé + +## Procédure + +1. Reproduire le bug avec le cas minimal +2. Lire le message d'erreur complet +3. Formuler une hypothèse unique +4. Tester et corriger +5. Vérifier les régressions + +## Vérification + +- [ ] Le bug est reproduit avant correction +- [ ] La correction ne casse aucun autre test +``` + +- [ ] **Étape 8 : Commit** + +```bash +rtk git add skills/ templates/ web/.gitkeep +rtk git commit -m "feat: structure dossiers, templates et skill démo debugging" +``` + +--- + +## Task 2 : Documentation — `docs/structure_skill.md` + +**Files:** +- Create: `docs/structure_skill.md` + +- [ ] **Étape 1 : Créer `docs/structure_skill.md`** + +```markdown +# Structure des Skills par Agent IA + +Ce document décrit le format exact attendu pour chaque agent. +Un même skill peut exister en plusieurs versions (une par agent). + +--- + +## Format commun (frontmatter YAML) + +Tous les agents partagent ces champs de base : + +| Champ | Requis | Description | +|-------|--------|-------------| +| `name` | oui | Identifiant unique du skill (kebab-case) | +| `version` | oui | Version semver `X.Y.Z` | +| `description` | oui | Description + déclencheurs (crucial pour l'activation automatique) | +| `agents` | oui | Liste des agents : `[claude-code]`, `[gemini-cli]`, etc. | +| `category` | oui | Catégorie : `dev`, `infra`, `ai`, `tools`, `jardinage`, `electronique`, `diy`, `task` | +| `tags` | recommandé | Mots-clés libres : `[bash, debug, git]` | + +--- + +## Claude Code + +**Docs :** https://code.claude.com/docs/en/skills + +**Fichier dans le dépôt :** `skills///claude-code.md` +**Destination globale :** `~/.claude/skills///SKILL.md` +**Destination locale :** `.claude/skills///SKILL.md` + +```yaml +--- +name: mon-skill +version: 1.0.0 +description: Description et déclencheurs. +agents: [claude-code] +category: dev +tags: [tag1, tag2] +# Optionnels : +# disable-model-invocation: true # seul l'utilisateur peut invoquer +# user-invocable: false # seul Claude peut invoquer +# allowed-tools: [Read, Grep] # restreint les outils disponibles +--- +``` + +**Commande de test :** +```bash +claude "utilise le skill " --print +``` + +--- + +## Gemini CLI + +**Docs :** https://github.com/google-gemini/gemini-cli/blob/main/docs/cli/skills.md + +**Fichier dans le dépôt :** `skills///gemini-cli.md` +**Destination globale :** `~/.gemini/skills///SKILL.md` +**Destination locale :** `.gemini/skills///SKILL.md` +**Alias :** `~/.agents/skills/` et `.agents/skills/` + +```yaml +--- +name: mon-skill +version: 1.0.0 +description: Description et déclencheurs. +agents: [gemini-cli] +category: dev +tags: [tag1, tag2] +--- +``` + +**Commande de test :** +```bash +gemini -p "utilise le skill " +``` + +--- + +## Codex (OpenAI) + +**Docs :** https://developers.openai.com/codex/skills + +**Fichier dans le dépôt :** `skills///codex.md` +**Destination globale :** `~/.codex/skills///SKILL.md` +**Destination locale :** `.codex/skills///SKILL.md` + +```yaml +--- +name: mon-skill +version: 1.0.0 +description: Description et déclencheurs. +allow_implicit_invocation: true +agents: [codex] +category: dev +tags: [tag1, tag2] +--- +``` + +**Commande de test :** +```bash +codex "$" +``` + +--- + +## Hermes Agent (NousResearch) + +**Docs :** https://hermes-agent.nousresearch.com/docs/user-guide/features/skills/ + +**Fichier dans le dépôt :** `skills///hermes.md` +**Destination globale :** `~/.hermes/skills///SKILL.md` +**Destination locale :** `.hermes/skills///SKILL.md` + +```yaml +--- +name: mon-skill +version: 1.0.0 +description: Description et déclencheurs. +agents: [hermes] +category: dev +tags: [tag1, tag2] +metadata: + hermes: + tags: [tag1, tag2] + category: dev +--- +``` + +Structure Markdown recommandée par Hermes : +- `## Quand utiliser ce skill` +- `## Référence rapide` +- `## Procédure` +- `## Pièges connus` +- `## Vérification` + +**Commande de test :** +```bash +hermes "utilise le skill " +``` +``` + +- [ ] **Étape 2 : Commit** + +```bash +rtk git add docs/structure_skill.md +rtk git commit -m "docs: référence format SKILL.md par agent" +``` + +--- + +## Task 3 : Documentation — `docs/structure_repo.md` et `docs/structure_script_install.md` + +**Files:** +- Create: `docs/structure_repo.md` +- Create: `docs/structure_script_install.md` + +- [ ] **Étape 1 : Créer `docs/structure_repo.md`** + +```markdown +# Structure de la Bibliothèque de Skills + +## Arborescence + +``` +mes_skills/ +├── skills/ ← bibliothèque principale +│ ├── / ← catégorie (dev, infra, jardinage, ...) +│ │ └── / ← un dossier par skill +│ │ ├── claude-code.md ← variante Claude Code +│ │ ├── gemini-cli.md ← variante Gemini CLI +│ │ ├── codex.md ← variante Codex +│ │ └── hermes.md ← variante Hermes Agent +├── templates/ ← squelettes vierges par agent +│ ├── claude-code.md +│ ├── gemini-cli.md +│ ├── codex.md +│ └── hermes.md +├── web/ ← portail web statique (Hugo + Docker) +├── docs/ ← documentation du dépôt +├── tests/ ← tests bash de install.sh +├── install.sh ← installeur interactif +├── README.md +├── evolution.md +└── CLAUDE.md +``` + +## Catégories disponibles + +| Catégorie | Usage | +|-----------|-------| +| `dev` | Développement : debug, git, tests, refactoring | +| `infra` | Infrastructure : docker, proxmox, homelab | +| `ai` | Agents IA : prompting, workflows | +| `tools` | Scripts utilitaires, automatisations | +| `jardinage` | Jardinage et plantes | +| `electronique` | Électronique, Arduino, ESP32 | +| `diy` | Bricolage, impression 3D | +| `task` | Gestion de tâches, organisation | + +## Conventions + +- Nom du skill : kebab-case (`mon-skill`) +- Nom des fichiers : `.md` (ex: `claude-code.md`) +- Version : semver `X.Y.Z` dans le frontmatter +- Tags : minuscules, sans espace (ex: `[bash, debug]`) +- L'installeur copie `.md` → `SKILL.md` dans la destination + +## Ajouter un nouveau skill + +1. Créer le dossier : `skills///` +2. Copier un template depuis `templates/.md` +3. Remplir le frontmatter et le contenu +4. Committer et pusher vers Gitea +``` + +- [ ] **Étape 2 : Créer `docs/structure_script_install.md`** + +```markdown +# Architecture de install.sh + +## Vue d'ensemble + +`install.sh` est un script bash autonome qui : +1. Vérifie les dépendances (git, fzf) +2. Détecte les agents IA installés +3. Clone le dépôt en /tmp +4. Présente un menu fzf interactif avec état par skill +5. Installe les skills sélectionnés sans sudo +6. Affiche un bilan + commandes de test + +## Variables d'environnement + +| Variable | Défaut | Effet | +|----------|--------|-------| +| `SKILLS_DEBUG=1` | non | Affiche chaque étape en détail | +| `SKILLS_DRY_RUN=1` | non | Simule sans écrire de fichiers | +| `SKILLS_REPO=/path` | (Gitea) | Utilise un dépôt local | +| `SKILLS_TAG=bash` | (tous) | Filtre les skills par tag | +| `SKILLS_AGENT=claude` | (auto) | Force un seul agent | + +## Palette Gruvbox Dark (256 couleurs) + +| Variable | Code | Usage | +|----------|------|-------| +| `GRV_GREEN` | `\033[38;5;142m` | Succès, installé ✓ | +| `GRV_YELLOW` | `\033[38;5;214m` | MAJ dispo ↑ | +| `GRV_AQUA` | `\033[38;5;108m` | Nouveau skill + | +| `GRV_GRAY` | `\033[38;5;245m` | Non applicable · | +| `GRV_RED` | `\033[38;5;167m` | Erreur fatale | +| `GRV_ORANGE` | `\033[38;5;208m` | Avertissement | +| `GRV_BLUE` | `\033[38;5;109m` | Info, action globale | +| `GRV_PURPLE` | `\033[38;5;175m` | Encadrés, titres | + +## Flux d'exécution + +``` +check_deps() + └─ fzf absent → install_fzf() ou exit + └─ git absent → exit 1 + +detect_agents() → tableau DETECTED_AGENTS[] + +clone_repo() → /tmp/mes_skills_/ + +scan_skills() + └─ pour chaque skills///.md du dépôt + └─ si agent dans DETECTED_AGENTS + └─ get_local_version() vs get_repo_version() + └─ compare_versions() → état (✓ ↑ + ·) + +run_menu() [fzf + fichier état /tmp/skills_state_] + └─ TAB → cycle_action() + reload + └─ ENTER → liste des sélections + +install_selected() + └─ mkdir -p destination + └─ cp .md → SKILL.md + +print_summary() + └─ bilan coloré + └─ commandes de test copiables + └─ liens docs agents + +cleanup() [trap EXIT] +``` + +## Destinations d'installation (sans sudo) + +| Agent | Global | Local | +|-------|--------|-------| +| claude-code | `~/.claude/skills///SKILL.md` | `.claude/skills///SKILL.md` | +| gemini-cli | `~/.gemini/skills///SKILL.md` | `.gemini/skills///SKILL.md` | +| codex | `~/.codex/skills///SKILL.md` | `.codex/skills///SKILL.md` | +| hermes | `~/.hermes/skills///SKILL.md` | `.hermes/skills///SKILL.md` | +``` + +- [ ] **Étape 3 : Commit** + +```bash +rtk git add docs/structure_repo.md docs/structure_script_install.md +rtk git commit -m "docs: structure dépôt et architecture install.sh" +``` + +--- + +## Task 4 : `README.md` et `evolution.md` + +**Files:** +- Create: `README.md` +- Create: `evolution.md` + +- [ ] **Étape 1 : Créer `README.md`** + +```markdown +# mes_skills — Bibliothèque personnelle de skills IA + +Dépôt Gitea personnel de skills réutilisables pour agents IA : +**Claude Code**, **Gemini CLI**, **Codex (OpenAI)**, **Hermes Agent**. + +## Installation rapide + +```bash +curl -fsSL https://gitea.maison43.duckdns.org/gilles/mes_skills/raw/branch/main/install.sh | bash +``` + +## Ce que fait l'installeur + +1. Détecte les agents IA présents sur ton système +2. Affiche la liste des skills disponibles avec leur statut (installé / nouveau / MAJ dispo) +3. Menu interactif fzf : TAB pour choisir local/global/ignorer, ENTER pour confirmer +4. Installe sans sudo dans `~/.claude/skills/`, `~/.gemini/skills/`, etc. +5. Affiche les commandes pour tester chaque skill installé + +## Options avancées + +```bash +SKILLS_DEBUG=1 bash install.sh # mode verbeux +SKILLS_DRY_RUN=1 bash install.sh # simulation sans écriture +SKILLS_TAG=bash bash install.sh # filtre par tag +SKILLS_REPO=/path bash install.sh # dépôt local (sans clone) +``` + +## Structure du dépôt + +``` +skills/// + claude-code.md ← skill pour Claude Code + gemini-cli.md ← skill pour Gemini CLI + codex.md ← skill pour Codex + hermes.md ← skill pour Hermes +``` + +Voir [docs/structure_repo.md](docs/structure_repo.md) pour le détail complet. + +## Créer un nouveau skill + +```bash +cp templates/claude-code.md skills/dev/mon-skill/claude-code.md +# Éditer le fichier, remplir name, version, description, tags +# Committer et pusher +``` + +## Documentation + +- [Format des skills par agent](docs/structure_skill.md) +- [Structure du dépôt](docs/structure_repo.md) +- [Architecture de install.sh](docs/structure_script_install.md) +- [Évolutions prévues](evolution.md) +``` + +- [ ] **Étape 2 : Créer `evolution.md`** + +```markdown +# Évolutions et Améliorations Prévues + +## v2 — Site web statique (en cours de conception) + +- Portail Hugo + Docker dans `web/` +- Navigation par catégorie, agent et tags +- Style CSS Gruvbox dark +- Synchronisation automatique avec le dépôt Gitea (git pull toutes les heures) +- Voir `docs/superpowers/plans/` pour le plan d'implémentation + +## v2.1 — Éditeur de skills depuis le navigateur + +- Éditeur Markdown intégré au portail web +- Création depuis template +- Push vers Gitea via token API + +## Futures idées + +- Upload de skills locaux vers Gitea (token API) +- Support des dossiers `scripts/` et `references/` (format Hermes complet) +- Signature/vérification d'intégrité des skills +- Synchronisation automatique via cron système +- Interface similaire à [skillsmp.com](https://skillsmp.com/fr) +``` + +- [ ] **Étape 3 : Commit** + +```bash +rtk git add README.md evolution.md +rtk git commit -m "docs: README et evolution.md" +``` + +--- + +## Task 5 : `install.sh` — socle, couleurs et helpers + +**Files:** +- Create: `install.sh` + +- [ ] **Étape 1 : Créer `install.sh` avec en-tête et palette Gruvbox** + +Créer `install.sh` : + +```bash +#!/usr/bin/env bash +# install.sh — Installeur interactif de skills IA +# Dépôt : https://gitea.maison43.duckdns.org/gilles/mes_skills +set -euo pipefail + +# ── Couleurs Gruvbox Dark 256 ────────────────────────────────────── +GRV_FG='\033[38;5;223m' +GRV_RED='\033[38;5;167m' +GRV_GREEN='\033[38;5;142m' +GRV_YELLOW='\033[38;5;214m' +GRV_BLUE='\033[38;5;109m' +GRV_PURPLE='\033[38;5;175m' +GRV_AQUA='\033[38;5;108m' +GRV_ORANGE='\033[38;5;208m' +GRV_GRAY='\033[38;5;245m' +RESET='\033[0m' + +# ── Icônes ──────────────────────────────────────────────────────── +ICO_OK="✓" +ICO_UPD="↑" +ICO_NEW="+" +ICO_NA="·" +ICO_LOCAL="●L" +ICO_GLOBAL="●G" +ICO_SKIP="○" + +# ── Configuration ───────────────────────────────────────────────── +REPO_URL="https://gitea.maison43.duckdns.org/gilles/mes_skills.git" +REPO_DIR="/tmp/mes_skills_$$" +STATE_FILE="/tmp/skills_state_$$" + +SKILLS_DEBUG="${SKILLS_DEBUG:-0}" +SKILLS_DRY_RUN="${SKILLS_DRY_RUN:-0}" +SKILLS_REPO="${SKILLS_REPO:-}" +SKILLS_TAG="${SKILLS_TAG:-}" +SKILLS_AGENT="${SKILLS_AGENT:-}" + +# ── Helpers couleur ─────────────────────────────────────────────── +ok() { echo -e "${GRV_GREEN}${ICO_OK} $*${RESET}"; } +err() { echo -e "${GRV_RED}✗ $*${RESET}" >&2; } +info() { echo -e "${GRV_BLUE}→ $*${RESET}"; } +warn() { echo -e "${GRV_ORANGE}⚠ $*${RESET}"; } +debug() { [[ "$SKILLS_DEBUG" == "1" ]] && echo -e "${GRV_GRAY}[DBG] $*${RESET}" || true; } +header() { echo -e "\n${GRV_PURPLE}╔══ $* ══╗${RESET}\n"; } +``` + +- [ ] **Étape 2 : Ajouter la fonction `cleanup` (trap EXIT)** + +Ajouter à la suite dans `install.sh` : + +```bash +# ── Nettoyage automatique ───────────────────────────────────────── +cleanup() { + debug "Nettoyage $REPO_DIR et $STATE_FILE" + [[ -d "$REPO_DIR" ]] && rm -rf "$REPO_DIR" + [[ -f "$STATE_FILE" ]] && rm -f "$STATE_FILE" +} +trap cleanup EXIT +``` + +- [ ] **Étape 3 : Commit intermédiaire** + +```bash +chmod +x install.sh +rtk git add install.sh +rtk git commit -m "feat: install.sh socle — palette Gruvbox et helpers" +``` + +--- + +## Task 6 : `install.sh` — vérification des dépendances et détection agents + +**Files:** +- Modify: `install.sh` + +- [ ] **Étape 1 : Ajouter `install_fzf()`** + +Ajouter dans `install.sh` après `cleanup` : + +```bash +# ── Installation fzf ────────────────────────────────────────────── +install_fzf() { + warn "fzf non trouvé." + echo -e " ${GRV_FG}Installer fzf ? [o/N]${RESET} \c" + read -r answer + [[ "$answer" != "o" && "$answer" != "O" ]] && err "fzf requis. Abandon." && exit 1 + + if command -v apt-get &>/dev/null; then + debug "Installation via apt" + apt-get install -y fzf 2>/dev/null || { + warn "apt échoué, tentative binaire GitHub..." + _install_fzf_binary + } + else + _install_fzf_binary + fi + command -v fzf &>/dev/null && ok "fzf installé." || { err "Impossible d'installer fzf."; exit 1; } +} + +_install_fzf_binary() { + local fzf_url="https://github.com/junegunn/fzf/releases/latest/download/fzf-linux_amd64.tar.gz" + local tmp_fzf="/tmp/fzf_$$.tar.gz" + info "Téléchargement fzf depuis GitHub Releases..." + curl -fsSL "$fzf_url" -o "$tmp_fzf" + tar -xzf "$tmp_fzf" -C "$HOME/.local/bin/" fzf + rm -f "$tmp_fzf" + export PATH="$HOME/.local/bin:$PATH" +} +``` + +- [ ] **Étape 2 : Ajouter `check_deps()`** + +```bash +# ── Vérification des dépendances ────────────────────────────────── +check_deps() { + header "Vérification des dépendances" + command -v git &>/dev/null || { err "git non trouvé. Installer git et relancer."; exit 1; } + ok "git $(git --version | awk '{print $3}')" + command -v fzf &>/dev/null || install_fzf + ok "fzf $(fzf --version | awk '{print $1}')" +} +``` + +- [ ] **Étape 3 : Ajouter `detect_agents()`** + +```bash +# ── Détection des agents IA ─────────────────────────────────────── +DETECTED_AGENTS=() + +detect_agents() { + header "Détection des agents IA" + + local check_agent() { + local name="$1" primary="$2" secondary="$3" + if [[ -n "$SKILLS_AGENT" && "$SKILLS_AGENT" != "$name" ]]; then + debug "Agent $name ignoré (SKILLS_AGENT=$SKILLS_AGENT)" + return + fi + if eval "$primary" &>/dev/null || eval "$secondary" &>/dev/null 2>/dev/null; then + DETECTED_AGENTS+=("$name") + ok "Agent détecté : $name" + else + echo -e "${GRV_GRAY}${ICO_NA} Agent absent : $name${RESET}" + fi + } + + check_agent "claude-code" "test -d $HOME/.claude" "command -v claude" + check_agent "gemini-cli" "command -v gemini" "test -f $(npm config get prefix 2>/dev/null)/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" + + if [[ ${#DETECTED_AGENTS[@]} -eq 0 ]]; then + warn "Aucun agent IA détecté. L'installation continuera mais aucun skill ne sera filtré." + fi +} +``` + +- [ ] **Étape 4 : Commit** + +```bash +rtk git add install.sh +rtk git commit -m "feat: install.sh — détection dépendances et agents IA" +``` + +--- + +## Task 7 : `install.sh` — clone, scan skills et versions + +**Files:** +- Modify: `install.sh` + +- [ ] **Étape 1 : Ajouter `clone_repo()`** + +```bash +# ── Clone du dépôt ──────────────────────────────────────────────── +clone_repo() { + header "Récupération du dépôt" + if [[ -n "$SKILLS_REPO" ]]; then + REPO_DIR="$SKILLS_REPO" + info "Utilisation du dépôt local : $REPO_DIR" + return + fi + info "Clonage depuis $REPO_URL..." + git clone --depth=1 "$REPO_URL" "$REPO_DIR" &>/dev/null + ok "Dépôt cloné dans $REPO_DIR" +} +``` + +- [ ] **Étape 2 : Ajouter les fonctions de parsing et comparaison versions** + +```bash +# ── Gestion des versions ────────────────────────────────────────── +get_frontmatter_field() { + local file="$1" field="$2" + grep "^${field}:" "$file" 2>/dev/null | head -1 | awk '{print $2}' | tr -d '"'\' +} + +get_local_version() { + local cat="$1" skill="$2" agent="$3" + local dest + dest=$(get_dest_path "$cat" "$skill" "$agent" "local") + [[ -f "$dest" ]] && get_frontmatter_field "$dest" "version" || echo "" +} + +# Retourne 1 si ver1 < ver2 (ver2 est plus récente) +version_is_newer() { + local ver1="$1" ver2="$2" + [[ "$ver1" == "$ver2" ]] && return 1 + local newest + newest=$(printf '%s\n%s' "$ver1" "$ver2" | sort -V | tail -1) + [[ "$newest" == "$ver2" ]] +} +``` + +- [ ] **Étape 3 : Ajouter `get_dest_path()` et `scan_skills()`** + +```bash +# ── Chemins de destination ──────────────────────────────────────── +get_dest_path() { + local cat="$1" skill="$2" agent="$3" scope="$4" + local base + case "$agent" in + claude-code) base="${scope//local/.claude}"; [[ "$scope" == "global" ]] && base="$HOME/.claude" ;; + gemini-cli) [[ "$scope" == "global" ]] && base="$HOME/.gemini" || base=".gemini" ;; + codex) [[ "$scope" == "global" ]] && base="$HOME/.codex" || base=".codex" ;; + hermes) [[ "$scope" == "global" ]] && base="$HOME/.hermes" || base=".hermes" ;; + esac + echo "${base}/skills/${cat}/${skill}/SKILL.md" +} + +# ── Scan des skills disponibles ─────────────────────────────────── +# Format interne : "cat|skill|agent|etat|repo_version|local_version" +SKILLS_LIST=() + +scan_skills() { + header "Scan des skills disponibles" + SKILLS_LIST=() + + while IFS= read -r skill_file; do + local rel="${skill_file#$REPO_DIR/skills/}" # dev/debugging/claude-code.md + local agent_file="${rel##*/}" # claude-code.md + local agent="${agent_file%.md}" # claude-code + local skill_path="${rel%/*}" # dev/debugging + local cat="${skill_path%%/*}" # dev + local skill="${skill_path#*/}" # debugging + + # Filtre agent + local agent_detected=0 + for a in "${DETECTED_AGENTS[@]:-}"; do [[ "$a" == "$agent" ]] && agent_detected=1; done + [[ "$agent_detected" -eq 0 && ${#DETECTED_AGENTS[@]} -gt 0 ]] && continue + + # Filtre tag + if [[ -n "$SKILLS_TAG" ]]; then + grep -q "$SKILLS_TAG" "$skill_file" || continue + fi + + local repo_ver; repo_ver=$(get_frontmatter_field "$skill_file" "version") + local local_ver; local_ver=$(get_local_version "$cat" "$skill" "$agent") + local etat + + if [[ -z "$local_ver" ]]; then + etat="new" + elif version_is_newer "$local_ver" "$repo_ver"; then + etat="upd" + else + etat="ok" + fi + + SKILLS_LIST+=("${cat}|${skill}|${agent}|${etat}|${repo_ver}|${local_ver}") + debug "Skill trouvé : $cat/$skill [$agent] état=$etat" + done < <(find "$REPO_DIR/skills" -name "*.md" | sort) + + ok "${#SKILLS_LIST[@]} skill(s) trouvé(s)" +} +``` + +- [ ] **Étape 4 : Commit** + +```bash +rtk git add install.sh +rtk git commit -m "feat: install.sh — clone dépôt, scan skills et comparaison versions" +``` + +--- + +## Task 8 : `install.sh` — menu fzf et installation + +**Files:** +- Modify: `install.sh` + +- [ ] **Étape 1 : Configurer le thème fzf Gruvbox** + +Ajouter dans `install.sh` après les variables de config : + +```bash +# ── Thème fzf Gruvbox Dark ──────────────────────────────────────── +export FZF_DEFAULT_OPTS=" + --color=bg+:#3c3836,bg:#282828,spinner:#fb4934,hl:#928374 + --color=fg:#ebdbb2,header:#928374,info:#8ec07c,pointer:#fb4934 + --color=marker:#fb4934,fg+:#ebdbb2,prompt:#fb4934,hl+:#fb4934 + --border=rounded --height=80% --layout=reverse + --header-lines=2 +" +``` + +- [ ] **Étape 2 : Ajouter les fonctions de gestion d'état par skill** + +```bash +# ── État du menu (fichier clé=valeur) ──────────────────────────── +state_init() { + > "$STATE_FILE" + for entry in "${SKILLS_LIST[@]}"; do + local key="${entry//|/_}" + local etat; etat=$(echo "$entry" | cut -d'|' -f4) + # Défaut : local (sauf si etat=ok → local aussi mais MAJ si upd) + echo "${key}=local" >> "$STATE_FILE" + done +} + +state_get() { grep "^${1}=" "$STATE_FILE" 2>/dev/null | cut -d'=' -f2; } + +state_cycle() { + local key="$1" + local etat="$2" # ok|new|upd + local current; current=$(state_get "$key") + local next + case "$current" in + local) next="global" ;; + global) next="skip" ;; + skip) + if [[ "$etat" == "upd" ]]; then next="update" + else next="local"; fi ;; + update) next="local" ;; + *) next="local" ;; + esac + sed -i "s/^${key}=.*/${key}=${next}/" "$STATE_FILE" +} +``` + +- [ ] **Étape 3 : Ajouter `format_skill_line()` et `run_menu()`** + +```bash +# ── Formatage d'une ligne du menu ───────────────────────────────── +format_skill_line() { + local entry="$1" + IFS='|' read -r cat skill agent etat repo_ver local_ver <<< "$entry" + local key="${cat}_${skill}_${agent}" + local action; action=$(state_get "$key") + + # Icône état + local ico_etat color_etat + case "$etat" in + ok) ico_etat="$ICO_OK"; color_etat="$GRV_GREEN" ;; + upd) ico_etat="$ICO_UPD"; color_etat="$GRV_YELLOW" ;; + new) ico_etat="$ICO_NEW"; color_etat="$GRV_AQUA" ;; + *) ico_etat="$ICO_NA"; color_etat="$GRV_GRAY" ;; + esac + + # Icône action + local ico_action color_action + case "$action" in + local) ico_action="$ICO_LOCAL"; color_action="$GRV_GREEN" ;; + global) ico_action="$ICO_GLOBAL"; color_action="$GRV_BLUE" ;; + skip) ico_action="$ICO_SKIP"; color_action="$GRV_GRAY" ;; + update) ico_action="$ICO_UPD"; color_action="$GRV_YELLOW" ;; + esac + + local ver_info="" + [[ "$etat" == "upd" ]] && ver_info=" (${local_ver}→${repo_ver})" + [[ "$etat" == "new" ]] && ver_info=" (v${repo_ver})" + + printf "${color_etat}%s${RESET} %-30s ${GRV_GRAY}[%s]${RESET} ${color_action}%s${RESET}%s\n" \ + "$ico_etat" "${cat}/${skill}" "$agent" "$ico_action" "$ver_info" +} + +# ── Menu fzf principal ──────────────────────────────────────────── +SELECTED_SKILLS=() + +run_menu() { + header "Sélection des skills" + state_init + + # Fichier helper pour le cycle TAB (appelé par fzf) + local cycle_script="/tmp/skills_cycle_$$.sh" + cat > "$cycle_script" << 'CYCLE_EOF' +#!/usr/bin/env bash +STATE_FILE="$1" +KEY="$2" +ETAT="$3" +current=$(grep "^${KEY}=" "$STATE_FILE" | cut -d'=' -f2) +case "$current" in + local) next="global" ;; + global) next="skip" ;; + skip) [[ "$ETAT" == "upd" ]] && next="update" || next="local" ;; + update) next="local" ;; + *) next="local" ;; +esac +sed -i "s/^${KEY}=.*/${KEY}=${next}/" "$STATE_FILE" +CYCLE_EOF + chmod +x "$cycle_script" + + # Generateur de liste pour fzf + local list_script="/tmp/skills_list_$$.sh" + cat > "$list_script" << LIST_EOF +#!/usr/bin/env bash +source /tmp/skills_fns_$$.sh +for entry in $(printf '"%s" ' "${SKILLS_LIST[@]}"); do + format_skill_line "\$entry" +done +LIST_EOF + # Exporter les fonctions nécessaires + declare -f format_skill_line state_get > "/tmp/skills_fns_$$.sh" + echo "STATE_FILE='$STATE_FILE'" >> "/tmp/skills_fns_$$.sh" + # Variables icônes et couleurs + declare -p GRV_GREEN GRV_YELLOW GRV_AQUA GRV_GRAY GRV_BLUE GRV_RED GRV_PURPLE RESET \ + ICO_OK ICO_UPD ICO_NEW ICO_NA ICO_LOCAL ICO_GLOBAL ICO_SKIP >> "/tmp/skills_fns_$$.sh" + chmod +x "$list_script" + + local legend + legend="$(echo -e "${GRV_GRAY}État: ${GRV_GREEN}✓ installé ${GRV_YELLOW}↑ MAJ ${GRV_AQUA}+ nouveau ${GRV_GRAY}· n/a Action: ${GRV_GREEN}●L local ${GRV_BLUE}●G global ${GRV_GRAY}○ ignorer TAB=changer ENTER=ok${RESET}")" + + fzf \ + --ansi \ + --multi \ + --prompt="Skills > " \ + --header="$legend" \ + --bind="tab:execute-silent($cycle_script '$STATE_FILE' {1} {4})+reload($list_script)" \ + < <(bash "$list_script") | while IFS= read -r line; do + SELECTED_SKILLS+=("$line") + done + + rm -f "$cycle_script" "$list_script" "/tmp/skills_fns_$$.sh" +} +``` + +Note : L'approche `execute-silent+reload` permet le cycle d'état en temps réel dans fzf. + +- [ ] **Étape 4 : Ajouter `install_selected()`** + +```bash +# ── Installation des skills sélectionnés ───────────────────────── +install_selected() { + header "Installation" + local count_install=0 count_update=0 count_skip=0 + + for entry in "${SKILLS_LIST[@]}"; do + IFS='|' read -r cat skill agent etat repo_ver local_ver <<< "$entry" + local key="${cat}_${skill}_${agent}" + local action; action=$(state_get "$key") + + [[ "$action" == "skip" ]] && (( count_skip++ )) && continue + + local src="${REPO_DIR}/skills/${cat}/${skill}/${agent}.md" + local dest; dest=$(get_dest_path "$cat" "$skill" "$agent" "$action") + [[ "$action" == "update" ]] && dest=$(get_dest_path "$cat" "$skill" "$agent" "local") + + debug "Copie $src → $dest" + + if [[ "$SKILLS_DRY_RUN" == "1" ]]; then + info "[DRY-RUN] cp $src → $dest" + else + mkdir -p "$(dirname "$dest")" + cp "$src" "$dest" + fi + + if [[ "$action" == "update" ]]; then + ok "Mis à jour : ${cat}/${skill} [${agent}] ${local_ver}→${repo_ver}" + (( count_update++ )) + else + ok "Installé : ${cat}/${skill} [${agent}] → ${action}" + (( count_install++ )) + fi + done + + echo -e "\n${GRV_PURPLE}╔══ Bilan ══╗${RESET}" + echo -e " ${GRV_GREEN}${ICO_OK} $count_install installé(s)${RESET}" + echo -e " ${GRV_YELLOW}${ICO_UPD} $count_update mis à jour${RESET}" + echo -e " ${GRV_GRAY}${ICO_SKIP} $count_skip ignoré(s)${RESET}" +} +``` + +- [ ] **Étape 5 : Commit** + +```bash +rtk git add install.sh +rtk git commit -m "feat: install.sh — menu fzf Gruvbox et installation des skills" +``` + +--- + +## Task 9 : `install.sh` — écran de fin et `main()` + +**Files:** +- Modify: `install.sh` + +- [ ] **Étape 1 : Ajouter `print_summary()`** + +```bash +# ── Récapitulatif final ─────────────────────────────────────────── +print_summary() { + local installed_skills=() + for entry in "${SKILLS_LIST[@]}"; do + IFS='|' read -r cat skill agent etat repo_ver local_ver <<< "$entry" + local key="${cat}_${skill}_${agent}" + local action; action=$(state_get "$key") + [[ "$action" != "skip" ]] && installed_skills+=("${skill}|${agent}") + done + + if [[ ${#installed_skills[@]} -gt 0 ]]; then + echo -e "\n${GRV_PURPLE}╔══ Tester vos skills ══╗${RESET}\n" + local shown_agents=() + for item in "${installed_skills[@]}"; do + IFS='|' read -r skill agent <<< "$item" + local already_shown=0 + for a in "${shown_agents[@]:-}"; do [[ "$a" == "${skill}|${agent}" ]] && already_shown=1; done + [[ "$already_shown" -eq 1 ]] && continue + shown_agents+=("${skill}|${agent}") + + case "$agent" in + claude-code) echo -e " ${GRV_AQUA}claude \"utilise le skill ${skill}\" --print${RESET}" ;; + gemini-cli) echo -e " ${GRV_AQUA}gemini -p \"utilise le skill ${skill}\"${RESET}" ;; + codex) echo -e " ${GRV_AQUA}codex \"\$${skill}\"${RESET}" ;; + hermes) echo -e " ${GRV_AQUA}hermes \"utilise le skill ${skill}\"${RESET}" ;; + esac + done + fi + + echo -e "\n${GRV_PURPLE}╔══ Documentation agents ══╗${RESET}\n" + 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" ;; + codex) echo -e " ${GRV_BLUE}Codex ${RESET} → https://developers.openai.com/codex/skills" ;; + hermes) echo -e " ${GRV_BLUE}Hermes ${RESET} → https://hermes-agent.nousresearch.com/docs/user-guide/features/skills/" ;; + esac + done + echo "" +} +``` + +- [ ] **Étape 2 : Ajouter `main()` et l'appel final** + +```bash +# ── Point d'entrée ──────────────────────────────────────────────── +main() { + echo -e "\n${GRV_PURPLE}╔══════════════════════════════════════╗${RESET}" + echo -e "${GRV_PURPLE}║ mes_skills — Installeur de skills ║${RESET}" + echo -e "${GRV_PURPLE}╚══════════════════════════════════════╝${RESET}\n" + + check_deps + detect_agents + clone_repo + scan_skills + + if [[ ${#SKILLS_LIST[@]} -eq 0 ]]; then + warn "Aucun skill compatible trouvé. Vérifier les agents détectés ou SKILLS_TAG." + exit 0 + fi + + run_menu + install_selected + print_summary +} + +main "$@" +``` + +- [ ] **Étape 3 : Vérifier la syntaxe bash** + +```bash +bash -n install.sh +``` + +Résultat attendu : aucune sortie (syntaxe valide). + +- [ ] **Étape 4 : Commit** + +```bash +rtk git add install.sh +rtk git commit -m "feat: install.sh — écran de fin, commandes test et point d'entrée main()" +``` + +--- + +## Task 10 : Tests bash + +**Files:** +- Create: `tests/test_install.sh` + +- [ ] **Étape 1 : Créer le runner de tests** + +Créer `tests/test_install.sh` : + +```bash +#!/usr/bin/env bash +# Tests unitaires pour install.sh +set -euo pipefail + +PASS=0 +FAIL=0 + +assert_eq() { + local desc="$1" expected="$2" actual="$3" + if [[ "$expected" == "$actual" ]]; then + echo " ✓ $desc" + (( PASS++ )) + else + echo " ✗ $desc" + echo " attendu : '$expected'" + echo " obtenu : '$actual'" + (( FAIL++ )) + fi +} + +assert_true() { + local desc="$1" + shift + if eval "$@" &>/dev/null; then + echo " ✓ $desc" + (( PASS++ )) + else + echo " ✗ $desc" + (( FAIL++ )) + fi +} + +# Charger les fonctions de install.sh sans exécuter main() +# (on commente temporairement l'appel main pour les tests) +source_install() { + # Extraire toutes les fonctions sauf main() et son appel + sed '/^main "\$@"/d' ../install.sh > /tmp/install_testable.sh + sed -i 's/^main()/# main()/' /tmp/install_testable.sh || true + source /tmp/install_testable.sh +} + +echo "" +echo "══ Tests install.sh ══" +echo "" + +# ── Test 1 : Comparaison de versions ────────────────────────────── +echo "1. Comparaison de versions" +source_install + +version_is_newer "1.0.0" "1.2.0" +assert_true "1.2.0 > 1.0.0" "version_is_newer '1.0.0' '1.2.0'" + +! version_is_newer "1.2.0" "1.0.0" 2>/dev/null +assert_true "1.0.0 n'est pas > 1.2.0" "! version_is_newer '1.2.0' '1.0.0'" + +! version_is_newer "1.0.0" "1.0.0" 2>/dev/null +assert_true "1.0.0 == 1.0.0 → pas plus récent" "! version_is_newer '1.0.0' '1.0.0'" + +# ── Test 2 : Parsing frontmatter ────────────────────────────────── +echo "" +echo "2. Parsing frontmatter" + +cat > /tmp/test_skill_$$.md << 'EOF' +--- +name: test-skill +version: 2.1.0 +description: Skill de test +agents: [claude-code] +category: dev +tags: [bash, test] +--- +# Contenu +EOF + +result=$(get_frontmatter_field "/tmp/test_skill_$$.md" "version") +assert_eq "version parsée correctement" "2.1.0" "$result" + +result=$(get_frontmatter_field "/tmp/test_skill_$$.md" "name") +assert_eq "name parsé correctement" "test-skill" "$result" + +rm -f "/tmp/test_skill_$$.md" + +# ── Test 3 : get_dest_path ──────────────────────────────────────── +echo "" +echo "3. Chemins de destination" + +result=$(get_dest_path "dev" "debugging" "claude-code" "global") +assert_eq "chemin global claude-code" "$HOME/.claude/skills/dev/debugging/SKILL.md" "$result" + +result=$(get_dest_path "dev" "debugging" "gemini-cli" "local") +assert_eq "chemin local gemini-cli" ".gemini/skills/dev/debugging/SKILL.md" "$result" + +result=$(get_dest_path "jardinage" "arrosage" "codex" "global") +assert_eq "chemin global codex jardinage" "$HOME/.codex/skills/jardinage/arrosage/SKILL.md" "$result" + +# ── Test 4 : État fichier (state_get/state_cycle) ───────────────── +echo "" +echo "4. Gestion d'état" + +STATE_FILE=$(mktemp) +echo "dev_debugging_claude_code=local" > "$STATE_FILE" + +result=$(state_get "dev_debugging_claude_code") +assert_eq "state_get retourne 'local'" "local" "$result" + +state_cycle "dev_debugging_claude_code" "ok" +result=$(state_get "dev_debugging_claude_code") +assert_eq "cycle local→global" "global" "$result" + +state_cycle "dev_debugging_claude_code" "ok" +result=$(state_get "dev_debugging_claude_code") +assert_eq "cycle global→skip" "skip" "$result" + +state_cycle "dev_debugging_claude_code" "upd" +result=$(state_get "dev_debugging_claude_code") +assert_eq "cycle skip→update (si upd)" "update" "$result" + +state_cycle "dev_debugging_claude_code" "upd" +result=$(state_get "dev_debugging_claude_code") +assert_eq "cycle update→local" "local" "$result" + +rm -f "$STATE_FILE" + +# ── Bilan ───────────────────────────────────────────────────────── +echo "" +echo "══ Résultats : ${PASS} passés, ${FAIL} échoués ══" +echo "" +[[ "$FAIL" -eq 0 ]] +``` + +- [ ] **Étape 2 : Exécuter les tests** + +```bash +cd tests && bash test_install.sh +``` + +Résultat attendu : +``` +══ Tests install.sh ══ + +1. Comparaison de versions + ✓ 1.2.0 > 1.0.0 + ✓ 1.0.0 n'est pas > 1.2.0 + ✓ 1.0.0 == 1.0.0 → pas plus récent + +2. Parsing frontmatter + ✓ version parsée correctement + ✓ name parsé correctement + +3. Chemins de destination + ✓ chemin global claude-code + ✓ chemin local gemini-cli + ✓ chemin global codex jardinage + +4. Gestion d'état + ✓ state_get retourne 'local' + ✓ cycle local→global + ✓ cycle global→skip + ✓ cycle skip→update (si upd) + ✓ cycle update→local + +══ Résultats : 13 passés, 0 échoués ══ +``` + +- [ ] **Étape 3 : Test de dry-run de install.sh** + +```bash +SKILLS_DRY_RUN=1 SKILLS_REPO=. bash install.sh +``` + +Résultat attendu : le menu fzf s'ouvre, et après sélection les lignes `[DRY-RUN] cp ...` s'affichent sans écrire de fichiers. + +- [ ] **Étape 4 : Test de débogage** + +```bash +SKILLS_DEBUG=1 SKILLS_DRY_RUN=1 SKILLS_REPO=. bash install.sh +``` + +Résultat attendu : lignes `[DBG]` visibles en gris entre chaque étape. + +- [ ] **Étape 5 : Commit final** + +```bash +cd .. +chmod +x install.sh tests/test_install.sh +rtk git add install.sh tests/test_install.sh +rtk git commit -m "feat: tests bash et install.sh complet — v1 prête" +``` + +--- + +## Auto-revue de couverture spec + +| Exigence spec | Tâche | +|---------------|-------| +| Structure dépôt par catégorie | Task 1 | +| Templates par agent | Task 1 | +| Dossier `web/` réservé | Task 1 | +| Frontmatter avec `tags` | Tasks 1-2 | +| `docs/structure_skill.md` avec liens | Task 2 | +| `docs/structure_repo.md` | Task 3 | +| `docs/structure_script_install.md` | Task 3 | +| `README.md` | Task 4 | +| `evolution.md` | Task 4 | +| Palette Gruvbox Dark 256 | Task 5 | +| Thème fzf Gruvbox | Task 8 | +| Zéro sudo | Task 6, 8 | +| Détection agents (2 méthodes) | Task 6 | +| Installation fzf si absent | Task 6 | +| Clone /tmp | Task 7 | +| Comparaison versions semver | Task 7 | +| Menu fzf + TAB cycle | Task 8 | +| Légende permanente | Task 8 | +| `install_selected()` | Task 8 | +| Écran de fin + commandes test | Task 9 | +| Liens docs agents détectés | Task 9 | +| `SKILLS_DEBUG/DRY_RUN/REPO/TAG/AGENT` | Tasks 5, 10 | +| Tests unitaires bash | Task 10 | +| Tests d'intégration dry-run | Task 10 |