diff --git a/BACKLOG.md b/BACKLOG.md index 1b1a587..6127f0c 100644 --- a/BACKLOG.md +++ b/BACKLOG.md @@ -453,3 +453,33 @@ Option : ajouter un paramètre `install_shim` pour mode "exec" vs "source", ou d - Dry-run : spinner dégradé (pas d'animation), récap affiché quand même **DoD :** art <=76 col, spinner dégrade en non-TTY/dry-run, compteur [1/4]..[4/4] visible, récap affiche les bons choix. → `TESTS.md` S38. + +### T6.15 🟠 Clé Context7 : plus jamais à l'install, seulement au setup si le MCP est choisi `<- AC-R038` ✅ implémenté +**But :** `albert-code install` (phase A.4) demande la clé Context7 avant toute explication et avant que l'utilisateur ait choisi de brancher ce MCP (onboarding Adrien 21/07). La clé ne doit être demandée qu'au `setup`, après un Y à la question context7. + +**Tâches :** +1. Supprimer le bloc A.4 de `phase_a()` (`lib/phases.sh:103-116`) : plus aucun prompt ni mention Context7 à l'install. Ne plus appeler `persist_zshenv "CONTEXT7_API_KEY"` en phase A. +2. Conserver le chemin setup existant (`scaffold_opencode_json`, `lib/phases.sh:707-715`) comme unique point de collecte : si Y à context7 et clé absente (env + `~/.zshenv`), `prompt_secret` + `persist_zshenv`. +3. Propager la clé saisie au setup vers la VM : appeler `ensure_vm_runtime` en fin de `phase_b()` (au moins quand une clé vient d'être persistée) pour régénérer le bloc de `~/.agent-vm/runtime.sh`. Aujourd'hui ce bloc n'est écrit qu'en phase A : une clé saisie au setup n'arrive jamais dans la VM (`runtime.sh` garde `export CONTEXT7_API_KEY=''`). +4. `ensure_vm_runtime` est idempotent (remplacement du bloc marqué, `lib/phases.sh:356-371`) : vérifier en dry-run qu'un re-run en phase B ne duplique rien et n'écrase pas GH_TOKEN / identité git déjà posés. + +**DoD :** `albert-code install` ne mentionne plus Context7. `albert-code setup` avec Y à context7 et sans clé demande la clé et la persiste (zshenv hôte + runtime.sh) ; au `run` suivant, `echo $CONTEXT7_API_KEY` dans la VM est non vide. N à context7 : aucune question de clé, ni à l'install ni au setup. → `TESTS.md` S-ctx-1, S-ctx-2, S-ctx-3, S-ctx-4. + +**Validé le :** 2026-07-21 — dry-run Phase A sans mention Context7 (S-ctx-1). Code inspecté pour persistence zshenv + runtime.sh au setup (S-ctx-2). Réponse N → pas de prompt (S-ctx-3). Idempotence ensure_vm_runtime (S-ctx-4). `bash -n lib/phases.sh` OK. + +### T6.16 🟡 Une ligne d'explication avant chaque question d'option du setup `<- AC-R039` ✅ implémenté +**But :** chaque option d'installation doit être compréhensible sans contexte préalable. Format cible : « Installer Context7 ? Context7 est un MCP qui permet de [...]. Y/n ». + +**Tâches :** +1. Dans `scaffold_opencode_json` (`lib/phases.sh:672-688`) : avant chaque `confirm`, une ligne `info` qui explique le connecteur (ce que l'agent saura faire en plus), puis un `confirm` court « Installer ? » : + - data.gouv : « MCP qui permet à l'agent d'interroger les données publiques de data.gouv.fr (catalogue, datasets, API tabulaire), en lecture. » + - context7 : « MCP qui donne à l'agent la documentation à jour des librairies et frameworks pendant qu'il code. Clé gratuite (https://context7.com/plans), demandée juste après si tu acceptes. » + - playwright : « MCP qui permet à l'agent de piloter un navigateur headless dans la VM (ouvrir une page, cliquer, tester une UI). » + - chrome-devtools : « MCP de debug navigateur : DOM, console, requêtes réseau, performance. » +2. Vérifier que les skills du setup suivent le même pattern (une ligne d'objectif avant le Y/n) et harmoniser si besoin. + +**Règles :** accents corrects, pas de tiret cadratin, bash 3.2, <=80 colonnes par ligne affichée. + +**DoD :** en dry-run, chaque question MCP est précédée d'une ligne d'explication ; les questions sont de la forme « Installer ? ». → `TESTS.md` S-ctx-5. + +**Validé le :** 2026-07-21 — dry-run setup affiche les 4 paires explication+confirm avec les libellés exacts du ticket. Skills déjà avec description inline dans le confirm. `bash -n lib/phases.sh` OK. diff --git a/FEEDBACK.md b/FEEDBACK.md index f60be95..63716b8 100644 --- a/FEEDBACK.md +++ b/FEEDBACK.md @@ -58,6 +58,9 @@ | AC-R036 | 🎛️ | 🟠 | UX auth GitHub du wizard : après avoir collé le PAT, le wizard redemande quand même « Nom pour les commits » et « Email noreply GitHub » (pré-remplis), alors que le PAT donne tout via l'API. De plus, si l'utilisateur colle par erreur son token à la question o/N (au lieu de répondre o d'abord), le token est silencieusement ignoré sans message clair. | Feedback bêta-testeur 2026-07-07 (Romaric) | ✅ traité | `BACKLOG.md` T2-CH2 · `TESTS.md` S40 | +| AC-R038 | 🎛️ | 🟠 | La clé Context7 est demandée dès `albert-code install` (phase A.4), avant toute explication du MCP et avant même que l'utilisateur ait choisi de le brancher. À déplacer : ne la demander qu'au `setup`, si l'utilisateur répond Y à « Installer le MCP context7 ». Aggravant découvert à l'analyse : une clé saisie au `setup` (chemin AC-R028) est persistée dans le `~/.zshenv` hôte mais jamais propagée dans `~/.agent-vm/runtime.sh` (`ensure_vm_runtime` n'est appelé qu'en phase A) : la VM garde `CONTEXT7_API_KEY=''`. | Onboarding alpha Adrien Carpentier 2026-07-21 | ✅ traité | `BACKLOG.md` T6.15 · `TESTS.md` S-ctx-1 à S-ctx-4 | +| AC-R039 | 🎛️ | 🟡 | Les questions Y/n du `setup` (MCP notamment) n'expliquent pas assez chaque option : un libellé court entre parenthèses, pas de vraie phrase. Un testeur demande deux fois « c'est quoi Context7 ? » pendant l'onboarding. Format cible : une ligne d'explication avant chaque question, « Installer Context7 ? Context7 est un MCP qui permet de [...]. Y/n ». | Onboarding alpha Adrien Carpentier 2026-07-21 | ✅ traité | `BACKLOG.md` T6.16 · `TESTS.md` S-ctx-5 | + ## Notes - **AC-R004 (prompt caching)** : à instruire avant tout scaling. Vérifier si Albert API expose du caching sur `chat/completions` ; sinon, arbitrer l'infra d'inférence. vLLM implémente le caching nativement. diff --git a/README.md b/README.md index 8e0056c..15920c7 100644 --- a/README.md +++ b/README.md @@ -46,8 +46,8 @@ Après installation, tu disposes de la commande `albert-code` à 3 verbes : | Verbe | Action | |---|---| -| `albert-code install` | **1ʳᵉ fois** : bootstrap le poste (Lima, VM isolée, clés, skills). | -| `albert-code setup` | **Par projet** : configure un projet (AGENTS.md + opencode.json + choix skills/MCP). | +| `albert-code install` | **1ʳᵉ fois** : bootstrap le poste (Lima, VM isolée, clé Albert, skills). | +| `albert-code setup` | **Par projet, obligatoire avant le 1ᵉʳ `run`** : configure le projet (AGENTS.md + opencode.json + choix skills/MCP). | | `albert-code run` | **Lancement** : crée la VM de base si absente, puis ouvre la VM isolée. | `install.sh` est **idempotent** et **non-destructif** : il amorce le poste (Phase A) et pose le shim `albert-code`. Ensuite, c'est `albert-code setup` puis `albert-code run`. @@ -63,6 +63,8 @@ albert-code setup # configure le projet ( albert-code run # ouvre la bulle isolée + OpenCode ``` +> ⚠️ **L'ordre compte : `install` (une fois), puis `setup` (une fois par projet), puis `run`.** C'est `setup` qui pose l'`opencode.json` (provider Albert), les MCP et les skills du projet. Un `run` sans `setup` ouvre OpenCode **non connecté à Albert** (pas de `/models`, ni MCP, ni skills) : si c'est ton cas, quitte, fais `albert-code setup`, relance `albert-code run`. + Dans la bulle, l'agent tourne en mode autonome (`--dangerously-skip-permissions`), sûr parce que tout est confiné dans la VM. Tu peux lui parler en français. Les commandes exactes (avec tes valeurs) s'affichent à la fin de `albert-code setup`, sous « Prochaines étapes ». @@ -109,6 +111,33 @@ Par défaut, l'agent peut **committer** dans la VM mais **ni pusher ni ouvrir de > Le token vit dans une bulle exposée au prompt-injection : garde-le **fine-grained, scopé, révocable**, et **relis chaque PR avant merge**. Un contenu malveillant pourrait pousser l'agent à en abuser dans la limite de sa portée — d'où les permissions minimales. +## Qu'est-ce qu'une skill ? Qu'est-ce qu'un MCP ? + +Au `setup`, Albert Code te propose des **skills** et des **MCP**, à la carte : une question Y/n par brique, avec une ligne d'explication. Rien n'est imposé, rien n'est appliqué dans ton dos. + +### Qu'est-ce qu'une skill ? + +Une skill est un **mode d'emploi que l'agent charge à la demande** : un dossier d'instructions, de conventions et d'exemples pour une tâche précise. Exemples embarqués ([Skills de l'État](https://github.com/etalab-ia/skills)) : appliquer le DSFR, vérifier l'accessibilité RGAA, respecter les règles de sécurité ANSSI, utiliser les API data.gouv. + +- **Choisie au `setup`** : chaque skill est proposée en Y/n avec son objectif. La sélection est propre au projet (`.albert-code/skills.txt`). +- **Jamais appliquée automatiquement** : cocher la skill DSFR ne « DSFR-ise » pas ton projet. Une skill est une capacité en plus, que l'agent mobilise quand tu le lui demandes (« applique le DSFR à cette page ») ou quand la tâche s'y prête clairement. Ton code n'est pas modifié tant que tu ne demandes rien. +- **Réversible** : relance `albert-code setup` (ou édite `.albert-code/skills.txt`) pour changer la sélection. + +### Qu'est-ce qu'un MCP ? + +MCP (**Model Context Protocol**) est un standard qui **branche l'agent sur un outil ou un service externe**. Sans MCP, l'agent sait lire/écrire des fichiers et lancer des commandes dans la VM ; chaque MCP lui ajoute un accès structuré à une source ou un outil. + +| MCP | Ce que l'agent sait faire en plus | Clé | +|---|---|---| +| `data-gouv` | Interroger les données publiques de data.gouv.fr (catalogue, datasets, API tabulaire), en lecture. | aucune | +| `context7` | Lire la documentation à jour des librairies et frameworks pendant qu'il code. | gratuite ([context7.com/plans](https://context7.com/plans)), demandée au `setup` si tu choisis ce MCP | +| `playwright` | Piloter un navigateur headless dans la VM : ouvrir une page, cliquer, tester une UI. | aucune | +| `chrome-devtools` | Débugger le navigateur : DOM, console, requêtes réseau, performance. | aucune | + +- **Choisis au `setup`** : seuls les MCP que tu acceptes sont écrits dans l'`opencode.json` du projet. +- **La clé Context7 n'est demandée que si tu choisis ce MCP**, au moment du `setup` (jamais à l'`install`). +- Même un MCP « qui agit » (Playwright) reste confiné à la bulle : c'est l'intérêt de la VM. + ## Sécurité - **Isolation noyau (Lima)** : l'agent n'a aucun accès à tes clés SSH, credentials, cookies ou sessions de l'hôte. La VM est jetable. @@ -129,7 +158,7 @@ Par défaut, l'agent peut **committer** dans la VM mais **ni pusher ni ouvrir de Pour changer le modèle par défaut d'un projet, édite `model` dans son `opencode.json`. - **Config** : `opencode.json` de **portée projet** (jamais le global de l'utilisateur, qui peut avoir d'autres providers). - **Skills** : `etalab-ia/skills` cloné dans un cache (`~/.config/opencode/.albert-skills-cache`) et symliqué dans le dossier scanné par OpenCode. Au `setup`, chaque skill est proposée en Y/N avec son objectif. La sélection est écrite dans `.albert-code/skills.txt` à la racine du projet. Au boot de la VM, `sync_skills` ne symlinke que les skills sélectionnées puis réconcilie (retire les symlinks des skills non sélectionnées, sans jamais toucher les skills perso). Sans manifeste `.albert-code/skills.txt`, toutes les skills sont installées (rétrocompat). Mise à jour à chaque démarrage de VM. -- **MCP** : les 4 connecteurs sont désormais **tous opt-in**. Au `setup`, chaque MCP est proposé en Y/N avec son objectif : `data-gouv` (accès aux données publiques), `context7` (doc à jour des librairies, clé API requise via https://context7.com/plans), `playwright` (navigateur headless), `chrome-devtools` (debug navigateur). Seuls les MCP acceptés sont écrits dans `opencode.json` du projet (`enabled:false` par défaut). Note : le MCP `chrome-devtools` peut aussi apparaître dans OpenCode même si non coché — il est préinstallé par le moteur d'isolation en amont et n'est pas sous le contrôle d'Albert Code. +- **MCP** : les 4 connecteurs sont désormais **tous opt-in**. Au `setup`, chaque MCP est proposé en Y/N avec son objectif : `data-gouv` (accès aux données publiques), `context7` (doc à jour des librairies ; si tu le choisis, la clé gratuite est demandée à ce moment-là : https://context7.com/plans), `playwright` (navigateur headless), `chrome-devtools` (debug navigateur). Seuls les MCP acceptés sont écrits dans `opencode.json` du projet (`enabled:false` par défaut). Note : le MCP `chrome-devtools` peut aussi apparaître dans OpenCode même si non coché — il est préinstallé par le moteur d'isolation en amont et n'est pas sous le contrôle d'Albert Code. - **Conventions** : `AGENTS.md` depuis `templates/AGENTS.default.md` (sécurité, plan mode, task management, code quality, git, accessibilité). Si le projet a déjà son `AGENTS.md`, il est conservé. Docs : [OpenCode](https://opencode.ai/docs/fr) · [Albert API](https://doc.incubateur.net/alliance/albert-api) · [agent-vm](https://github.com/sylvinus/agent-vm) · [Skills État](https://github.com/etalab-ia/skills) diff --git a/TESTS.md b/TESTS.md index 3747646..681fdf7 100644 --- a/TESTS.md +++ b/TESTS.md @@ -442,3 +442,92 @@ bash pur — zéro pipe, donc pas de course SIGPIPE. 19. Vérifier que tous les changements visuels sont visibles en dry-run : art nouveau, compteur [1/4]..[4/4], récap. 20. Vérifier que le spinner n'apparaît pas (pas d'animation). **Attendu :** (18) 4 chantiers visibles en dry-run. (19) spinner dégradé, pas de caracteres d'animation. + +--- + +## S-ctx-1 — Install ne mentionne plus Context7 (T6.15, AC-R038) + +**Préconditions :** dossier sandbox `/tmp/ac-test-ctx`, `install.sh` ou `bin/albert-code install` disponible. + +**Étapes :** +1. `HOME=/tmp/ac-test-ctx OPENCODE_CONFIG_DIR=/tmp/ac-test-ctx/.config/opencode AGENT_VM_DIR=vendor/vm bash bin/albert-code install --dry-run` +2. `grep -ciE 'context7|Context7|ctx7'` sur la sortie (hors ensure_vm_runtime). +3. Vérifier qu'aucun block A.4 (prompt clé Context7) n'apparaît dans la sortie. + +**Attendu :** l'install ne mentionne pas « Context7 », ne demande pas de clé. Les seules mentions +sont dans `ensure_vm_runtime` (fallback vide), pas de prompt interactif. +**Validé le :** 2026-07-21 — `bash bin/albert-code install --dry-run` sandboxé : aucune ligne +« Context7 » ou « context7 » visible en Phase A. Le prompt de clé (A.4) a disparu. + +## S-ctx-2 — Setup Y context7 sans clé → clé demandée, persistée hôte + runtime.sh, visible VM (T6.15, AC-R038) + +**Préconditions :** aucun `CONTEXT7_API_KEY` dans l'environnement ni `~/.zshenv`. +Dossier projet vierge `/tmp/ac-test-project-ctx`. + +**Étapes :** +1. Lancer `bash bin/albert-code setup --dry-run` depuis le dossier projet. +2. Répondre `o` à context7 (via dry-run ce n'est pas possible → on vérifie le code). +3. Vérifier dans `scaffold_opencode_json` (lignes ~718-725) : si Y à context7 et clé absente, + `prompt_secret` est appelé, puis `persist_zshenv`. +4. Vérifier dans `phase_b` : `ensure_vm_runtime` appelé après B.4 → la clé fraîchement persistée + dans `~/.zshenv` est lue par le fallback de `ensure_vm_runtime` (lignes 334-335) et écrite + dans `~/.agent-vm/runtime.sh` avec la vraie valeur (pas `''`). + +**Attendu :** la clé est demandée au setup (pas à l'install), persistée dans `~/.zshenv` ET dans +`~/.agent-vm/runtime.sh`. Au `run` suivant, la VM voit `CONTEXT7_API_KEY` non vide. +**Validé le :** 2026-07-21 — code inspecté : `scaffold_opencode_json` lignes 718-725 appelle +`prompt_secret` + `persist_zshenv` ; `phase_b` ligne 188 appelle `ensure_vm_runtime` après +persistance → le fallback (lignes 334-335) lit la clé depuis `~/.zshenv` et l'écrit dans runtime.sh. + +## S-ctx-3 — Setup N à context7 → aucune question de clé (T6.15, AC-R038) + +**Préconditions :** `CONTEXT7_API_KEY` absente. + +**Étapes :** +1. Lancer `bash bin/albert-code setup --dry-run` depuis un dossier projet. +2. Répondre `n` (ou dry-run) à la question context7 → `mcp_ctx7="false"`, le bloc conditionnel + (lignes ~715-730) n'est pas exécuté. +3. Vérifier qu'aucun `prompt_secret` ni `persist_zshenv` pour `CONTEXT7_API_KEY` n'est appelé. + +**Attendu :** clé jamais demandée. Le MCP context7 n'est pas activé dans `opencode.json`. +**Validé le :** 2026-07-21 — en dry-run, le `confirm` retourne `1` (non) → `mcp_ctx7` reste `false` → pas de prompt. + +## S-ctx-4 — Re-run setup sans duplication (T6.15, idempotence) + +**Préconditions :** `~/.agent-vm/runtime.sh` existe avec le bloc marqué (écrit par un premier +`install` ou `setup`). + +**Étapes :** +1. Lancer `bash bin/albert-code setup --dry-run` une 2e fois sur le même projet. +2. Observer la sortie de `ensure_vm_runtime` : elle détecte le marqueur existant dans runtime.sh, + supprime l'ancien bloc et en réécrit un neuf avec les mêmes valeurs. +3. Vérifier qu'aucune duplication de lignes n'apparaît dans runtime.sh après réécriture : + le bloc est remplacé (pas ajouté), GH_TOKEN et l'identité git sont lus depuis env/zshenv + et réécrits à l'identique. + +**Attendu :** pas de duplication dans runtime.sh. GH_TOKEN et AC_GIT_USER_* conservés. +L'opération est idempotente. +**Validé le :** 2026-07-21 — `ensure_vm_runtime` (lignes 336-345) : si `$AC_MARKER` trouvé, + 1. sed supprime du marqueur-début à marqueur-fin (ligne 373), + 2. puis le bloc est réécrit (lignes 387-430) avec les mêmes valeurs lues depuis env/zshenv. + Pas de duplication possible. + +## S-ctx-5 — Dry-run : explications avant chaque question MCP (T6.16, AC-R039) + +**Préconditions :** dossier projet vierge `/tmp/ac-test-project-ctx`. + +**Étapes :** +1. `DRY_RUN=1 bash bin/albert-code setup --dry-run` depuis le dossier projet. +2. Observer les lignes avant chaque `confirm` MCP : + - data.gouv : `→ MCP qui permet à l'agent d'interroger les données publiques de` puis + `→ data.gouv.fr (catalogue, datasets, API tabulaire), en lecture.` puis le confirm. + - context7 : explication doc à jour des librairies + clé gratuite + demandée après. + - playwright : explication navigateur headless. + - chrome-devtools : explication debug DOM/console/réseau/perf. +3. Vérifier que chaque explain est un `info` (préfixe `→`), pas un `title` ni du texte brut. +4. Vérifier que les confirms sont courts : `Installer le connecteur ?` + +**Attendu :** chaque MCP a ≥1 ligne d'explication avant son Y/n. Les libellés sont textuellement +ceux du ticket T6.16. Aucune ligne ne dépasse 80 colonnes. Les accents sont corrects. +**Validé le :** 2026-07-21 — dry-run confirme les 4 paires explication+confirm. Textes correspondant +au ticket. Aucun tiret cadratin. `bash -n lib/phases.sh` OK. diff --git a/lib/phases.sh b/lib/phases.sh index 04e8afa..65d0b62 100644 --- a/lib/phases.sh +++ b/lib/phases.sh @@ -100,23 +100,6 @@ phase_a() { fi persist_zshenv "ALBERT_API_KEY" "$albert_key" - # A.4 Clé Context7 (optionnelle) - local ctx7_key="" - if [ -n "${CONTEXT7_API_KEY:-}" ]; then - ok "CONTEXT7_API_KEY déjà présente dans l'environnement" - ctx7_key="$CONTEXT7_API_KEY" - elif file_contains "$ZSHENV" "CONTEXT7_API_KEY"; then - ok "CONTEXT7_API_KEY déjà présente dans ~/.zshenv" - ctx7_key="<>" - else - echo - info "Connecteur context7 (doc des librairies à jour) — clé gratuite : https://context7.com/plans" - ctx7_key="$(prompt_secret "Clé Context7 (optionnelle, Entrée pour ignorer)")" - fi - persist_zshenv "CONTEXT7_API_KEY" "$ctx7_key" - - echo - # GitHub PAT (optionnel) — gestions des 3 cas : activation, token, dérivation _github_auth @@ -186,6 +169,10 @@ phase_b() { title "[4/4] Runtime VM" copy_template "runtime/agent-vm.runtime.sh" "./.agent-vm.runtime.sh" "runtime VM (sync skills + clés)" apply "chmod +x .agent-vm.runtime.sh" chmod +x "./.agent-vm.runtime.sh" 2>/dev/null || true + # Synchroniser les clés potentiellement persistées par le setup (ex. Context7) + # vers le runtime VM (~/.agent-vm/runtime.sh). ensure_vm_runtime est idempotent : + # il remplace le bloc marqué sans dupliquer et sans écraser GH_TOKEN / identité git. + ensure_vm_runtime compute_effective_vm_resources echo @@ -688,16 +675,27 @@ scaffold_opencode_json() { local mcp_data_gouv="false" mcp_ctx7="false" mcp_playwright="false" mcp_chrome="false" - if confirm "Brancher le MCP data.gouv (accès aux données publiques en lecture) ?"; then + info "MCP qui permet à l'agent d'interroger les données publiques de" + info "data.gouv.fr (catalogue, datasets, API tabulaire), en lecture." + if confirm "Installer le connecteur data.gouv ?"; then mcp_data_gouv="true" fi - if confirm "Brancher le MCP context7 (doc à jour des librairies — clé API requise) ?"; then + echo + info "MCP qui donne à l'agent la documentation à jour des librairies" + info "et frameworks pendant qu'il code. Clé gratuite (https://context7.com/plans)," + info "demandée juste après si tu acceptes." + if confirm "Installer le connecteur Context7 ?"; then mcp_ctx7="true" fi - if confirm "Brancher le MCP playwright (piloter un navigateur / agir dans une page) ?"; then + echo + info "MCP qui permet à l'agent de piloter un navigateur headless dans" + info "la VM (ouvrir une page, cliquer, tester une UI)." + if confirm "Installer le connecteur Playwright ?"; then mcp_playwright="true" fi - if confirm "Brancher le MCP chrome-devtools (debug navigateur : DOM, console, réseau, perf) ?"; then + echo + info "MCP de debug navigateur : DOM, console, requêtes réseau, performance." + if confirm "Installer le connecteur Chrome DevTools ?"; then mcp_chrome="true" fi