Commit graph

649 commits

Author SHA1 Message Date
233fdf2d2b [IMP] script todo: suivi install — colonne État moins large (12 -> 10)
La colonne « État » réservait 12 caractères alors que le plus long libellé
(«  effacée ») en fait 10 -> elle paraissait trop large. Ramenée à 10
(sans troncature).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-30 03:10:04 -04:00
e8c60a2d46 [FIX] install: apt lock — réessayer « update » (DPkg::Lock::Timeout insuffisant)
Le fix précédent (DPkg::Lock::Timeout) ne suffisait pas : cette option NE
couvre PAS le verrou /var/lib/apt/lists/lock de « apt-get update ». Au 1er
boot, cloud-init/apt-daily tient ce verrou -> update échouait AUSSITÔT
-> lists vides -> « Unable to locate package git » (exit 100), toujours sur
debian-12.

On RÉESSAIE désormais « apt-get update » jusqu'à libération du verrou (et
lists peuplées), borné à ~5 min (30×10s), avant l'install. Une fois update
OK, git/make s'installent normalement.

Note : le remote_cmd est construit côté HÔTE -> relancer le CLI todo pour
que la nouvelle commande soit envoyée aux VM.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-30 02:36:31 -04:00
bcb77df2d3 [IMP] script todo: suivi install — colonne # (séquence) + max de durée
- Nouvelle 1re colonne « # » : numéro de séquence de chaque VM.
- Sommaire enrichi du « max » de durée : la VM TERMINÉE la plus lente
  (pire cas), à côté du temps global et de l'ETA.

Validé headless : # = 1..N, sub_title « … · max MM:SS ».

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-30 02:30:29 -04:00
808e37cd59 [IMP] script todo: déploiement — choix dev/prod (/opt + SELinux confiné en prod)
Au déploiement (« Déployer une ou plusieurs VM »), après le choix de la
branche, on demande l'ENVIRONNEMENT cible (dev par défaut / prod).

- DEV : ERPLibre dans ~/git/erplibre ; service systemd unconfined si
  SELinux actif (comportement inchangé).
- PROD : ERPLibre dans /opt/erplibre (sudo git clone + chown à
  l'utilisateur) ; service systemd CONFINÉ par SELinux (pas d'unconfined)
  + restorecon des contextes -> hors user_home_t, un service peut exécuter
  le contenu sans lever le confinement.

Le drapeau `prod` est propagé : _qemu_deploy -> _qemu_install_erplibre_
monitored/_vm -> _qemu_erplibre_remote_cmd -> _qemu_odoo_service_cmd.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-30 02:09:29 -04:00
43d268e448 [FIX] install: poetry — rejeu -vvv (et non -v) à l'échec pour la vraie cause
« -v » montre l'étape mais pas la sortie des sous-processus. Seul « -vvv »
(debug) affiche git clone/checkout et le build pip -> l'erreur réelle d'une
dépendance VCS/build. Le rejeu de diagnostic passe donc en -vvv.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-30 01:56:04 -04:00
64c0bbc698 [FIX] install: revue 13 VM — apt lock, wkhtmltopdf trixie, SELinux, poetry
Corrections issues de la revue complète des 13 VM (6 en échec réel) :

- APT lock (debian-12) : au 1er boot, cloud-init/apt-daily tient le verrou
  et « apt-get install » échouait aussitôt. Ajout de
  « -o DPkg::Lock::Timeout=600 » (update + install) -> attend le verrou.

- wkhtmltopdf Debian 13 « trixie » (debian-13) : on prenait le build
  « bullseye » (dépend de libssl1.1, absent de trixie) -> gdebi échouait.
  Désormais bookworm pour bookworm/trixie/+. ET l'échec gdebi est NON
  bloquant (avertissement au lieu d'exit 1 : wkhtmltopdf est optionnel,
  sinon tout install_os avortait et Odoo n'était jamais installé).

- SELinux 203/EXEC (fedora-41/43/44) : un service système ne peut pas
  exécuter run.sh/venv sous /home (contexte user_home_t). Ajout
  conditionnel de « SELinuxContext=unconfined_u:unconfined_r:unconfined_t:s0 »
  au service (uniquement si getenforce != Disabled).

- poetry status 1 (ubuntu-2604) : « -q » masquait la cause. À l'échec, on
  rejoue « poetry install -v » pour capturer l'erreur dans le log.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-30 01:52:55 -04:00
7904c72d71 [IMP] script todo: suivi install — colonne « Odoo » (état :8069)
Nouvelle colonne « Odoo » dans le dashboard : teste par TCP si l'UI web
répond sur le port 8069 de la VM (🟢 up / — sinon). Une fois « up »
détecté, on ne re-teste plus (Odoo ne redescend pas en cours d'install).
Le test (socket, timeout 0,5 s) est fait dans le thread collecteur ->
n'impacte pas la fluidité de l'UI.

Validé headless : port ouvert -> 🟢, fermé -> —.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-30 01:52:55 -04:00
1ebf2b353f [FIX] qemu: Fedora image robuste (miroirs) + silence du bruit virtinst
Déploiement PARALLÈLE de 13 VM -> 2 problèmes observés :

1. « Aucune image Fedora-Cloud-Base-Generic pour Fedora 42 » alors que
   l'image EXISTE. download.fedoraproject.org est un redirecteur
   (MirrorManager) : sous requêtes parallèles, une VM tombait sur un miroir
   incomplet -> index HTML sans correspondance -> sys.exit.
   resolve_fedora_url réessaie (2× le redirecteur) puis se replie sur le
   serveur MAÎTRE dl.fedoraproject.org (toujours complet). Validé : F41/F42
   résolus.

2. Pavé « Fetched capabilities … » (énorme XML) dans la sortie : erreur de
   LOGGING de virtinst — sous sudo, HOME/cache inaccessible -> échec
   d'écriture du journal debug -> Python déverse l'enregistrement raté.
   On préfixe virt-install de « env XDG_CACHE_HOME=… HOME=… » (traverse
   sudo) vers un cache écrivable -> journal silencieux.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-30 01:41:17 -04:00
b99db0ea66 [FIX] script todo: suivi install — navigation fluide (tail + debounce)
Cause des GROS ralentissements en changeant de VM / lisant les logs :
- on_data_table_row_highlighted rechargeait le log à CHAQUE mouvement du
  curseur (donc en rafale quand on tient la flèche) ;
- _load_selected_log(reset) lisait le fichier ENTIER (offset 0) et écrivait
  TOUTES les lignes dans le RichLog, SYNCHRONE sur la boucle d'événements
  -> un log de 250 Ko / plusieurs milliers de lignes gelait l'UI, × chaque
  pas de navigation.

Corrections :
- _read_tail : au changement de VM on ne lit que la FIN du log (128 Ko /
  1000 lignes max) et on cale l'offset sur la taille totale -> le suivi
  incrémental continue depuis la fin. Affichage quasi instantané.
- Debounce (0,25 s) : RowHighlighted mémorise seulement la cible ; on ne
  charge qu'une fois le curseur stabilisé, et uniquement la DERNIÈRE VM.

Validé headless : 2 flèches rapides -> 1 seul chargement (VM finale),
1000 lignes affichées au lieu de 8000.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-30 01:31:00 -04:00
fd3226a053 [REV] script todo: suivi install — revert auto-refresh coupé par défaut (4f0c3cd)
L'auto-refresh coupé par défaut était une mauvaise idée : (1) les lags
persistaient malgré tout ; (2) une fois coupé, on ne voyait plus
l'avancement (et l'activation ne suffisait pas). On revient au
comportement précédent : rafraîchissement automatique TOUJOURS actif
(logs 1s / table 2s / domstate 10s) — au moins on voit la progression.

Revert de 4f0c3cd. L'analyse du VRAI ralentissement (navigation / logs)
est traitée séparément.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-30 01:28:06 -04:00
bea9a82d75 [IMP] script todo: redimension — avertir de la taille max soutenable (hôte)
À l'agrandissement, on indique désormais l'espace libre de l'hôte et la
taille virtuelle MAX « soutenable » ≈ (taille réelle actuelle + libre
hôte) — affichée AVANT la saisie pour guider le choix. Si la cible la
dépasse, avertissement NON bloquant : le qcow2 est creux, donc OK tant que
la VM ne remplit pas, mais au-delà l'hôte tomberait à court d'espace.

Ex. : réel 115G + libre 30G -> max soutenable ~145G ; viser 190G affiche
« dépasse de ~45G — surallocation ». L'opération n'est pas bloquée.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-30 01:08:13 -04:00
ae3745a22a [FIX] qemu: forcer LC_ALL=C sur virsh/sgdisk/… (locale fr cassait l'état des VM)
Sur un hôte en français, « virsh domstate » renvoie « en cours d'exécution »
au lieu de « running ». Le test « state == "running" » échouait donc :
l'agrandissement à chaud tombait dans la branche « qemu-img resize » (au
lieu de « virsh blockresize ») sur une VM ALLUMÉE -> « Failed to get write
lock ».

On force désormais LC_ALL=C / LANG=C (via _qemu_c_env) sur tous les outils
dont on PARSE la sortie, pour avoir l'anglais quelle que soit la locale :
virsh domstate/domname/dominfo/domblklist/list, sgdisk -i, dumpe2fs,
resize2fs -P (todo.py) et virsh list --all (dashboard). Cela répare aussi,
en locale fr, la détection d'état (pause/éteinte), l'analyse des infos
avancées (CPU/RAM) et le parsing de la réduction (partition/GPT).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-30 01:04:07 -04:00
8be034f25e [IMP] script todo: réduction — sauvegarde optionnelle + effacement du backup
Trois améliorations autour de la sauvegarde de disque à la réduction :

- La sauvegarde .bak n'est plus systématique : on DEMANDE (défaut OUI)
  « Sauvegarder le disque avant réduction ? ». Si non, avertissement (un
  échec pourrait casser le disque, pas de restauration possible).
- À la FIN, après avoir proposé de démarrer la VM (donc après test manuel
  possible), on propose d'EFFACER la sauvegarde (défaut NON -> on la garde
  par prudence).
- « Nettoyer QEMU » détecte désormais les sauvegardes *.qcow2.bak (libellé
  « sauvegarde de disque (redim.) ») et permet de les effacer.

_qemu_shrink_revert gère l'absence de sauvegarde (avertit de lancer fsck
au lieu de restaurer). Validé de bout en bout sur image jetable.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-30 00:48:42 -04:00
c9ec5b98b9 [FIX] script todo: réduction — détection de partition robuste (FSTYPE vide)
« Partition à réduire introuvable » sur une vraie VM : _qemu_root_part
parsait lsblk en positionnel et EXIGEAIT 4 colonnes. Juste après le connect
nbd, le FSTYPE n'est pas encore en cache -> colonne VIDE -> 3 tokens ->
toutes les partitions étaient ignorées. (Le test initial passait car le FS
avait eu le temps d'être détecté.)

- lsblk -P (paires clé="valeur") : robuste aux colonnes vides ; on repère
  la partition par TYPE="part" et on sonde le FSTYPE via blkid si absent.
- _qemu_nbd_connect attend l'APPARITION des sous-périphériques nbdNpM
  (jusqu'à ~15 s) avant de rendre la main.
- partprobe silencieux (capture) -> plus de spam « Invalid argument during
  seek » pendant la réparation GPT.

Validé sur image jetable au layout cloud (p1 root + p14 bios + p15 ESP),
détection immédiate après connect : 25G -> 15G, GPT « No problems found »,
partitions préservées, fsck propre.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-30 00:41:54 -04:00
545193d293 [FIX] qemu: disque minimum 20G (10G -> poetry « disk full » sur ubuntu-2004)
erplibre-ubuntu-2004 (déployée à 10G) plantait à l'install : « Poetry
installation error status 1 » car le disque était plein (9.7G/10G). Un
ERPLibre + Odoo occupe ~11G, plus le transitoire (caches pip, sync repo,
sources Odoo). Preuve : la VM à 15G réussissait, celle à 10G non.

Plancher relevé à 20G pour TOUTES les versions (ubuntu 20.04/22.04,
debian, fedora, arch). Le qcow2 est CREUX (sparse) : une taille virtuelle
plus grande ne consomme rien tant qu'elle n'est pas remplie -> aucun
surcoût réel, marge confortable pour l'installation.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-30 00:41:54 -04:00
9fb24e583a [FIX] script todo: réduction disque via qemu-nbd (libguestfs cassé sur l'hôte)
La réduction « sûre » via virt-resize ne marchait pas : (1) j'utilisais
« virt-filesystems -b » (option INEXISTANTE -> aucune partition détectée ->
« abandon »), et (2) libguestfs est inutilisable ici (aucun vmlinuz dans
/boot -> l'appliance supermin échoue). La VM restait donc à 25G.

Réécriture SANS libguestfs, avec des outils de base présents et éprouvés
(qemu-nbd, e2fsck, resize2fs, sgdisk, parted/partprobe) :
1. copie .bak AVANT toute modification ;
2. nbd + détection de la racine (plus grosse partition, ext seulement) ;
3. e2fsck -> resize2fs (FS) -> sgdisk réécrit la partition en PRÉSERVANT
   type/UUID/nom (PARTUUID intact) -> qemu-img --shrink (conteneur) ->
   sgdisk -e (GPT de secours) -> fsck final ;
4. en cas d'échec à N'IMPORTE quelle étape : restauration depuis .bak
   -> corruption impossible.

Validé de bout en bout sur une image jetable (GPT + ext4, racine à offset
élevé, 800M de données) : 25G -> 15G, GPT « No problems found », fsck
propre, UUID préservé, données intactes.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-30 00:34:45 -04:00
0b02e9fe43 [IMP] script todo: QEMU — rouvrir le suivi d'installation (dernier run / historique)
Si le dashboard se ferme (bug, sortie), on peut désormais le ROUVRIR sur un
run passé pour reprendre l'analyse. Nouvelle entrée [11] du menu QEMU :
« 📈 Rouvrir le suivi d'installation (dernier run / historique) ».

- mon.list_install_runs() : liste les runs (~/.erplibre/qemu-install/*/
  session.json) triés du plus récent au plus ancien.
- _qemu_reopen_monitor : affiche l'historique (VM par run), choix (défaut =
  le dernier), puis run_monitor(session.json) rouvre le dashboard.
- « Lister les images » passe de [11] à [12] ; config -> 13+.

Validé : 20 runs listés, dashboard reconstruit (titre + 5 VM) depuis un
session.json passé.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-30 00:22:37 -04:00
4f0c3cd217 [IMP] script todo: suivi install — auto-refresh coupé par défaut (moins de lag)
Sur un gros parc, les ticks périodiques (logs 1s / table 2s / domstate 10s)
causaient du lag à la lecture des logs. Nouveau bouton « a » pour couper/
activer le rafraîchissement automatique, COUPÉ par défaut ; « r » pour
rafraîchir une seule fois à la demande.

- Chaque tick est scindé en wrapper _tick_* (ne fait rien si auto coupé) +
  corps _do_* (le travail réel), réutilisable pour les rafraîchissements
  forcés (init à l'ouverture, toggle, refresh manuel, après pause/reprise).
- Un relevé initial unique (table + domstate) à l'ouverture affiche l'état
  courant même auto coupé ; changer de VM recharge son log (synchrone).
- Indicateur #autobar : « ⏸ Rafraîchissement auto : COUPÉ (a=activer ·
  r=rafraîchir) » / « ▶ … : ACTIVÉ (a=couper) ».

Validé headless : défaut OFF, toggle a, refresh r, table peuplée à l'init.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-30 00:14:58 -04:00
c60b3f5cbd [IMP] script todo: dashboard de suivi — défaut OUI
« Suivi interactif (dashboard) ? » répondait NON par défaut (réponse vide).
Le défaut est désormais OUI : nouveau helper _is_yes_default_yes (vide = oui)
et libellé « (O/n, défaut : oui) » / « (Y/n, default: yes) ».

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-30 00:09:37 -04:00
e3c548e57b [IMP] script todo: libguestfs dans le profil « ERPLibre Déploiement »
virt-resize/virt-filesystems (requis pour la réduction SÛRE de disque) sont
des binaires SYSTÈME (OCaml), pas des paquets Python : ils ne peuvent pas
vivre dans .venv.erplibre. On les ajoute donc au jeu de paquets système du
profil « ERPLibre Déploiement » (à côté de qemu/libvirt/virtinst) :
apt libguestfs-tools · dnf guestfs-tools · pacman libguestfs.

Ainsi tout hôte provisionné avec ce profil peut réduire un disque sans
risque. (La commande de redimensionnement propose déjà d'installer
libguestfs à la demande si absent.)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-30 00:04:51 -04:00
9b00de6d8b [FIX] script todo: réduction disque SÛRE via virt-resize (ne casse plus l'OS)
Réduire avec « qemu-img resize --shrink » tronquait le conteneur qcow2 SANS
réduire le FS/partition/GPT invités : partition racine tronquée + GPT de
secours perdue -> dracut-initqueue en échec, OS non bootable.

Désormais la réduction passe par virt-resize (libguestfs) qui réduit
proprement système de fichiers + partition + GPT :
- _qemu_safe_shrink : écrit dans une NOUVELLE image (qemu-img create +
  virt-resize --shrink <partition>), et ne remplace l'originale (mv) QUE si
  virt-resize réussit. En cas d'échec/refus, le disque d'origine reste
  INTACT (impossible de corrompre). Sauvegarde conservée en .bak.
- _qemu_largest_partition : détecte la partition racine (la plus grosse) via
  virt-filesystems.
- _qemu_install_libguestfs : propose d'installer libguestfs-tools si absent ;
  sinon on ABANDONNE (on ne tronque jamais).
- _qemu_offer_start extrait (redémarrage après extinction).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-30 00:01:30 -04:00
7e89fa354f [FIX] install: propager l'échec au code de sortie (faux du suivi corrigé)
update_env_version.py (cible « make install_odoo_XX ») calculait un statut
mais ne faisait JAMAIS sys.exit() et IGNORAIT le retour de
update_environment() (l'install réelle : venv/poetry). Résultat : même
quand install_locally.sh échouait (ex. poetry status 127), le script
sortait 0 -> make 0 -> remote « && » continuait (service créé) ->
__ERPLIBRE_EXIT__ 0 -> le suivi d'installation affichait  à tort.

- main() suit un exit_code : install_system() ou update_environment()
  renvoyant une valeur non nulle (os.system : 0 = succès) -> exit_code=1.
- sys.exit(main() or 0) propage réellement l'échec.
- Étapes post-install (pycharm, git_repo_update, generate_config) exécutées
  seulement si l'install a réussi (sinon .venv.erplibre absent -> cascade
  d'erreurs).

Chaîne désormais complète : install_locally.sh exit 1 -> install_locally_
dev.sh exit 1 -> os.system != 0 -> install_erplibre != 0 ->
update_environment != 0 -> main exit_code=1 -> sys.exit(1) -> make échoue
-> remote && stoppe -> __ERPLIBRE_EXIT__ != 0 -> dashboard .

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-30 03:49:56 +00:00
0f50c524db [FIX] install: wkhtmltopdf — URL vide sur Ubuntu 26.04 (gdebi sans fichier)
Sur erplibre-ubuntu-2604 (Ubuntu 26.04), wkhtmltopdf ne s'installait pas :
la liste de versions s'arrêtait à 25.10, donc WKHTMLTOX_X64 restait VIDE
-> « sudo gdebi $(basename '') » -> « Usage: gdebi… » -> erreur -> Odoo :
« You need Wkhtmltopdf to print a pdf ».

- Bloc Ubuntu réécrit : 18.04->bionic, 20.04->focal, ELSE->jammy (build le
  plus récent publié par wkhtmltopdf, valable 22.04..26.04 et au-delà).
  Un « else » évite toute URL vide sur une future version.
- Garde-fou : si l'URL est vide malgré tout, on saute proprement
  (wkhtmltopdf est optionnel) au lieu d'appeler gdebi sans fichier.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-30 03:44:40 +00:00
c9b51998a4 [FIX] install: shfmt cassait tout l'apt-get sur Ubuntu < 22.04 (pas de gcc -> pyenv KO)
Sur erplibre-ubuntu-2004, l'installation ERPLibre plantait : pyenv ne
pouvait pas compiler Python 3.12.10 (« no acceptable C compiler found »),
car build-essential n'était jamais installé.

Cause : shfmt figurait dans le MÊME « apt-get install » que build-essential
(git, cmake, …). shfmt est absent des dépôts Ubuntu < 22.04 -> apt refuse
le lot ENTIER (« Unable to locate package shfmt ») -> exit 1 avant même les
dépendances de compilation de pyenv.

Fix : shfmt (simple formateur shell, non requis pour exécuter ERPLibre) est
retiré du lot critique et installé SÉPARÉMENT en best-effort (jamais fatal).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-30 03:36:03 +00:00
6ce56629f4 [FIX] script todo: redimension — résoudre le nom de VM AVANT extinction
Après un shrink, « Démarrer la VM » faisait « virsh start <id> » : une fois
la VM éteinte, l'ID numérique disparaît -> « failed to get domain 32 ».

On résout désormais le NOM canonique dès le début de _qemu_resize_disk
(VM encore allumée, ID résoluble) et on l'utilise partout, y compris pour
le redémarrage final. Plus de dépendance à l'ID une fois la VM arrêtée.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-30 03:25:54 +00:00
c140b418d5 [IMP] script todo: « Tester une VM » — option d'installer un autre navigateur
Le choix du navigateur propose désormais « [i] Installer un autre
navigateur » en plus des navigateurs déjà installés. L'option ouvre le
sous-menu d'installation (choix w3m/lynx/links/elinks, commande adaptée à
l'OS, validation), même s'il existe déjà un navigateur.

Le flux d'installation est extrait dans _qemu_install_cli_browser
(réutilisé quand aucun navigateur n'est présent ET via l'option [i]).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-30 03:23:28 +00:00
14fa807221 [FIX] script todo: « Tester une VM » — navigateur CLI via os.system (vrai TTY)
Le navigateur ne faisait qu'imprimer sans réagir au clavier : la commande
passait par exec_command_live, qui exécute avec stdout=PIPE (et sans stdin
terminal) -> un navigateur texte (w3m/elinks) n'a pas de TTY interactif.

On lance désormais le navigateur avec os.system(), qui hérite du vrai
terminal (stdin/stdout/stderr) — même principe que le suivi d'installation
(TUI) qui l'appelle dans self.suspend(). Ici, en CLI simple, aucun suspend
n'est nécessaire.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-30 03:21:10 +00:00
babe69dbf7 [IMP] script todo: QEMU — commande « Tester une VM » (ouvre Odoo en navigateur CLI)
Nouvelle entrée [10] dans « Gérer » du menu QEMU/KVM : 🧪 Tester une VM.
Elle liste les VM, demande laquelle, résout son IP puis ouvre
http://IP:8069 (Odoo) dans un navigateur web EN LIGNE DE COMMANDE choisi
par l'utilisateur.

- _qemu_test_vm : résolution d'IP (_qemu_vm_ip), lancement du navigateur,
  message d'aide si la page ne s'affiche pas (Odoo pas démarré / réseau).
- _qemu_choose_cli_browser : liste les navigateurs CLI installés et laisse
  choisir ; si aucun, propose d'en installer un (réutilise CLI_BROWSERS /
  INSTALLABLE_BROWSERS / browser_install_command de qemu_install_monitor).
- « Lister les images » passe de [10] à [11] ; les entrées de config
  suivent à 12+ (branche else inchangée via la liste `real`).

Validé : rendu du menu, choix du navigateur ([2]->elinks, vide->w3m).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-30 03:17:58 +00:00
59bf857558 [IMP] script todo: suivi install — fenêtre des lignes d'erreurs/avertissements
La colonne ⚠ donne le NOMBRE ; on peut désormais LIRE les lignes associées.
Touche « d » (ou indice dans la barre) : ouvre une petite fenêtre modale
(ErrorLinesScreen) listant, pour la VM sélectionnée, les lignes d'erreurs
puis d'avertissements (numéro de ligne + texte), défilable. Échap/q ferme.

- scan_log_error_lines() : mêmes détection + listes d'ignore que la suite de
  tests ERPLibre, mais retient les lignes (bornées à 500) avec leur numéro.
- Scan à la demande à l'ouverture -> toujours à jour (marche même pendant
  l'installation).

Validé headless : modale s'ouvre avec les lignes, se ferme à Échap.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-30 02:16:35 +00:00
f7df2310b3 [FIX] qemu: installer qemu-guest-agent (apt update d'abord) — validé bout en bout
Sur les images cloud, /var/lib/apt/lists est vide (package_update désactivé)
-> « Unable to locate package qemu-guest-agent » et agent inactif. On
rafraîchit l'index (timeout 120, || true) AVANT l'install dans le runcmd
(après sshd, sans bloquer SSH). Idem pacman -Sy. Sous-shell ( ) et non
accolades { } (indicateur YAML).

Validé sur une VM de test Ubuntu 24.04 (redéployée) :
- cloud-init status: done ; user erplibre créé + mot de passe (login console
  erplibre/erplibre OK) ;
- qemu-guest-agent: active ;
- guest-ping OK ; guest-exec autorisé (echo -> code 0, tourne en root).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-29 12:35:39 +00:00
e2b940a3af [FIX] qemu: user-data invalide (YAML) cassait cloud-init -> VM figée
La ligne runcmd Fedora commençait par « - [ -f … ] » : en YAML, «  - [ »
démarre une SÉQUENCE EN FLUX, donc « [ -f … ] && sed … » rendait tout le
user-data invalide. cloud-init rejetait alors la config ENTIÈRE : aucun
utilisateur créé, pas de SSH, login console erplibre/erplibre impossible,
VM « en attente de démarrage ».

- « test -f … && … » au lieu de « [ -f … ] && … » (ne démarre pas de
  séquence YAML).
- timeout 300 sur l'installation de qemu-guest-agent : un miroir lent ne
  bloque plus cloud-init.
- Validé : le user-data se parse en YAML (tous les runcmd sont des chaînes),
  avec et sans mot de passe.

Les VM déjà déployées avec le mauvais seed doivent être redéployées ; les
prochaines repartent correctement.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-29 12:23:05 +00:00
8278c38f46 [IMP] qemu: table lisible/scrollable, guest-exec autorisé, service Odoo, choix navigateur
Suivi d'installation (qemu_install_monitor.py) :
- Table VM/État LISIBLE : largeurs de colonnes fixes (VM 26, ⚠ 4, État 12,
  Durée 7, Disque 8) -> l'État n'est plus tronqué à 3-4 caractères
  («  effacée », « ⏸ en pause » lisibles) ; table défilable (overflow-x,
  height 1fr) pour les longs noms et les gros parcs.
- « w » web : offre désormais la LISTE des navigateurs CLI installés
  (_choose_browser) pour choisir lequel utiliser, + option [i] installer.

Déploiement (deploy_qemu.py) :
- guest-exec AUTORISÉ : on vide la liste de blocage de qemu-ga
  (block-rpcs/blacklist vides — pas allow-rpcs qui est une liste BLANCHE et
  casserait les autres RPC), + neutralise /etc/sysconfig/qemu-ga (Fedora).

Installation (todo.py) :
- Profils AVEC Odoo (install_odoo*) UNIQUEMENT : Odoo est enregistré comme
  service systemd (erplibre.service, inspiré de script/systemd/
  install_daemon.sh) puis enable --now. Pas pour ERPLibre seul / mobile /
  Déploiement.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-29 12:06:29 +00:00
ab8bfec113 [IMP] qemu: guest-agent au déploiement + suivi (erreurs, stats, pause parc)
Provisioning (deploy_qemu.py) :
- qemu-guest-agent installé + activé dans le runcmd cloud-init (APRÈS
  sshd, « || true » : ne bloque pas le boot si le réseau est lent).
- Canal virtio org.qemu.guest_agent.0 ajouté à virt-install : virsh peut
  piloter la VM SANS réseau.
- Extension du FS invité (todo.py) : nouveau tier AGENT INVITÉ
  (_qemu_guest_exec via qemu-agent-command guest-exec) entre SSH et la
  console série -> étend le FS même sans IP.

Suivi d'installation (qemu_install_monitor.py) :
- Détection d'erreurs dans le log à la complétion (succès OU échec) en
  réutilisant la logique de script/test/run_parallel_test.py (sous-chaîne
  error/warning + listes d'ignore). Nouvelle colonne « ⚠ » À GAUCHE d'État
  (⚠N erreurs / N avert. / ✓ propre).
- Sommaire de stats EN CHIFFRES (📊 total ·  ·  ·  · ⏸ · 🗑 · ⚠ · ) ;
  CLIC pour déplier le détail (VM en erreur + durées).
- Boutons « p » Pause tout (virsh suspend des VM running) et « o »
  Reprendre tout (virsh resume) — les logs continuent (offsets conservés).

Validé headless : succès-avec-erreur -> ⚠1, stats/détail, pause du parc.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-29 11:40:43 +00:00
3f20497912 [IMP] script todo: FS invité robuste (heartbeat+console), temps/version, i18n versions
Trois améliorations QEMU :

- Extension du FS invité robuste : résolution d'IP avec BATTEMENT
  (_qemu_resolve_ips, parallèle, boot émulé lent) au lieu d'un timeout
  court ; en cas d'absence d'IP ou d'échec SSH, repli sur la CONSOLE
  SÉRIE avec la commande growpart/resize prête à coller (login
  erplibre/erplibre). Commande factorisée dans _GROW_FS_REMOTE.

- Temps estimés PAR VERSION : nouveau mon.avg_by_version(distro, version)
  et _qemu_stat_avg("version", v, distro) -> suffixe « · ~46s moy (1) »
  dans les listes de versions (prompt simple + granulaire).

- i18n : « Versions for » n'avait AUCUNE traduction (restait en anglais).
  Ajout FR « Versions des » (+ « Version des ») et capitalisation de la
  distro -> « Versions des Ubuntu : ».

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-29 11:29:53 +00:00
a0c560b15f [IMP] script todo: fil d'Ariane télémétrie + arrêt VM par signal (compte à rebours)
Deux points :

- Fil d'Ariane depuis la télémétrie : une commande lancée DEPUIS le TUI de
  télémétrie ne passait par aucun menu, donc son chemin n'était jamais
  affiché. On imprime désormais « 📍 TODO › … › <commande> » (dernier
  segment traduit + icône) avant l'exécution, et on enregistre le chemin.

- Arrêt de VM (réduction disque) par SIGNAL : virsh shutdown --mode
  acpi,agent (bouton ACPI puis agent invité) au lieu d'un arrêt implicite.
  Pendant l'attente, on affiche un compte à rebours du timeout
  («  arrêt en cours… NNN s restantes ») et le délai max au départ.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-29 11:23:54 +00:00
ec88b5f1f0 [IMP] script todo: télémétrie navigation — vue Liste (F3) + sections + icônes
- F3 fait maintenant défiler Arbre -> Kanban -> Liste -> Arbre. Le résumé
  et le footer annoncent la PROCHAINE vue (« F3 → Liste »).
- Nouvelle vue Liste : tous les menus empilés verticalement, chacun avec
  ses sections et ses commandes exécutables.
- Les colonnes Kanban et la vue Liste affichent les SECTIONS (── … ──)
  pour guider le choix, et chaque commande porte son ICÔNE.

L'icône vient de t() : l'AST extrait la clé i18n (prompt_description /
prompt_description_key), et _disp() la résout en libellé traduit + icône.
Les sections sont capturées via _choice_entries (marqueurs {"section": …}).
Validé headless : cycle F3, 11 en-têtes de menu, sections en Liste/Kanban.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-29 11:22:16 +00:00
4bebf5a397 [IMP] script todo: QEMU [4] — choix infos avancées OU changer l'état de VM
Après « virsh list --all », le menu propose désormais :
  [1] Infos avancées (vCPU, RAM, disque)
  [2] Changer l'état d'une ou plusieurs VM
  [Entrée] Rien

Changement d'état (_qemu_change_state) :
- Saisie d'une liste de VM séparée par des virgules (noms ou ID, résolus
  via _qemu_domname et validés contre les VM existantes).
- Choix de l'état cible : Ouvrir (start) ou Fermer (shutdown).
- DOUBLE validation (« Appliquer : … ? » puis « Confirmer pour de vrai ? »)
  avant d'exécuter virsh start/shutdown sur chaque VM.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-29 11:09:40 +00:00
22dcf96853 [IMP] script todo: réduction disque — proposer de redémarrer la VM éteinte
Si la VM a dû être éteinte pour la réduction, on le NOTE (« La VM a été
éteinte pour le redimensionnement. ») puis on demande (o/N) si on veut la
redémarrer (virsh start sur le nom canonique). Si la VM était déjà éteinte
ou n'a pas eu besoin de l'être (agrandissement à chaud), on ne demande
rien : drapeau was_shut_down positionné uniquement après un arrêt effectif.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-29 11:07:46 +00:00
03f6205b9e [IMP] script todo: réduction disque — proposer d'éteindre la VM et réessayer
Avant, réduire le disque d'une VM allumée affichait seulement « Éteignez
la VM » puis abandonnait. Désormais on DEMANDE (o/N) si on veut l'éteindre
et réessayer :

- _qemu_shutdown_wait : arrêt ACPI gracieux (virsh shutdown), attente
  jusqu'à « shut off » (timeout 120s), puis propose un arrêt forcé
  (virsh destroy) si l'arrêt traîne.
- _qemu_domname : résout un ID numérique en nom canonique — l'ID
  disparaît une fois la VM éteinte, le polling doit utiliser le nom.
  Validé : domname(14) -> erplibre-ubuntu-2004.
- Tous les nouveaux prompts affichent la valeur par défaut (o/N).

Une fois éteinte, la réduction (qemu-img resize --shrink) se poursuit
automatiquement après confirmation du risque.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-29 11:05:24 +00:00
4d2b7cea00 [IMP] script todo: QEMU « Lister les VM » — option infos avancées
Après « sudo virsh list --all », le menu propose désormais (o/N) un
tableau détaillé par VM : état, vCPU, RAM allouée (Max memory), taille
disque virtuelle et réelle (qemu-img info -U, lit même VM allumée), plus
l'espace total/libre/utilisé du stockage des images (shutil.disk_usage).

- _qemu_list_vms(ask_advanced=False) : seul le menu [4] prompte ;
  les appels internes (IP, console, resize, delete) restent inchangés.
- Helpers _qemu_dominfo (vcpu + Max memory) et _qemu_disk_sizes
  (virtuel + réel, -U). Validé en réel : 8 vCPU / 8.0G / 30.0G / 2.5G.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-29 11:01:00 +00:00
edf066bb82 [IMP] script todo: icônes du menu Execute + icône « Précédent » sur Retour
- Icônes devant chaque entrée du menu Execute (Code 💻, Config 🔧, Run 🏃,
  Test 🧪, Process 📟, Database 💾, Git 🌿, Mise à jour 🔃, Doc 📖, GPT code
  🤖, Automatisation 🦾, Déploiement 🚀, Réseau 📡, Sécurité 🔒, Langue 🌍).
- Icônes sur les titres de section (Développement 🧰, Données 📊, Sources &
  documentation 📚, IA & automatisation 🧠, Déploiement/réseau/sécurité 🌐,
  Préférences 🎨).
- « Back » (Retour) reçoit 🔙 — icône « Précédent » partagée par tous les
  sous-menus via fill_help_info.

Emojis larges (2 cellules) -> 1 espace, alignement de la colonne label
préservé. Modifs uniquement dans les VALEURS de todo_i18n.py.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-29 10:59:01 +00:00
e36795fb34 [FIX] script todo: redimension disque — lecture taille sur VM allumée (-U)
qemu-img info échouait (« Failed to get shared write lock ») sur une VM
running car libvirt tient le lock d'écriture : la taille virtuelle lue
tombait à 0.0 G, et « -10G » donnait alors 0-10 = -10 → « Taille invalide ».

- Ajout de -U (--force-share) aux deux appels qemu-img info (affichage +
  _qemu_disk_virtual_bytes) : lecture seule sûre même VM allumée.
- Garde-fou : si la taille reste illisible (0), on abandonne avec un
  message clair au lieu de calculer une cible négative.

Le redimensionnement lui-même était déjà correct (virsh blockresize à
chaud si running, qemu-img resize si éteinte) — pas besoin d'éteindre la
VM pour AGRANDIR. Validé : lecture -U renvoie 30.0 G sur une VM running.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-29 10:57:22 +00:00
c31dc3967d [FIX] script todo: dashboard « w » — choix du navigateur + diagnostic visible
Deux problèmes du bouton « w » (ouvrir l'UI web de la VM) :

- L'installation prenait w3m sans demander. Désormais on CHOISIT le
  navigateur CLI à installer (w3m / lynx / links / elinks) via _install_cli_
  browser ; la commande (adaptée à l'OS) est affichée puis validée.
  browser_install_command prend un paramètre `browser`.
- Au lancement, le navigateur « clignotait » et revenait au TUI sans qu'on
  voie l'erreur (souvent Odoo pas démarré sur :8069). On affiche maintenant
  la commande, le CODE DE SORTIE, un indice (Odoo/réseau) et une PAUSE
  « Entrée pour revenir » pour diagnostiquer.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-29 10:51:54 +00:00
d9b8372784 [IMP] script todo: alignement des icônes + icônes menus principal/Deploy/SSH
- Alignement : les icônes ÉTROITES (rendues sur 1 cellule : ⬇ 🖥 🗂 🛠)
  reçoivent 2 espaces au lieu d'un -> la colonne des libellés s'aligne avec
  les icônes larges (2 cellules + 1 espace).
- Icônes ajoutées (emojis larges, alignés) aux menus les plus utilisés :
  principal (🧰 Exécution, 📦 Installation,  Question, 🔀 Fork,
  📊 Télémétrie), Deploy (💻 Local, 🌐 Distant, 📥 Cloner, 📁 sshfs,
  🔐 SSH, 🔔 NTFY, 💻 QEMU) et sous-menu SSH (🔌🔄📦🟢🔴🔁📊📜🧰🧩🔒).

Uniquement les VALEURS i18n changent ; clés (et télémétrie) inchangées.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-29 10:49:25 +00:00
b2a2db686e [IMP] script todo: stats d'install (durée/version) + moyennes par arch/distro
L'historique d'installation est désormais enregistré dans un fichier DÉDIÉ
.venv.erplibre/qemu_install_stats.json (repli ~/.erplibre) : chaque run garde
distro + version + architecture + durée + horodatage (500 derniers).

- record_duration(distro, version, arch, secs) enregistre le run (appelé par
  le dashboard à la complétion d'une VM).
- Menus de sélection enrichis : chaque architecture et chaque distribution
  affiche la DURÉE MOYENNE d'install historique « · ~5m moy (3) » quand la
  donnée existe. La DERNIÈRE install (distro version [arch] — durée) est
  rappelée en tête du déploiement.
- eta_reference lit désormais les runs (médiane par arch, repli global).
  Nouveaux helpers : avg_by_arch, avg_by_distro, last_run.

Validé : enregistrement + moyennes (amd64 ~5m (2), ubuntu ~13m (3)),
dernière install affichée, distros sans données masquées.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-29 10:46:21 +00:00
4c04145c31 [IMP] script todo: choix du profil d'installation ERPLibre sur une VM
Quand on installe ERPLibre sur une/des VM, on choisit désormais CE qu'on
installe (au lieu de forcer install_odoo_18) :

  ERPLibre + Odoo 18/17/16/15/14/13/12  (make install_os && make install_odoo_X)
  ERPLibre + toutes les versions Odoo    (make install_odoo_all_version)
  ERPLibre seulement (sans Odoo)         (./script/install/install_erplibre.sh)
  ERPLibre mobile (home)                 (./mobile/install_and_run.sh)
  ERPLibre Déploiement (+ QEMU + dev)    (install_dev + qemu/libvirt/virtinst)

_qemu_pick_install_profile renvoie la commande finale ; _qemu_erplibre_remote_cmd
l'exécute dans ~/git/erplibre ; le profil est threadé aux installeurs
(monitoré + streamé). Cibles make vérifiées dans les Makefiles.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-29 10:42:02 +00:00
99180d2abf [FIX] script todo: télémétrie système — rafraîchir après install lm-sensors
Après « i » (installer lm-sensors) dans la vue système F2, l'affichage
n'était pas garanti d'être remis à jour : le message « lm-sensors absent »
pouvait rester même si les capteurs devenaient lisibles.

Fix : à la fin de action_install_sensors, on ré-échantillonne le système
(température incluse, _sys_prev remis à zéro) et on réécrit la case
SYNCHRONEMENT + self.refresh(), puis on notifie le résultat (« capteurs
désormais disponibles » ou « toujours pas de température — reboot/modprobe
requis ? »).

Validé headless : la ligne Température passe de « lm-sensors absent… » à
« 48°C (max) » une fois la température lisible.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-29 10:35:24 +00:00
421f61b84b [IMP] script todo: icônes devant les entrées du menu QEMU/KVM
Ajoute une icône descriptive devant chaque section et entrée du menu QEMU :
🚀 Déploiement / Déployer, 🔍 Prévisualiser, ⬇ Télécharger, 🛠 Gérer,
📋 Lister, 🌐 IP, 🖥 Console, 📐 Redimensionner, 🗑 Effacer, 🧹 Nettoyer,
📚 Catalogue, 🗂 Lister images.

Uniquement les VALEURS i18n (fr+en) changent -> aucune modif de todo.py, les
clés (et donc les appels t(...) + la télémétrie) restent inchangés.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-29 10:24:27 +00:00
320b88b83b [IMP] script todo: télémétrie — vue Système (F2) + case agrandissable (grille)
- F2 : nouvelle vue SYSTÈME (état/uptime + charge, CPU %, mémoire, disque,
  réseau ↓/↑, batterie, température). Les I/O sont déportées en thread
  (asyncio.to_thread) ; rafraîchissement 2 s (deltas CPU/réseau). Si la
  température n'est pas lisible (ni /sys/class/thermal ni lm-sensors), on
  propose d'installer lm-sensors avec la touche « i » (commande selon l'OS —
  apt/dnf/pacman — affichée puis validée). read_temperature essaie
  /sys/class/thermal d'abord (sans dépendance).
- Vue Kanban GRILLE : clic sur le TITRE d'une case -> elle s'AGRANDIT
  (row-span, prend toute la hauteur d'une colonne) ; re-clic -> taille
  normale (classe kbig).

Validé headless : vue système peuplée (mém/disque/temp), F2/F3 basculent,
clic titre en grille -> kbig on/off.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-29 10:22:11 +00:00
6440cec2e1 [IMP] script todo: télémétrie — revenir après commande + Kanban F4 (swimlanes)
- Après exécution d'une commande choisie dans la télémétrie, on propose de
  REVENIR (r) ou de quitter. En revenant, la vue ET la position du curseur
  sont RESTAURÉES (chemin porté par chaque nœud/carte ; run_tui prend/rend un
  `state`).
- Vue Kanban : F4 fait défiler la DISPOSITION —
  columns (une rangée de colonnes) / swimlanes (une rangée par menu de
  niveau 1) / grid (grille 3 colonnes). F3 bascule Arbre/Kanban.

Validé headless : F3/F4 cyclent les dispositions, sélection -> action+état,
relance avec `state` -> curseur restauré sur le bon nœud.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-29 10:09:06 +00:00
bc0e06137f [IMP] script todo: dashboard async (I/O en thread) + install navigateur CLI
- Ticks ASYNCHRONES : les I/O bloquantes (lecture des logs, stat disque,
  subprocess « virsh list », /proc) sont déportées en THREAD via
  asyncio.to_thread ; seules les mises à jour d'UI restent sur la boucle
  d'événements Textual -> plus de gel, même sous forte charge ou disque lent.
  _collect_table (thread) rassemble statut+disque+télémétrie, l'application
  au tableau se fait ensuite sur la boucle. _tick_log/_tick_domstate idem.
  Helper _read_new (lecture incrémentale) réutilisé.
- Touche « w » : si aucun navigateur CLI n'est présent, on PROPOSE de
  l'installer selon l'OS (apt Ubuntu/Debian, dnf Fedora, pacman Arch — nos 4
  systèmes) : la commande est AFFICHÉE puis exécutée après validation (o/N).

Validé headless : ticks async mettent l'UI à jour ; browser_install_command
renvoie la bonne commande selon l'OS.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-29 10:09:06 +00:00
b542aa7dc2 [IMP] script todo: télémétrie — exécuter une commande + vue Kanban (F3)
Le TUI de télémétrie devient aussi un LANCEUR, avec deux vues :

- Sélectionner une COMMANDE (feuille de l'arbre, ou carte du Kanban) +
  Entrée -> le TUI se ferme et la commande est EXÉCUTÉE (getattr(self, méthode)
  (**kwargs)). Les kwargs littéraux sont extraits du code (ex. Aperçu ->
  _qemu_deploy(dry_run=True)), donc la commande est rejouée à l'identique.
- Vue KANBAN : une colonne par menu contenant des commandes (issu du code),
  cartes = commandes exécutables + compteur de visites du menu.
- F3 bascule entre vue Arbre et vue Kanban. Résumé mis à jour (Entrée =
  exécuter, F3 = vue).

_dispatch capture désormais (méthode, kwargs) ; les feuilles de l'arbre
portent la méthode en data ; run_tui renvoie (méthode, kwargs) à exécuter.

Validé headless : 11 colonnes Kanban, kwargs (dry_run/production_ready)
capturés, bascule F3, capture de l'action à exécuter.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-29 09:56:50 +00:00
7517cc814b [IMP] script todo: télémétrie — arbre de navigation DÉRIVÉ DU CODE
La télémétrie n'affichait que les chemins effectivement visités. Elle
observe désormais les MÉTADONNÉES DE NAVIGATION issues du CODE : todo.py est
analysé (AST) pour reconstruire l'arbre RÉEL des menus et commandes.

- build_code_tree() lit _MENU_LABELS + les listes « choices » + le dispatch
  « status == N: self.X() » de chaque menu pour bâtir l'arborescence complète
  (sous-menus = cibles présentes dans _MENU_LABELS ; sinon commandes-feuilles,
  libellées par leur prompt_description).
- Le TUI affiche cet arbre COMPLET (tous les menus, même jamais visités) avec
  le compteur de visites en surimpression sur chaque menu (via la télémétrie
  persistée). Repli sur l'arbre des seuls chemins visités si l'analyse échoue.

Validé : l'arbre reconstruit couvre Execute -> Deploy -> SSH/QEMU (+ toutes
leurs commandes : Resize, Delete, …), Git -> Git local server, GPT code ->
RTK, etc. ; compteurs corrects (menus visités > 0, autres 0).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-29 09:49:13 +00:00
f2cb9be665 [ADD] script todo: télémétrie de navigation + diagramme arborescent (TUI)
Nouvelle entrée « [5] Télémétrie de navigation (TUI) » dans le menu principal.

- Enregistrement : Todo._menu_header (seul constructeur du fil d'Ariane)
  appelle todo_telemetry.record(fil) à chaque affichage de menu. Dédup des
  ré-affichages consécutifs -> on ne compte que les TRANSITIONS de
  navigation. Persistant dans ~/.erplibre/todo_telemetry.json. Best-effort :
  ne casse jamais la navigation.
- Visualisation : todo_telemetry.run_tui() ouvre un TUI Textual affichant
  l'ARBRE des fonctionnalités visitées (chaque nœud = un menu, avec son
  nombre de visites), trié par usage décroissant. Touches : q (quitter),
  r (réinitialiser), e (tout déplier). Sommaire : total navigations + menus.

Validé headless : enregistrement + dédup, arbre imbriqué à compteurs,
montage du TUI, peuplement, touches.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-29 09:35:31 +00:00
62ea6ebb7f [IMP] script todo: dashboard — états Pause / Effacée (check virsh lent)
Pendant le suivi, une VM pouvait « stagner » sans qu'on sache pourquoi
(mise en pause, ou effacée à côté). Le dashboard interroge désormais l'état
libvirt (« virsh list --all ») à INTERVALLE LENT (toutes les 10 s, un seul
appel pour tout le parc ; le tableau applique le cache à chaque tick de 2 s) :

- VM en pause (virsh suspend) -> État « ⏸ pause » (non terminal, peut
  reprendre).
- VM absente de virsh (effacée pendant l'attente) -> État «  effacée »,
  terminal (on cesse de lire son log).

Sinon on garde le statut basé sur le log ( /  / ).

Validé headless : running -> , paused -> ⏸ pause, absente ->  effacée.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-29 09:30:16 +00:00
1fd98e6ab6 [IMP] script todo: commande QEMU « Redimensionner le disque d'une VM »
Nouvelle entrée dans le menu QEMU/KVM (section Gérer). Elle :
- affiche le disque principal (qcow2 via domblklist) + « qemu-img info »
  (taille virtuelle + réelle) et l'état de la VM ;
- demande +NG (agrandir), -NG (réduire) ou NG (taille cible) ;
- applique : agrandissement À CHAUD si la VM tourne (virsh blockresize),
  sinon qemu-img resize ; réduction via qemu-img resize --shrink (VM éteinte
  obligatoire + avertissement fort : le FS invité n'est PAS réduit, risque
  de perte de données) ;
- propose ensuite d'étendre le FS invité via SSH (growpart + resize2fs /
  xfs_growfs / btrfs, device et type de FS détectés).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-29 09:27:20 +00:00
6f70da98d5 [IMP] script todo: dashboard — télémétrie CPU/disque, ETA historique, web CLI
Ajouts au suivi d'installation (dashboard Textual) :

- Télémétrie hôte (barre dédiée, MAJ 2 s) : CPU % = charge / nb CPU, et
  disque du dossier des images (utilisé/total/libre) — utile pour anticiper
  le remplissage du disque (cas vécu).
- Colonne « Disque » par VM : taille RÉELLE du qcow2 (st_blocks) -> on voit
  quelle VM grossit.
- ETA « hypothèse » : les durées d'install sont MÉMORISÉES par architecture
  dans ~/.erplibre/qemu-install/stats.json ; l'ETA du parc = médiane
  historique (par arch, repli global) - temps écoulé, affichée au sous-titre.
- Touche « w » : ouvre l'UI web de la VM (Odoo :8069) dans un navigateur CLI
  (browsh/carbonyl/w3m/links/elinks/lynx, le 1er trouvé ; sinon notifie quoi
  installer). Surtout utile quand l'install est terminée.

Helpers module : load_stats/record_duration/eta_reference, _fmt_size/_fmt_secs,
vm_disk_path/disk_actual_size, cli_browser. run_monitor(run_app=False) expose
l'app pour test headless.

Validé headless (run_test) : montage, ticks, enregistrement des durées, ETA,
télémétrie, touches f/w — sans crash.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-29 09:20:18 +00:00
fdbec6d19d [FIX] script todo: dashboard — stoppe le churn de rendu + nombre de VM
Encore du lag à 16 VM : update_cell était appelé pour CHAQUE ligne à chaque
tick (état + « Durée »), or la Durée — dérivée d'un `started` global — est
identique sur toutes les lignes et se réécrivait sans cesse -> re-render
permanent de la DataTable.

- _set_cell : n'appelle update_cell (donc ne re-render) que si la valeur
  CHANGE. Mesuré : 312 -> 18 update_cell sur 10 ticks × 16 VM.
- La durée « live » passe dans le SOUS-TITRE (une seule mise à jour) ; la
  colonne Durée n'est écrite qu'à la complétion (durée finale figée).
- Le NOMBRE de VM est affiché : titre « … (N VM) », sous-titre
  « k/N terminées · mm:ss ».

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-29 09:13:56 +00:00
b7522bb92d [FIX] script todo: dashboard Textual — lag et gel sur gros parc corrigés
Le TUI de suivi laggait à 30 VM et se figeait quand l'I/O ralentissait
(disque plein / logs effacés). Cause : à chaque tick (1 s) on lisait le
fichier log ENTIER de CHAQUE VM pour le statut + on relisait tout le log
sélectionné, en synchrone sur la boucle d'événements Textual.

Corrections :
- read_status ne lit que les 4 derniers Ko (le marqueur de sortie est sur
  la dernière ligne) : un log de 2 Mo passe de « tout lire » à 0,1 ms.
- _load_selected_log lit de façon INCRÉMENTALE (seek à l'offset) au lieu de
  relire tout le fichier.
- Les VM TERMINÉES ne sont plus relues (cache _final).
- _tick_table (2 s) et _tick_log (1 s) séparés et PROTÉGÉS par try/except :
  une erreur I/O transitoire (disque plein, log supprimé) ne tue plus la
  boucle -> l'interface reste réactive aux touches.
- RichLog borné (max_lines=5000).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-29 09:01:39 +00:00
51a9e7b97c [FIX] script todo: résolution d'IP robuste (ping + multi-source + heartbeat)
Sur un gros parc (30 VM, ~18 émulées), la résolution d'IP « bloquait » 10 min
en silence sur les VM lentes. Trois causes traitées :

- Joignabilité par PING (ICMP) d'abord, TCP:22 en repli. Le ping répond dès
  que le réseau de la VM est up, BIEN AVANT sshd : on ne retenait pas une VM
  qui a déjà son IP juste parce que sshd (lent en émulation) n'était pas prêt.
  Le ping distingue toujours le bail actif (répond) du bail périmé (non).
- IP cherchée sur PLUSIEURS sources : lease (dnsmasq), agent (qemu-guest-
  agent DANS la VM) et arp (table ARP hôte). Le bail dnsmasq peut être vide
  sous forte charge alors que la VM a une IP (constaté sur ce parc).
- BATTEMENT toutes les 30 s listant les VM encore en attente + timeout PAR VM
  ramené à 5 min (au lieu de 10) dans la phase de résolution -> plus de
  silence prolongé, et on n'attend pas indéfiniment une VM sans IP.

NB : déployer la matrice complète (30 VM dont ~18 émulées TCG) sature un seul
hôte ; certaines VM émulées n'obtiennent pas de bail DHCP à temps (limite de
capacité, pas un bug). La résolution dégrade désormais proprement.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-29 08:54:36 +00:00
1e9e5abd1f [IMP] script todo: compteur de complétion, durées par étape + sommaire total
Améliore le suivi du déploiement multi-VM :

- Compteur de COMPLÉTION devant chaque résultat (« [1/26] », « [2/26] »… =
  ordre où les tâches TERMINENT), en plus de l'ID de préparation stable
  (« [7/26] ») — utile car l'exécution parallèle rend les résultats
  désordonnés.
- Temps d'exécution PAR ÉTAPE : durée de chaque VM (déploiement, résolution
  d'IP) + bilan de phase (« Bilan déploiement : 24 OK, 2 en échec, 26 VM,
  3m10s » ; « IP résolues : 25/26 (2m). »).
- SOMMAIRE TOTAL encadré en fin de flux (VM déployées, total avec
  existantes, temps total).

Helper _fmt_dur (« 45s » / « 2m05s »).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-29 08:46:48 +00:00
da1206bcb2 [IMP] script todo: afficher la valeur par défaut des questions oui/non
Chaque question oui/non affiche désormais explicitement la valeur par défaut
appliquée si on laisse vide, ex. :
  « Suivi interactif (dashboard) ? (o/N, défaut : non) : »

Les 18 prompts passent par _is_yes(input(...)) : une réponse vide vaut NON.
On l'indique donc dans les traductions (fr « (o/N, défaut : non) », en
« (y/N, default: no) »). Seules les VALEURS i18n changent ; les clés (donc
les appels t(...) dans todo.py) sont inchangées.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-29 08:37:18 +00:00
a74b0c0c4c [IMP] script todo: nb de VM dans le prompt parallèle + IDs de suivi (k/N)
Sur un gros parc (ex. 26 VM), on ne voyait ni combien de VM allaient être
déployées ni lesquelles étaient en cours (résultats parallèles dans le
désordre). Deux améliorations :

- Le prompt de parallélisme affiche le NOMBRE de VM à déployer :
  « Déploiements en parallèle (défaut : 24, 26 VM) : ». Pour cela, la
  séparation à-créer / déjà-existantes est faite AVANT le prompt (on connaît
  le vrai compte).
- Chaque VM reçoit un ID « k/N » suivant l'ordre de préparation, affiché
  dans les résultats de déploiement («  [3/26] nom ») et dans la résolution
  d'IP (« [5/30] nom : ip »). L'ID reste stable même si les résultats
  reviennent dans le désordre -> on suit lesquelles sont traitées.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-29 08:33:50 +00:00
372aedb0eb [IMP] script todo: fusionner « Déployer VM » et « infra » + renommage granulaire
Le menu QEMU avait deux commandes de déploiement redondantes : [1] « Déployer
une VM » (mono, noms/ressources personnalisés) et [4] « Déployer l'infra »
(multi, matrice distro×version×archi). Elles sont FUSIONNÉES en une seule,
[1] « Déployer une ou plusieurs VM » (_qemu_deploy), qui gère aussi bien 1 VM
que N, avec :

- renommage GRANULAIRE des VM à la demande (_qemu_customize_names) : noms
  auto par défaut, on en renomme certains par numéros séparés de virgules ;
- multiplicateur de ressources (x1..x4) déjà présent ;
- aperçu dry-run ([2]) qui passe par le même flux et imprime les commandes
  deploy_qemu (--dry-run) via le helper partagé _qemu_build_deploy_parts.

Menu simplifié : [1] Déployer une/plusieurs VM, [2] Aperçu (dry-run),
[3] Télécharger une image, puis Gérer/Catalogue renumérotés. Code mort retiré
(_qemu_deploy_vm, _qemu_prompt_arch, _normalize_disk_size,
_qemu_offer_ssh_config).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-29 08:25:38 +00:00
52b79551dd [IMP] script qemu: échec de téléchargement -> chemin + commande de reprise
Quand le téléchargement échoue sur tous les miroirs, le message indique
désormais le CHEMIN de destination visé et une commande prête à copier pour
reprendre manuellement :

  Destination : /var/lib/.../fedora-cloud-41-aarch64.qcow2
  Reprendre le téléchargement manuellement :
    sudo curl -fL -C - -o <dest> \
      <url>
  puis relancez le déploiement (l'image en cache sera réutilisée).

curl -C - reprend un .part partiel (ou repart de zéro), -f échoue proprement
sur une erreur HTTP. Complète la détection de téléchargement incomplet.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-29 08:25:38 +00:00
4688e7c606 [IMP] script todo: regrouper les opérations SSH dans un sous-menu Deploy
Le menu Deploy listait 11 entrées « SSH - … » à plat, ce qui le surchargeait.
Elles sont déplacées dans un sous-menu « SSH (hôte distant)… »
(prompt_execute_deploy_ssh), comme le sous-menu QEMU. Le menu Deploy tient
désormais en 5 entrées :

  ── Local ──
  [1] Cloner ERPLibre localement
  [2] Configurer sshfs
  ── Distant & services ──
  [3] SSH (hôte distant)…        -> sous-menu (11 opérations SSH)
  [4] NTFY
  [5] QEMU/KVM…

Le fil d'Ariane affiche « TODO › Execute › Deploy › SSH » dans le sous-menu.
Les libellés et actions SSH sont inchangés (traductions réutilisées).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-29 08:14:50 +00:00
5a408f1061 [IMP] script todo: infra — multiplicateur de ressources par VM (x1..x4)
Avant le déploiement infra, on demande un multiplicateur de ressources :
x1 (minimum catalogue) .. x4. Il multiplie la RAM (base = minimum de la
version) et les vCPU (base 2), en bornant les vCPU au nombre de cœurs de
l'hôte et en signalant si la RAM totale dépasse la RAM libre.

- Le prompt affiche les ressources de l'hôte (vCPU, RAM libre) et, pour
  chaque multiplicateur, le total RAM + vCPU/VM avec un ⚠ si ça dépasse.
- Le plan reflète les ressources effectives (vCPU + RAM×mult par VM).
- Les jobs passent --memory et --vcpus effectifs à deploy_qemu (avant,
  l'infra laissait le minimum catalogue + 2 vCPU par défaut).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-28 09:39:59 +00:00
b49e107b83 [FIX] script todo: résolution d'IP en parallèle (dashboard ne s'ouvrait jamais)
Après un déploiement infra, la résolution d'IP tournait EN SÉRIE (boucle
ssh_config puis install), jusqu'à 10 min par VM émulée, SANS aucune sortie :
le dashboard « n'ouvrait jamais » (impression de blocage), d'autant qu'une
VM qui ne boote pas (IP jamais attribuée) bloquait tout le reste.

Fix : _qemu_resolve_ips résout les IP de toutes les VM EN PARALLÈLE, avec
progression affichée par VM, une seule fois, réutilisée pour ~/.ssh/config
ET l'installation (plus de double résolution). _qemu_install_erplibre_*
acceptent une IP/ip_map déjà résolue.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-28 09:22:46 +00:00
7bd44d21a9 [FIX] script qemu: téléchargement complet vérifié + arm64 sans Secure Boot
Une VM arm64 (Fedora aarch64 émulée) restait FIGÉE au firmware (CPU ~2 %,
aucune IP, seed non appliqué). Deux causes :

1) Téléchargement tronqué non détecté. _download_one ne vérifiait pas que le
   nombre d'octets reçus == Content-Length. Une connexion coupée en cours
   laissait un .part TRONQUÉ, validé comme « complet » (tmp.replace) : un
   qcow2 valide mais VIDE (128 Kio, juste l'en-tête, 5 Gio virtuels) ->
   disque sans OS -> pas de boot. Pire, ce cache corrompu était réutilisé.
   Fix : contrôle de complétude (done < total -> exception -> miroir suivant
   ou échec net, jamais de commit d'un fichier tronqué).

2) arm64 : « --boot uefi » simple laissait libvirt choisir l'AAVMF « secure »
   (clés Microsoft enrôlées) -> pas de boot. On désactive Secure Boot comme
   pour x86 (secure-boot=no -> AAVMF_CODE.no-secboot.fd).

Validé : redéploiement Fedora 42 aarch64 avec image complète + firmware
non-SB -> CPU 111 % (boot actif), IP en ~80 s, SSH OK (erplibre, aarch64,
Fedora 42 Cloud, sudo OK).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-28 09:22:46 +00:00
939e26ba83 [IMP] script todo: en-tête d'install (date, distro, version, archi) dans le log
Le log d'installation commence désormais par un en-tête identifiant
l'installation : date, VM, distribution + version, architecture, branche, IP.
Écrit dès la création du log (plus jamais vide au démarrage).

_qemu_install_erplibre_monitored déduit distro/version/arch de chaque VM
(nom via _qemu_infra_name + arch via virsh dumpxml) et les passe à
launch_installs, qui écrit l'en-tête et les stocke dans le manifeste.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-28 08:57:36 +00:00
b395e7c3ed [FIX] install: supporter Ubuntu 26.04 (sinon deps système sautées -> pas de gcc)
L'install ERPLibre échouait sur une VM Ubuntu 26.04 :
« configure: error: no acceptable C compiler found in $PATH » -> pyenv ne
compile pas Python -> pas de venv -> pip/poetry/repo absents.

Cause : install_dev.sh ne listait Ubuntu que jusqu'à 25.10. Sur 26.04 il
tombait dans le « else » (« Your version is not supported… : 26.04 ») et
n'exécutait donc PAS install_debian_dependency.sh -> ni build-essential ni
gcc installés. Le catalogue de déploiement propose pourtant 26.04.

Fix : ajout de 26.04 à la liste des versions Ubuntu supportées.

Note : Ubuntu 26.04 utilise uutils (rust-coreutils), bogué en big-endian ;
sur s390x un « sort » peut paniquer (non bloquant ici) — problème amont.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-28 08:57:36 +00:00
50617e3909 [IMP] script todo: infra — architecture [all] (matrice distro×version×arch)
Menu « Déployer l'infra ERPLibre » : la sélection d'architecture propose
désormais [all] = toutes les architectures supportées. L'architecture
devient une dimension à part entière de la matrice de déploiement.

- [all] archis + [all] catalogue : une VM par (distro, version, archi
  publiée par cette distro). Ex. ubuntu -> amd64/arm64/s390x, debian/fedora
  -> amd64/arm64, arch -> amd64 (30 VM au total avec le catalogue courant).
- [all] archis + [granulaire] : la liste à plat inclut l'archi ([amd64]/
  [arm64]/[s390x]) ; on choisit des combinaisons précises par virgules.
- [all] archis + [principal] : version par défaut de chaque distro × chaque
  archi supportée.
- Une archi précise (arm64/s390x) restreint le catalogue aux distros qui la
  publient (inchangé).

selected porte l'archi par élément ; les noms sont suffixés par archi pour
les non-natives (erplibre-ubuntu-2604-s390x) -> pas de collision. --arch
transmis par VM. Chaque distro ne reçoit que les archis QU'ELLE publie.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-28 08:51:45 +00:00
bd94c277d3 [FIX] script qemu/todo: bonne IP quand la VM a plusieurs baux DHCP
Symptôme : ~/.ssh/config (et l'install) pointaient sur .31 alors que la VM
était joignable sur .32 -> SSH KO (« No route to host »), console OK.

Cause : au boot, une image cloud demande d'abord une IP DHCP avec son
hostname par défaut (« ubuntu ») -> 1er bail ; puis cloud-init fixe le vrai
hostname et le client redemande -> 2e bail (IP différente). La MÊME MAC a
donc DEUX baux ; le 1er (« ubuntu ») devient périmé. Le code retenait
aveuglément le PREMIER IPv4 de « virsh domifaddr » = le bail périmé. Plus
visible sur s390x/arm64 émulé (boot lent -> les deux baux coexistent).

Fix :
- todo._qemu_vm_ip : renvoie en priorité l'IP dont le bail dnsmasq porte le
  hostname == nom de la VM (bail définitif), sinon une IP JOIGNABLE (sshd up,
  test TCP:22), sinon le dernier bail — jamais le 1er au hasard. Attente
  portée à 10 min (boot émulé lent). Helpers _qemu_lease_candidates /
  _qemu_ip_reachable / _qemu_lease_ip_for_host.
- deploy_qemu.wait_for_ip : même logique (IP joignable, sinon la plus
  récente) pour l'IP affichée en fin de déploiement standalone.

Validé sur la VM s390x réelle : candidats [.31, .32] -> choisit .32
(hostname-match + seule joignable) ; ssh via alias OK.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-28 08:33:50 +00:00
0930f30cd3 [IMP] script todo: suffixe d'arch dans le nom + log d'install non vide
1) Nommage : _qemu_infra_name ajoute un suffixe d'architecture quand elle
   diffère de la native de l'hôte -> déployer un s390x sur un hôte amd64
   donne « erplibre-ubuntu-2604-s390x » (au lieu de « erplibre-ubuntu-2604 »).
   Évite les collisions de noms entre archis et rend l'archi visible. Passé
   dans les 3 appelants (VM unique + plan + jobs de l'infra).

2) Log d'installation vide : sur une archi ÉMULÉE (s390x/arm64 sur x86) le
   boot prend plusieurs minutes ; pendant ce temps l'attente n'écrivait rien
   -> le log restait VIDE et paraissait « bloqué ». _launch_one écrit
   désormais un en-tête d'attente immédiat + un battement toutes les ~30 s,
   et l'attente sshd/cloud-init passe de ~12 à ~20 min (boot émulé lent).
   _qemu_wait_ssh (chemin streamé) : timeout porté à 20 min également.

Validé : nommage (amd64/natif sans suffixe, s390x/arm64 suffixés) ; le log
se remplit dès le départ (en-tête + « ... 30s »).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-28 08:15:46 +00:00
88dc1d5409 [IMP] script qemu: support arm64/aarch64 (+ archi native marquée d'un *)
Ajoute l'architecture arm64 (aarch64) au déploiement, en plus d'amd64
(x86_64) et s390x. Disponibilité réelle vérifiée (juillet 2026) :
- arm64 : Ubuntu, Debian, Fedora (Arch : pas d'image cloud aarch64 -> rejet).
- s390x : Ubuntu seulement (inchangé).

deploy_qemu.py :
- host_arch() : arch native de l'hôte ; toute arch différente est ÉMULÉE
  (TCG, --virt-type qemu) — plus de liste FOREIGN_ARCHES figée.
- virt_install : arm64 -> --arch aarch64 --machine virt --boot uefi (firmware
  AAVMF résolu par libvirt) ; s390x inchangé ; x86 UEFI/OVMF inchangé.
- ensure_emulator(arch) généralisé : installe qemu-system-aarch64 + firmware
  UEFI AAVMF (arm64) ou qemu-system-s390x (s390x), selon le gestionnaire de
  paquets, avec vérif de présence (binaire + firmware pour arm64).
- Validation --arch tôt via ARCH_DISTRO_SUPPORT (message clair si la distro
  ne publie pas l'arch). Les URLs d'images arm64 marchent déjà via les alias
  (fedora/arch aarch64 ; ubuntu/debian arm64).

todo.py : menus d'architecture (VM unique + infra) proposent amd64/arm64/
s390x selon la distro ; l'architecture NATIVE de l'hôte est marquée d'un *
(défaut) ; les autres sont signalées « émulé, lent ». Le catalogue infra est
restreint aux distros publiant l'arch choisie (arm64 -> ubuntu/debian/fedora,
s390x -> ubuntu).

install_debian_dependency.sh : wkhtmltopdf (deb amd64 en dur) ignoré
best-effort sur toute arch non-x86_64 (au lieu d'avorter l'install).

Validé : dry-runs Ubuntu/Debian/Fedora arm64 (bonnes URLs + virt-install
aarch64/virt/uefi/qemu), rejet Arch arm64, non-régression s390x, menus et
filtrage simulés (natif *, arm64 par distro).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-28 07:56:20 +00:00
8652c30507 [FIX] install Fedora: git-daemon (repo sync via git daemon local échouait)
repo sync échouait sur Fedora :
  git: 'daemon' is not a git command.
  fatal: cannot obtain manifest git://127.0.0.1:9418/  -> Connection refused
  Unable to sync manifest ./manifest/git_manifest_erplibre.xml

Cause : sur Fedora la sous-commande « git daemon » N'EST PAS fournie par le
paquet « git » de base (contrairement à Debian/Ubuntu/Arch) mais par le
paquet séparé « git-daemon ». ERPLibre sert son manifeste via un « git
daemon » local (git://127.0.0.1:9418/) pendant repo sync ; sans le binaire,
le daemon ne démarre pas -> connexion refusée -> synchro du manifeste KO.

Fix : ajout de git-daemon aux dépendances Fedora.

Validé sur VM Fedora 42 réelle : avant, « git daemon » rc=1 ; après
« dnf install git-daemon », rc=0, et un git daemon local sert bien
git://127.0.0.1:9418/ (git ls-remote renvoie les refs).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-28 07:47:02 +00:00
3bf8fc2972 [IMP] script todo: infra deploy — option granulaire + choix d'architecture
Menu « Déployer l'infra ERPLibre » :

- Nouveau choix [granulaire] dans la sélection des distributions : affiche
  la liste À PLAT de TOUTES les versions du catalogue (distro + version,
  défauts marqués d'un *) et permet d'en choisir plusieurs par leurs numéros
  séparés par des virgules (ex. « 1,3,12 »). Complète [all] et [principal].

- Demande l'ARCHITECTURE du parc en début de flux, par défaut l'architecture
  NATIVE de l'hôte (amd64/arm64/s390x via uname -m). s390x est proposé mais
  émulé (lent) et n'a d'images cloud que pour Ubuntu -> le catalogue est
  alors restreint à Ubuntu (les autres distros sont ignorées avec un
  avertissement). --arch est transmis à deploy_qemu.py quand ≠ amd64.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-28 07:35:25 +00:00
374373cc7c [FIX] install Arch: mise à jour complète (pacman -Syu) contre glibc mismatch
Après le passage à pacman, l'init PostgreSQL échouait :
« /usr/bin/postgres: /usr/lib/libm.so.6: version GLIBC_2.44 not found ».
Cause : Arch est en rolling release et NE SUPPORTE PAS les mises à jour
partielles. Sur une image cloud dont la glibc date du build de l'image, un
« pacman -S <paquet récent> » (postgresql 18.4) installe un binaire lié à
une glibc plus récente que celle du système -> symbole introuvable.

Fix : mise à jour COMPLÈTE (pacman -Syu) avant d'installer, dans les deux
endroits : install_arch_linux.sh (deps OS) et le bootstrap Arch de
_qemu_erplibre_remote_cmd (todo.py, remplace -Syy par -Syu).

Validé sur VM Arch réelle : après -Syu, « postgres (PostgreSQL) 18.4 » OK,
initdb OK, service postgresql actif, superuser erplibre créé, psql connecte.
Chaîne complète confirmée : gcc 16.1.1, make, node, psql tous présents.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-28 07:27:44 +00:00
63e7b6af8c [FIX] install Arch (pacman/base-devel) + attente fin cloud-init (Fedora)
Deux échecs d'install ERPLibre sur VM constatés dans les logs :

Arch — install_arch_linux.sh utilisait « yay » (helper AUR ABSENT d'une
image cloud et qui refuse de tourner en root) et n'installait JAMAIS
base-devel : sur une image cloud fraîche rien ne s'installait, donc pas de
compilateur C -> pyenv : « no acceptable C compiler found » -> build de
Python 3.12 échoué -> pas de venv -> pip/poetry/repo absents. Réécrit avec
pacman (dépôts officiels) : base-devel (gcc/make), deps de build pyenv
(openssl/zlib/xz/tk/…), PostgreSQL (+ initdb, Arch ne l'initialise pas),
Node/npm, deps Odoo en best-effort paquet par paquet (pacman refuse toute
la transaction sur un seul nom inconnu). wkhtmltopdf (AUR) : ignoré
proprement.

Fedora — « Connection closed by remote host » (exit 255) dès le début :
« cloud-init status --wait » tournait dans une session SSH UNIQUE tuée
quand cloud-init régénère les clés d'hôte et REDÉMARRE sshd au 1er boot.
On attend désormais la FIN de cloud-init via des connexions COURTES
successives (chaque tentative survit à un redémarrage de sshd), AVANT de
lancer l'install — dans les deux chemins : _qemu_wait_ssh (streamé) et
_launch_one (détaché/monitoré). On matche sur le TEXTE de « cloud-init
status » (done/disabled/error/degraded) car son code de sortie n'est pas
fiable selon la version.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-28 07:19:17 +00:00
482a914ab8 [FIX] script qemu: bon paquet émulateur s390x sur apt (qemu-system-s390x)
Sur apt, qemu-system-misc NE contient PAS l'émulateur s390x (il fournit
alpha/avr/hppa/… mais pas s390x) : ensure_s390x_emulator installait donc
un paquet inutile puis échouait (« qemu-system-s390x toujours absent »).
Le binaire est fourni par le paquet dédié qemu-system-s390x.

Validé de bout en bout : déploiement réel Ubuntu 24.04 s390x émulé (TCG) ->
domaine type=qemu, machine s390-ccw-virtio, emulator qemu-system-s390x ->
boot OK, IP DHCP, SSH par clé (erplibre), sudo OK, uname -m = s390x
(IBM z15, /proc/sysinfo Type: 8561).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-28 07:09:21 +00:00
37a999b911 [ADD] script qemu: support architecture s390x (IBM Z, Ubuntu)
Ajoute --arch s390x au déploiement QEMU. Réalité constatée (juillet 2026) :
seul Ubuntu publie des images cloud s390x (cloud-images.ubuntu.com : OK) ;
Debian et Fedora n'en publient pas (404), Arch ne cible que x86_64/aarch64.
s390x est donc scopé à Ubuntu et rejeté proprement pour les autres distros.

deploy_qemu.py :
- FOREIGN_ARCHES / S390X_DISTROS : s390x n'est valide que pour Ubuntu.
- virt_install : sur s390x -> --arch s390x, --machine s390-ccw-virtio,
  --virt-type qemu (émulation TCG, pas de KVM sur hôte x86), console SCLP
  (pas de série ISA), amorçage IPL/zipl (aucun --boot UEFI/BIOS). Les
  disques/réseau bus=virtio sont mappés en virtio-ccw par libvirt.
- ensure_s390x_emulator : installe qemu-system-s390x au besoin
  (apt: qemu-system-misc, dnf: qemu-system-s390x, pacman:
  qemu-emulators-full, zypper: qemu-s390).
- Avertit que s390x est ÉMULÉ (lent) sur un hôte x86.

todo.py : le menu « Déployer une VM » demande l'architecture (s390x proposé
uniquement pour Ubuntu, avec avertissement lenteur) et passe --arch.

install_debian_dependency.sh : wkhtmltopdf n'a pas de build s390x -> skip
best-effort au lieu d'avorter l'install (la branche s390x rust-all existait
déjà pour compiler les wheels).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-28 07:03:19 +00:00
deddaeb6a9 [FIX] script qemu: no cloud-init package install (Fedora hang) + bigger disk
Fedora install stalled: the log stopped right after boot with no exit
marker. Cause: cloud-init was running "dnf -y install qemu-guest-agent
openssh-server" at first boot; on this host's slow VM network that dnf
took many minutes (metadata refresh + download), so cloud-init stayed
"running" and the install (which waits for cloud-init) never proceeded.

Fix: do NOT install any package via cloud-init. sshd is already present
in every cloud image (verified Ubuntu/Debian/Fedora/Arch) and is just
enabled via runcmd; the tools (curl/git/make…) are installed by the
ERPLibre bootstrap with optimised mirrors. cloud-init now finishes in
seconds (Fedora: "status: done" at 10s instead of blocking 5+ min).
--package still adds a cloud-init packages block on demand.

Also: when ERPLibre is installed via the infra menu, add
ERPLIBRE_EXTRA_DISK_GB (5G) to each VM's disk, because the image minimum
left only ~97 MB free after installation. Drop the now-useless
"--package git" (the bootstrap installs git).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-28 06:48:48 +00:00
137f4245ec [FIX] script todo: wait for cloud-init before install (Arch pacman lock)
The Arch install failed at once: "error: failed to synchronize all
databases (unable to lock database)" then "reflector: command not
found". Cause: cloud-init was still running its own pacman (installing
qemu-guest-agent/openssh) and held /var/lib/pacman/db.lck when our
bootstrap started, so every pacman call failed and reflector never got
installed.

Fix: the remote install now waits for cloud-init to finish first
("cloud-init status --wait", 15 min timeout) before touching any package
manager — this releases the apt/dnf/pacman lock cloud-init holds during
its package stage (helps all distros). For Arch, also drop a stale
db.lck when no pacman is actually running. Verified live: cloud-init
done, no lock, reflector + refresh + curl/git/make all succeed.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-28 06:27:15 +00:00
7a001a9b84 [IMP] script todo: show log path in dashboard + fast repo refresh (incl. Arch)
Dashboard: the info bar under the log now shows the selected VM's log
file path (in addition to its ssh command), so it can be opened/shared.

Install bootstrap: each package-manager branch first refreshes the repos
so the VM is as fast as possible, and Arch (pacman) is now supported:
- apt: apt-get update
- dnf: dnf makecache (dnf5 picks the fastest mirrors)
- pacman (Arch): reflector selects the 20 fastest HTTPS mirrors ->
  pacman -Syy -> install curl/git/make (Arch was previously unsupported
  by the bootstrap and would abort with "no package manager").
Validated live on the Arch VM: reflector + refresh + install all OK.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-28 06:10:58 +00:00
69d87f93c3 [FIX] script qemu: Arch SSH package name (openssh, not openssh-server)
cloud-init reported "status: error" on Arch because the seed's packages
list requested "openssh-server", which does not exist on Arch (the
package is "openssh"). Pick the SSH server package per distro: "openssh"
on Arch, "openssh-server" elsewhere. Verified on Arch: cloud-init now
finishes with "status: done", openssh installed, sshd active.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-28 05:59:08 +00:00
ea3f9c00cf [FIX] script qemu: Arch networking (network-config key = eth0)
Arch VMs booted (after the Secure Boot fix) but eth0 stayed DOWN and
cloud-init never finished -> no IP, no SSH. Cause found in the guest:
cloud-init's Arch renderer writes the systemd-networkd [Match] Name from
the ethernet KEY of the v2 config (ignoring "match:"), so our key
"primary" produced "Name=primary" which matches no interface (Arch's NIC
is eth0). Rename the key to "eth0": Arch now renders "Name=eth0" and
DHCPs; Debian/Fedora/Ubuntu still use "match: name: e*" (verified Debian
redeploy: enp1s0 UP with an IP), so no regression.

Arch is now fully working end to end: boot, DHCP IP, SSH by key, user
erplibre in sudo, passwordless sudo, console login erplibre/erplibre.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-28 05:56:11 +00:00
18d3f4461c [FIX] script qemu: disable UEFI Secure Boot (Arch boot)
OVMF Secure Boot rejected Arch's unsigned GRUB with "Access Denied" ->
"No bootable option" -> dropped to the firmware menu, never booted.
Disable Secure Boot in the UEFI boot (firmware.feature secure-boot=no):
Arch now boots and cloud-init applies user/password/hostname/ssh-key
(console login erplibre/erplibre works). Ubuntu/Debian/Fedora also boot
without Secure Boot (their signed shim is not required), no regression.

Note: Arch networking (eth0 stays down, cloud-init does not finish) is
still under investigation and tracked separately.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-28 05:49:28 +00:00
44d64fe87a [IMP] script qemu: add Arch Linux to the deploy catalog
Arch (rolling release, single "latest" version) joins ubuntu/debian/
fedora: official cloud image geo.mirror.pkgbuild.com/images/latest/
Arch-Linux-x86_64-cloudimg.qcow2 (cloud-init included), osinfo=archlinux
(known locally), UEFI boot + virtio seed like the others. ERPLibre
already has install_arch_linux.sh. Exposed in the infra/deploy menus.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-28 05:28:41 +00:00
3cb6f45269 [FIX] script install: Fedora wkhtmltopdf via AlmaLinux 9 RPM
wkhtmltopdf 0.12.6.1-3 no longer ships a fedora-* RPM (my URL 404'd).
The AlmaLinux 9 (EL9) RPM is compatible with Fedora — tested on the
Fedora 42 VM: "dnf install <almalinux9 rpm>" resolves the deps and
"wkhtmltopdf --version" reports 0.12.6.1 (with patched qt). Use it, with
an AlmaLinux 8 fallback.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-28 05:23:24 +00:00
7def76eb62 [FIX] script install: Fedora postgres initdb (locale) + dev group id
Tested make install_os on a real Fedora 42 VM (exit 0: gcc 15, psql,
node 22 installed). Two fixes from the run:

- postgresql-setup --initdb failed with "invalid locale settings"
  because Fedora cloud images ship no LANG; force a valid locale via
  PGSETUP_INITDB_OPTIONS=--locale=C.UTF-8 and wipe a partial data dir
  first (a failed init leaves /var/lib/pgsql/data/log behind and blocks
  the retry). Verified: cluster PG 16 initialised, service active,
  erplibre superuser created.
- the dev-tools group was referenced by display name ("C Development
  Tools and Libraries", "No match"); use the group id c-development.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-28 05:17:40 +00:00
84e383a3b1 [FIX] script install: Fedora support + Ubuntu apt-lock/postgis fixes
From the QEMU install logs: Debian 12 succeeded, Ubuntu 24.04 and
Fedora 42 failed.

Ubuntu (install_debian_dependency.sh):
- apt failed with "Could not get lock" (cloud-init/unattended-upgrades
  hold it on first boot) -> all apt-get calls now use
  DPkg::Lock::Timeout=600 so apt waits for the lock.
- "postgis" is not a package on Ubuntu 24.04, so the postgresql line
  exited 1 before installing build-essential -> no C compiler -> pyenv
  could not build Python 3.12.10. PostGIS is now best-effort (tries
  postgis, then postgresql-postgis) and never aborts; postgresql-contrib
  is added.

Fedora (new install_fedora_dependency.sh, wired into install_dev.sh):
- install_dev.sh dispatched Fedora to the apt script; it now has a
  fedora / ID_LIKE branch calling a dnf-based dependency installer
  (dev tools, postgresql-server + initdb, pyenv build deps, node, etc.),
  using --refresh --skip-unavailable to tolerate mirror/name issues.

Bootstrap (todo.py): the dnf "curl git make" install hit a GPG/checksum
failure on a fresh image; it now uses --refresh and retries after
"dnf clean all".

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-28 05:07:10 +00:00
4a821226fb [IMP] script todo: print all log paths when opening the install monitor
After "Opening the interactive monitor..." the install now lists every
VM's log file path, so they can be read or shared even when leaving the
dashboard before the installs finish.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-28 04:41:41 +00:00
0830c895eb [FIX] script todo: reliable curl/git/make install + copyable logs
Root cause of "git/make: command not found": the bootstrap ran
"apt-get update -qq && apt-get install -y $PKGS". Inside an && list,
set -e does NOT abort on failure, so when apt-get update failed (flaky
VM network) the install was silently skipped and the script marched on
without git/make. Now: "apt-get update || true; apt-get install -y
$PKGS" (update best-effort, install mandatory), followed by an explicit
"command -v curl git make" check that exits with a clear message
("Outil manquant ... (reseau de la VM ?)") instead of a cryptic failure
later. Shared by the streamed and the monitored install paths.

Dashboard: add "c" to copy the selected VM's full log to the clipboard
(OSC 52, works over SSH) with a notification; the ssh bar documents
Shift+drag for native terminal selection; on close, print a ready-to-
copy "tail -n +1 <logdir>/*.log" to share the logs.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-28 04:40:18 +00:00
d4d3d801c3 [ADD] script todo: interactive Textual dashboard for ERPLibre installs
Deploying ERPLibre (single VM [1] and infra [4]) now asks "Interactive
monitoring dashboard?". When yes, the installs run DETACHED (setsid, one
log file + exit marker per VM) and a Textual dashboard opens:

- left: a table of VMs with live status ( running /  done /  failed
  with exit code) and elapsed time;
- right: the selected VM's log, tailed live (f toggles follow);
- footer: the VM's ssh command; s suspends the dashboard and SSHes in;
- q quits back to the menu — the installs keep running detached, so you
  can leave before they finish and reopen later on the same log dir.

New module qemu_install_monitor.py holds the detached launcher and the
Textual app. The remote install script is factored into
_qemu_erplibre_remote_cmd. Falls back gracefully if textual is missing.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-28 04:27:25 +00:00
8d8d0750b0 [FIX] script todo: wait for SSH before the ERPLibre install
Right after boot the VM's sshd may not be up yet (notably on Fedora),
so the install failed with "Connection refused". _qemu_install_erplibre_vm
now polls SSH (ssh ... true, BatchMode) for up to 3 minutes and skips
with a clear message if it never answers, instead of failing instantly.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-28 04:10:33 +00:00
83a28ed9e8 [IMP] script todo: add "principal" choice to infra (one main VM per distro)
The infra distribution prompt now accepts "principal" (alongside
numbers and "all"): it deploys the default version of each distro —
ubuntu 24.04, debian 12, fedora 42 — one VM each. The default version is
also marked with a * in the distro listing so it is visible.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-28 04:08:38 +00:00
83f71561f8 [FIX] script todo: install curl/git/make before ERPLibre make targets
Minimal cloud images ship without make (and often without curl), so the
ERPLibre install cloned the repo then died on "make: command not found".
The remote bootstrap now installs curl, git and make via apt (Debian/
Ubuntu) or dnf/yum (Fedora) — running apt-get update first since
cloud-init did not refresh the lists — before cloning and running
make install_os / make install_odoo_18.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-28 04:03:03 +00:00
0aa84ed1e3 [IMP] script install: quiet poetry/repo by default, EL_VERBOSE to opt in
Installation was very noisy: poetry ran "install -vvv" and repo sync /
git daemon ran with -v/--verbose. They are now quiet by default
(poetry -q, repo sync -q, no git daemon --verbose) and the detailed
logs come back only when EL_VERBOSE=1.

Applied to install_locally.sh (poetry) and every manifest script (repo
sync + git daemon). env_var.sh documents EL_VERBOSE and respects a value
already set in the environment, so "EL_VERBOSE=1 make install_odoo_18"
works.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-28 03:57:04 +00:00
65a0d6f907 [IMP] script todo: offer ERPLibre install on single VM + run make targets
"Deploy a new VM" now asks, after a successful deploy, whether to
install ERPLibre into ~/git/erplibre (pick a branch), just like the
infra command.

Installing ERPLibre no longer only clones the repo: after the clone it
runs "make install_os" then "make install_odoo_18" over SSH (the
erplibre user has passwordless sudo from cloud-init). The Odoo target is
a constant (ERPLIBRE_ODOO_TARGET) and both the single-VM and infra flows
use the same install path.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-28 03:48:56 +00:00
6ac7624950 [IMP] script todo: extend "Clean up QEMU" with 4 more sweeps
The cleanup command now runs, each listed and confirmed independently:

1. orphan files (disks/seeds/.part/nvram) — as before;
2. ghost domains: libvirt domains whose disk no longer exists ->
   offer destroy + undefine --nvram;
3. stale codename-named Ubuntu images (noble/resolute/... left by the
   move to /releases/ version-named images) -> targeted delete;
4. orphan ~/.ssh/config entries: "Host erplibre-*" blocks with no
   matching VM (personal SSH hosts are never touched);
5. stale libvirt DHCP leases whose MAC belongs to no VM (best-effort
   rewrite of the dnsmasq status file + SIGHUP; they also self-expire);
6. the full base-image cache remains an explicit opt-out at the end.

Detections verified read-only on the host.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-28 03:12:43 +00:00