diff --git a/.claude/tasks/TODO.md b/.claude/tasks/TODO.md index 14d80a9..bbc743b 100644 --- a/.claude/tasks/TODO.md +++ b/.claude/tasks/TODO.md @@ -68,6 +68,27 @@ Subtasks : - [x] Mettre à jour `skills/seo/SKILL.md` — cross-ref /validate pour W3C/WCAG - [x] Grep cohérence : refs /validate correctes, skill détecté par la harness +## Animation lib (`motion`) — install + détection + +Problème : `motion` (ex-`framer-motion`, rebrandé nov 2024) n'est ni installé par les scripts ni détecté par plugin-advisor / design-gate. Ajouter détection + install conditionnel. + +Décisions : +- **Package** : `motion` (npm `motion`, import `motion/react`). `motion-v` pour Vue 3 (package séparé). Svelte/vanilla → `motion`. +- **Éligibilité** : tout projet qui peut consommer l'API. ✅ React/Next/Remix/Astro+React, Vue3/Nuxt, Svelte. ❌ Backend, CLI, embedded, Flutter, WordPress/Drupal/Strapi, RN (réservé `react-native-reanimated`). +- **init-project** STEP 5 : auto-install si éligible + absent (l'utilisateur a déjà validé scaffold). +- **onboard** STEP 2.5 : propose + attendre OK (projet existant, opt-in). +- **plugin-advisor** : read-only — détecte + reporte ("✅ motion installed" ou "ℹ️ eligible but absent — run /onboard"). +- **design-gate** : ajouter motion/motion-v/framer-motion (legacy) dans filesystem signals. + +Subtasks : +- [x] Créer `lib/animation-lib-check.sh` — fonctions `detect_anim_eligibility()` + `is_anim_lib_installed()` + `recommend_anim_install_cmd()` +- [x] Patcher `agents/scaffolder.md` PHASE 4 — note (le scaffolder n'installe PAS, l'orchestrateur init-project STEP 5e gère) +- [x] Patcher `skills/init-project/SKILL.md` — STEP 5e ANIMATION LIB (auto-install si éligible) +- [x] Patcher `skills/onboard/SKILL.md` — STEP 2.5 ANIMATION LIB (propose + attendre yes/skip) +- [x] Patcher `agents/plugin-advisor.md` PHASE 1 (sourcing du helper) + PHASE 2 (signaux `anim-lib-eligible`/`anim-lib-installed`) + PHASE 3 (section ANIMATION LIB read-only) +- [x] Patcher `lib/design-gate.md` — ajouter motion/motion-v/framer-motion + autres anim-libs dans filesystem signals +- [x] Tester : shellcheck OK ; matrix React/Vue/RN/backend/with-motion/no-package/pnpm tous corrects + ## Helper `--help` / `help` sur tous les skills (option C) Problème : aucun skill ne gère `--help` aujourd'hui. `argument-hint` affiche juste la syntaxe en autocomplétion, pas de description/exemples. L'utilisateur doit lire le SKILL.md ou deviner. diff --git a/agents/plugin-advisor.md b/agents/plugin-advisor.md index 1aab844..eacc2fd 100644 --- a/agents/plugin-advisor.md +++ b/agents/plugin-advisor.md @@ -35,6 +35,13 @@ ls package.json pyproject.toml Cargo.toml go.mod 2>/dev/null | head -5 grep -rl "next\|react\|vue\|prisma\|supabase" package.json 2>/dev/null | head -3 || true find . -name "*.tsx" -o -name "*.jsx" 2>/dev/null | head -3 | wc -l find . -name "docker-compose*" -o -name "Dockerfile" 2>/dev/null | head -3 | wc -l + +# Animation lib status (motion / motion-v) — read-only detection +if [ -f "$HOME/.claude/lib/animation-lib-check.sh" ]; then + source "$HOME/.claude/lib/animation-lib-check.sh" + detect_anim_eligibility # outputs '||' + is_anim_lib_installed || echo "anim-lib-not-installed" +fi # Monorepo detection (current dir + parent dirs for sub-package context) ls apps/ packages/ services/ workspaces/ 2>/dev/null | head -5 ls pnpm-workspace.yaml turbo.json nx.json lerna.json 2>/dev/null @@ -70,6 +77,8 @@ Detect signals from the project description and filesystem scan: | `skill-creation` | "create a skill", "new skill", "custom skill", `/plugin-dev:create-plugin` in description | | `embedded` | "firmware", "bare-metal", "microcontroller", "STM32", "ESP32", "RTOS", "driver", "kernel", "bootloader" in description; **or** `platformio.ini` present; **or** linker script (`*.ld`, `*.lds`) present; **or** `Makefile` + `src/*.c` + no `package.json`/`Cargo.toml`/`go.mod`/`setup.py`/`pyproject.toml` (C project without standard ecosystems). Note: `.c` files with a Rust/Node/Go manifest = FFI binding, NOT embedded. | | `simple` | single file, hotfix, quick script, no frontend, no deploy | +| `anim-lib-eligible` | output of `detect_anim_eligibility` starts with `eligible|` (React/Vue/Svelte stack) | +| `anim-lib-installed` | `is_anim_lib_installed` returns 0 (any of motion / motion-v / framer-motion / gsap / lottie-react / react-spring / popmotion / auto-animate present) | --- @@ -117,11 +126,20 @@ RECOMMENDATIONS: ℹ️ OPTIONAL: [plugin] — [marginal benefit, low priority] 🖥️ CLI : [gsd v2] — [run 'gsd' in terminal if multi-session] +ANIMATION LIB: + ✅ installed (anim-lib-installed) + ℹ️ eligible () — install via /onboard or /init (eligible, not installed) + — not eligible () (no UI framework / RN / backend) + CONFLICTS: [plugin A ↔ plugin B — overlap on X] or none BLOCKING: [issues] or none ACTION REQUIRED? YES / NO ``` +> ANIMATION LIB is **read-only** in this report. The advisor never installs +> packages itself — it just states the status. Installation happens in +> `/init-project` STEP 5e (auto) or `/onboard` STEP 2.5 (opt-in). + ## PHASE 4 — AUTO-ACTIVATION (when called from /init-project or /ship-feature) After presenting RECOMMENDATIONS, if any plugin has ⚡ ENABLE status: diff --git a/agents/scaffolder.md b/agents/scaffolder.md index 670d82a..cf902a5 100644 --- a/agents/scaffolder.md +++ b/agents/scaffolder.md @@ -89,6 +89,10 @@ Add `COMPOSE_PROJECT_NAME=` to `.env.example`. On failure: read error → fix config → retry once → if still failing: report and stop. If DOCKER_RELEVANT: `docker --version && docker compose version` — failure is warning, not blocker. +> **Note**: do NOT install `motion` / `motion-v` / animation libs here. +> The init-project orchestrator handles that in STEP 5e via +> `lib/animation-lib-check.sh`. Scaffolder stays language-agnostic. + --- ## PHASE 5 — VERIFY BUILD diff --git a/lib/animation-lib-check.sh b/lib/animation-lib-check.sh new file mode 100755 index 0000000..244d1d1 --- /dev/null +++ b/lib/animation-lib-check.sh @@ -0,0 +1,117 @@ +#!/usr/bin/env bash +# ============================================================ +# lib/animation-lib-check.sh — Animation library detection +# Sourced by: skills/init-project, skills/onboard, agents/plugin-advisor. +# +# Recommends `motion` (ex-`framer-motion`, rebranded Nov 2024) for +# React-family / Svelte stacks, and `motion-v` for Vue 3 / Nuxt. +# +# Override the project root with: ANIM_PROJECT_ROOT=/path before sourcing. +# ============================================================ + +ANIM_PROJECT_ROOT="${ANIM_PROJECT_ROOT:-$PWD}" + +# Match a literal dep key in package.json (deps + devDeps + peerDeps). +# Args: $1 = exact dep name. Returns 0 if found, 1 otherwise. No output. +_anim_has_dep() { + local pkg_json="$ANIM_PROJECT_ROOT/package.json" + [ -f "$pkg_json" ] || return 1 + # The closing escaped quote anchors the match so "react" does not + # collide with "react-native" or "react-dom". + grep -Eq "\"$1\"[[:space:]]*:" "$pkg_json" +} + +# Decide whether the project can consume the motion library. +# Outputs on stdout: '||' +# status : eligible | no +# package : motion | motion-v | - +# reason : short human-readable note +# Returns 0 if eligible, 1 if not. +detect_anim_eligibility() { + local pkg_json="$ANIM_PROJECT_ROOT/package.json" + + if [ ! -f "$pkg_json" ]; then + echo "no|-|no package.json (not a Node project)" + return 1 + fi + + # React Native / Expo are excluded: motion targets the DOM, RN apps + # should use react-native-reanimated instead. + if _anim_has_dep "react-native" || _anim_has_dep "expo"; then + echo "no|-|React Native stack — use react-native-reanimated" + return 1 + fi + + if _anim_has_dep "react" || _anim_has_dep "next" \ + || _anim_has_dep "@remix-run/react" || _anim_has_dep "@astrojs/react"; then + echo "eligible|motion|React-family stack" + return 0 + fi + + if _anim_has_dep "vue" || _anim_has_dep "nuxt"; then + echo "eligible|motion-v|Vue 3 / Nuxt stack" + return 0 + fi + + if _anim_has_dep "svelte" || _anim_has_dep "@sveltejs/kit"; then + echo "eligible|motion|Svelte stack" + return 0 + fi + + if _anim_has_dep "astro"; then + echo "no|-|Astro without a React/Vue/Svelte integration" + return 1 + fi + + echo "no|-|no supported UI framework detected" + return 1 +} + +# Look for any installed animation library. +# Outputs the detected package name on stdout (empty if none). +# Returns 0 if found, 1 otherwise. +is_anim_lib_installed() { + local pkg_json="$ANIM_PROJECT_ROOT/package.json" + [ -f "$pkg_json" ] || return 1 + + local libs=( + motion + motion-v + framer-motion + gsap + "@gsap/react" + lottie-react + react-spring + "@react-spring/web" + popmotion + "@formkit/auto-animate" + ) + + local lib + for lib in "${libs[@]}"; do + if _anim_has_dep "$lib"; then + echo "$lib" + return 0 + fi + done + return 1 +} + +# Build the install command for the recommended package. +# Args: $1 = package name (motion | motion-v). +# Outputs the command on stdout. Returns 1 on missing arg. +recommend_anim_install_cmd() { + local pkg="$1" + [ -z "$pkg" ] && return 1 + local root="$ANIM_PROJECT_ROOT" + + if [ -f "$root/pnpm-lock.yaml" ]; then + echo "pnpm add $pkg" + elif [ -f "$root/yarn.lock" ]; then + echo "yarn add $pkg" + elif [ -f "$root/bun.lockb" ] || [ -f "$root/bun.lock" ]; then + echo "bun add $pkg" + else + echo "npm install $pkg" + fi +} diff --git a/lib/design-gate.md b/lib/design-gate.md index d3c0762..1d56bdd 100644 --- a/lib/design-gate.md +++ b/lib/design-gate.md @@ -21,6 +21,7 @@ Check BOTH the task description AND the filesystem: - `tailwind.config` or `postcss.config` present in project root - `tokens/`, `theme/`, or `design-system/` directory exists - Storybook config (`.storybook/`) present +- Animation lib in `package.json` deps: `motion`, `motion-v`, `framer-motion` (legacy), `gsap`, `@gsap/react`, `lottie-react`, `react-spring`, `popmotion`, `@formkit/auto-animate` ## DECISION diff --git a/skills/init-project/SKILL.md b/skills/init-project/SKILL.md index 3cac6c5..7aaea77 100644 --- a/skills/init-project/SKILL.md +++ b/skills/init-project/SKILL.md @@ -87,6 +87,33 @@ If `graphify` CLI is installed AND complexity >= 30%: 3. Print: `🔗 Scaffold graph generated at graphify-out/` If `graphify` not installed or complexity < 30% → skip silently. +## STEP 5e — ANIMATION LIB (auto-install) +Install `motion` (ex-`framer-motion`, rebranded Nov 2024) when the stack supports it. +The scaffold has just been validated by the user, so install proceeds silently. + +```bash +source "$HOME/.claude/lib/animation-lib-check.sh" +if result=$(detect_anim_eligibility); then + pkg=$(echo "$result" | cut -d'|' -f2) + if ! is_anim_lib_installed >/dev/null; then + cmd=$(recommend_anim_install_cmd "$pkg") + echo "🎬 Installing animation lib: $cmd" + eval "$cmd" + else + installed=$(is_anim_lib_installed) + echo "🎬 Animation lib already present: $installed — skipping install" + fi +else + echo "🎬 Animation lib: stack not eligible — skipping ($(echo "$result" | cut -d'|' -f3))" +fi +``` + +Rules: +- `motion` for React-family / Svelte / vanilla JS stacks. +- `motion-v` for Vue 3 / Nuxt. +- React Native, Flutter, backend, embedded, static HTML → skipped. +- If another animation lib (gsap, lottie-react, react-spring, …) is already present → skipped. + ## STEP 6 — PLAN Invoke `superpowers:writing-plans` with BRIEF + skeleton. Granular tasks (2-5 min each), exact file paths, TDD: tests before code. diff --git a/skills/onboard/SKILL.md b/skills/onboard/SKILL.md index b7c5e85..dbf9110 100644 --- a/skills/onboard/SKILL.md +++ b/skills/onboard/SKILL.md @@ -103,6 +103,38 @@ Si `CLAUDE.md` existe déjà : lire son contenu, ne PAS écraser — fusionner a --- +## STEP 2.5 — ANIMATION LIB (propose, opt-in) +Vérifier si le stack peut consommer `motion` (ex-`framer-motion`, rebranded nov 2024) +et proposer l'install si absent. **Aucun install sans confirmation utilisateur** — +on ajoute une dep à un projet existant. + +```bash +source "$HOME/.claude/lib/animation-lib-check.sh" +result=$(detect_anim_eligibility) +status=$(echo "$result" | cut -d'|' -f1) +pkg=$(echo "$result" | cut -d'|' -f2) +reason=$(echo "$result" | cut -d'|' -f3) +``` + +Cas : +- **`status=eligible` AND aucune lib anim détectée** → proposer : + ``` + 🎬 ANIMATION LIB + Stack: . Aucune lib d'animation détectée. + Install `` ? (yes / skip) + ``` + Sur `yes` → exécuter `recommend_anim_install_cmd "$pkg"` puis confirmer. + Sur `skip` → continuer silencieusement. + +- **`status=eligible` AND une lib anim déjà présente** (motion, framer-motion, gsap, lottie, react-spring, popmotion, auto-animate) → log info uniquement : + ``` + 🎬 Animation lib déjà présente : — pas d'action. + ``` + +- **`status=no`** → skip silencieusement (raison loggée seulement en mode verbose). + +--- + ## STEP 3 — DEEP INTERVIEW L'orchestrateur pilote directement l'interview (l'agent `interviewer.md` est laissé pour `/init-project` où le BRIEF format est attendu ; ici on reste en markdown libre dans la CLAUDE.md).