Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 42 additions & 0 deletions BACKLOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -480,6 +480,48 @@ Option : ajouter un paramètre `install_shim` pour mode "exec" vs "source", ou d
**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é

---

## EPIC 8 — Rafraîchir les fichiers projet figés au setup

**Problème de fond :** Au `albert-code setup`, les fichiers posés dans le projet (AGENTS.md, opencode.json, .agent-vm.runtime.sh) sont **conservés** s'ils existent — les évolutions du template ne redescendent **jamais** aux projets déjà configurés. Symptômes déjà vus : opencode.json conservé sans provider Albert (T1.6/T7.7), runtime projet ancien + OpenCode 1.2.9 dans la VM → `opencode --auto` inconnu → écran de help au lieu du TUI (AC-R041).

**Fait de code clé :** Le SEUL fichier rafraîchi à l'existant est le runtime USER `~/.agent-vm/runtime.sh` : son bloc marqué (`$AC_MARKER … $AC_MARKER_END`) est réécrit par `ensure_vm_runtime()` à chaque phase A ET B. Toute logique évolutive doit passer par là.

### T8.1 🟡 (doc) Convention zone gérée vs fichiers figés

**But :** Documenter dans ce ticket l'architecture de rafraîchissement du bundle, pour que tout contributeur sache où et comment ajouter une logique évolutive.

**Architecture de rafraîchissement :**
| Fichier | Rafraîchi ? | Mécanisme | Pourquoi |
|---|---|---|---|
| `~/.agent-vm/runtime.sh` bloc marqué | ✅ Oui, à chaque phase A ET B | `ensure_vm_runtime()` supprime le bloc `$AC_MARKER … $AC_MARKER_END` et le réécrit | Clés API + GH_TOKEN doivent être à jour au boot VM |
| `./opencode.json` | 🟡 Merge conditionnel (T8.2) | Si `jq` présent → merge provider.albert dans existant, sinon avertissement | Provider Albert doit pouvoir être ajouté sans écraser les MCP/permissions |
| `./AGENTS.md` | ❌ Non (jamais écrasé) | `copy_template()` → non-destructif pur | Le projet peut avoir un AGENTS.md personnalisé |
| `./.agent-vm.runtime.sh` (projet) | ❌ Non (jamais écrasé) | `copy_template()` → non-destructif pur | Idem, fichier figé chez l'existant |
| `vendor/vm/` (moteur VM) | ❌ Non (vendored figé) | Versionné dans le repo albert-code | Mis à jour par `git pull` du dépôt albert-code |
| `templates/` | ❌ Non (versionnés) | Versionné dans le repo | Utilisés uniquement au premier `setup` |

**DoD :** cette documentation est présente dans `BACKLOG.md`.

### T8.2 🟠 opencode.json — réparer, pas seulement avertir (généralise T1.6/T7.7)

**But :** Dans `scaffold_opencode_json()`, branche « fichier existe sans albert » (ajoutée par T7.7) : si `jq` est présent, proposer (confirm) puis **merger** `provider.albert` + `model` + `small_model` du template dans l'`opencode.json` existant, sans toucher les autres clés (MCP, permissions, autres providers). Sauvegarder l'original (`.bak`). Si `jq` absent → garder l'avertissement T7.7 (fallback). Non-destructif.

**DoD :** `opencode.json` perso avec provider scaleway → après setup, provider albert ajouté ET scaleway préservé. → `TESTS.md` S46.

### T8.3 🟠 Garde-fou version OpenCode dans le bloc marqué du runtime USER (absorbe AC-R041)

**But :** `ensure_vm_runtime()` écrit un garde-fou exécuté dans la VM au boot, à l'intérieur du bloc marqué `~/.agent-vm/runtime.sh` (après les exports, avant `$AC_MARKER_END`). Logique : capture `opencode --help`, si `--auto` absent → upgrade auto.

**DoD :** VM avec opencode trop vieux → au boot, upgrade auto → `run` ouvre le TUI, plus de help. → `TESTS.md` S47 `<- AC-R041`.

### T8.4 🟡 (OPTION, nice-to-have) Verbe `albert-code update` pour rafraîchir un projet existant

**But :** Proposer un verbe simple pour rafraîchir un projet existant sans repasser tout le setup interactif. `albert-code update` (ou `--update`) exécute les logiques de rafraîchissement (T8.2 merge opencode.json + T8.3 garde-fou runtime) sans les questions MCP/skills. Non implémenté dans cette EPIC, ouvert pour le futur.

**DoD :** ticket documenté mais pas 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 :**
Expand Down
1 change: 1 addition & 0 deletions FEEDBACK.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@
| 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 |
| AC-R040 | 🎛️ | 🟠 | `albert-code run` dans un dossier jamais `setup` (pas de `opencode.json`) — ou avec un `opencode.json` sans provider `albert` — ouvre OpenCode sur ses modèles par défaut, **Albert absent de `/models`, sans aucune alerte**. 2 bêta-testeurs piégés (dont un power user), longue session de debug à chaque fois. Généralise T1.6 au cas « pas de fichier ». Fix : garde-fou au `run` (avertit + confirmation avant de lancer sans Albert) + avertissement au `setup` sur fichier existant sans `albert`. | Bêta-testeur 2026-07-21 (Julien Bouquillon, dossier pres-gafam) | ✅ traité | `BACKLOG.md` T7.7 · `TESTS.md` S44, S45 |
| AC-R041 | 🐛 | 🟠 | `albert-code run` ouvre l'écran de help d'OpenCode au lieu du TUI quand la VM a une version d'OpenCode trop ancienne (ex 1.2.9) qui ne connaît pas le flag `--auto` lancé par le moteur VM (`vendor/vm/agent-vm.sh:1167`). Le runtime valide la présence d'OpenCode mais pas la compatibilité `--auto`. Source : bêta-testeur Julien Bouquillon, VM betabot2, 2026-07-21. | Bêta-testeur 2026-07-21 (Julien Bouquillon, VM betabot2) | ✅ traité | `BACKLOG.md` T8.3 · `TESTS.md` S47 |

## Notes

Expand Down
59 changes: 59 additions & 0 deletions TESTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -557,3 +557,62 @@ L'opération est idempotente.
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.

---

## S46 — Merge provider Albert dans opencode.json existant (T8.2)

**Préconditions :** `jq` installé sur le PATH ; un dossier projet avec un `opencode.json` contenant
un provider non-Albert (ex. Scaleway) et des MCP + permissions, sans `"albert"`.

**Étapes :**
1. Créer un fichier `opencode.json` de test avec un provider Scaleway :
```json
{
"provider": { "scaleway": { "npm": "@ai-sdk/scaleway", "name": "Scaleway", "options": { "baseURL": "https://api.scaleway.ai/v1", "apiKey": "{env:SCW_API_KEY}" } } },
"mcp": { "data-gouv": { "type": "remote", "url": "https://mcp.data.gouv.fr/mcp", "enabled": true } },
"permission": { "edit": "allow", "bash": {".*":"allow"} }
}
```
2. Lancer `bash bin/albert-code setup --dry-run` dans ce dossier.
3. Observer la sortie : proposition de merge, dry-run affiche `[dry-run] merge du provider albert dans opencode.json`.
4. Relancer en réel (`DRY_RUN=0` avec un HOME sandboxé) et répondre `o` au confirm.
5. Vérifier le fichier résultant :
- Provider `albert` présent avec ses 3 modèles
- Provider `scaleway` toujours présent (non écrasé)
- MCP `data-gouv` toujours présent
- La sauvegarde `.bak` existe et contient l'original
6. Relancer le setup : le fichier est détecté comme ayant `"albert"` → message « conservé (non écrasé) ».

**Attendu :** (3) proposition affichée. (4) jq merge réussi. (5) les 3 vérifications passent — albert ajouté, scaleway intact, MCP intact, .bak présent. (6) idempotent, pas de duplication. Sans `jq` → avertissement T7.7 inchangé + info « installe jq ».

## S47 — Garde-fou OpenCode --auto dans la VM (T8.3, AC-R041)

**Préconditions :** `~/.agent-vm/runtime.sh` existe (post-install) ; une VM avec une version
ancienne d'OpenCode (ex. 1.2.9) ne supportant pas `--auto`.

**Étapes (validation du code injecté) :**
1. Lancer `bash bin/albert-code install --dry-run` (ou setup) → le bloc marqué de `ensure_vm_runtime`
est réécrit avec le garde-fou T8.3.
2. Inspecter `~/.agent-vm/runtime.sh` (ou `/tmp/ac-test/.agent-vm/runtime.sh` sandboxé) :
le bloc `$AC_MARKER … $AC_MARKER_END` contient les lignes :
```
_oc_help="$(opencode --help 2>&1 || true)"
case "$_oc_help" in
*--auto*) : ;;
*) echo "OpenCode trop ancien pour --auto - mise a jour..."; opencode upgrade || true ;;
esac
unset _oc_help
```
3. Vérifier qu'elles sont placées APRÈS les exports et AVANT `$AC_MARKER_END`.

**Validation réelle (VM) :**
4. Démarrer une VM où opencode est une ancienne version (simulable en renommant `opencode` ou
en installant une version antérieure) → au boot, le runtime `~/.agent-vm/runtime.sh` s'exécute :
`opencode --help` ne contient pas `--auto` → le garde-fou déclenche `opencode upgrade` → après
upgrade, `opencode --auto` fonctionne → le TUI s'affiche au lieu du help.
5. Même VM avec opencode à jour → le `case` matche `--auto` → no-op, pas d'upgrade.
6. Vérifier que le garde-fou est en `|| true` : un échec d'upgrade ne casse pas le boot.

**Attendu :** (2)(3) le code injecté est correctement placé. (4) opencode 1.2.9 → upgrade auto → TUI.
(5) opencode à jour → no-op. (6) un échec (hors-ligne, etc.) n'empêche pas le runtime de continuer.
54 changes: 51 additions & 3 deletions lib/phases.sh
Original file line number Diff line number Diff line change
Expand Up @@ -427,6 +427,20 @@ ensure_vm_runtime() {
apply_append "export AC_GIT_USER_EMAIL dans runtime.sh" "$RUNTIME_VM_FILE" \
"export AC_GIT_USER_EMAIL='${safe_email}'"
fi
# T8.3: Garde-fou OpenCode --auto execute dans la VM au boot
# Si opencode est trop ancien pour --auto, upgrade auto.
apply_append "garde-fou OpenCode --auto (T8.3)" "$RUNTIME_VM_FILE" \
" _oc_help=\"\$(opencode --help 2>&1 || true)\""
apply_append "garde-fou OpenCode --auto (T8.3)" "$RUNTIME_VM_FILE" \
" case \"\$_oc_help\" in"
apply_append "garde-fou OpenCode --auto (T8.3)" "$RUNTIME_VM_FILE" \
" *--auto*) : ;;"
apply_append "garde-fou OpenCode --auto (T8.3)" "$RUNTIME_VM_FILE" \
" *) echo \"OpenCode trop ancien pour --auto - mise a jour...\"; opencode upgrade || true ;;"
apply_append "garde-fou OpenCode --auto (T8.3)" "$RUNTIME_VM_FILE" \
" esac"
apply_append "garde-fou OpenCode --auto (T8.3)" "$RUNTIME_VM_FILE" \
" unset _oc_help"
apply_append "albert-code block end" "$RUNTIME_VM_FILE" "$AC_MARKER_END"
fi

Expand Down Expand Up @@ -682,9 +696,43 @@ scaffold_opencode_json() {
if grep -q '"albert"' "$dest" 2>/dev/null; then
warn "%s existe déjà — conservé (non écrasé)" "$dest"
else
# T1.6 : fichier existant sans provider Albert → footgun silencieux.
warn "%s existe déjà mais ne déclare pas le provider Albert — conservé (non écrasé)." "$dest"
info "Albert ne sera pas câblé dans ce projet. Ajoute le bloc provider \"albert\" (voir README), ou renomme/supprime ce fichier puis relance albert-code setup."
# T8.2 (generalise T1.6/T7.7) : tenter le merge du provider albert
if command -v jq >/dev/null 2>&1; then
warn "%s existe déjà sans provider Albert — proposition de merge." "$dest"
info "Le provider Albert (et model/small_model) peuvent etre ajoutes sans ecraser"
info "tes MCP, permissions ou autres providers (ex. Scaleway)."
if confirm "Ajouter le provider Albert dans opencode.json ?"; then
local _bak="${dest}.bak"
apply_cp "sauvegarder ${dest} vers ${_bak}" "$dest" "$_bak"
if [ "$DRY_RUN" -eq 1 ]; then
info "[dry-run] merge du provider albert dans ${dest}"
# jq : ajoute provider.albert + model + small_model, preserve le reste.
# Le message de succes n'est affiche que si le merge a reellement abouti.
elif jq '.provider.albert = {
"npm": "@ai-sdk/openai-compatible",
"name": "Albert API (État)",
"options": {"baseURL": "https://albert.api.etalab.gouv.fr/v1", "apiKey": "{env:ALBERT_API_KEY}"},
"models": {
"mistralai/Mistral-Medium-3.5-128B": {"name": "Mistral Medium 3.5 (Albert)", "limit": {"context": 131072, "output": 65536}},
"deepseek-ai/DeepSeek-V4-Flash": {"name": "DeepSeek V4 Flash (Albert)", "limit": {"context": 393216, "output": 65536}},
"Qwen/Qwen3.6-27B": {"name": "Qwen 3.6 27B (Albert)", "limit": {"context": 262144, "output": 65536}}
}
} | .model = "albert/mistralai/Mistral-Medium-3.5-128B" | .small_model = "albert/deepseek-ai/DeepSeek-V4-Flash"' "$dest" > "${dest}.tmp" 2>/dev/null && mv "${dest}.tmp" "$dest"; then
ok "Provider Albert ajoute dans ${dest}. Sauvegarde dans ${_bak}"
else
warn "Echec du merge jq (JSON invalide ? ex. commentaires) - fichier restaure, Albert non cable."
mv "$_bak" "$dest" 2>/dev/null || true
info "Ajoute le bloc provider \"albert\" manuellement (voir README)."
fi
else
info "Provider Albert non ajoute. Utilise albert-code setup plus tard ou ajoute-le manuellement."
fi
else
# Fallback T7.7 : jq absent, simple avertissement
warn "%s existe déjà mais ne déclare pas le provider Albert — conservé (non écrasé)." "$dest"
info "Albert ne sera pas câblé dans ce projet. Ajoute le bloc provider \"albert\" (voir README), ou renomme/supprime ce fichier puis relance albert-code setup."
info "Astuce : installe jq pour que albert-code puisse merger automatiquement."
fi
fi
return 0
fi
Expand Down
Loading