- listMachineEvents (machine_events, 30 derniers, desc) + route GET /machines/:id/events
- api machineEvents ; section repliable « Timeline » dans le panneau détail
(badge sévérité + horodatage), exploite les events déjà enregistrés par recordEvent
tsc 0 · 118 tests · build OK.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- extractImportantMessages (TDD) : E:/dpkg error → error, W:/GPG → warning,
déprecations/EOL → future_major_change ; nettoyage des secrets dans les URLs
- recordImportantMessages : dédup par (machine, source, message) non acquitté →
maj lastSeenAt, sinon insert (firstSeen/lastSeen) dans important_messages
- branché dans refreshMachine (sortie APT) avec snapshotId
- routes GET /machines/:id/messages + POST .../:msgId/ack
- UI : carte « Messages importants » (badge sévérité + ack) dans le panneau détail
tsc 0 · 118 tests · build OK.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- updateMachine accepte name/hostname/port (correction d'identité réseau)
- rebootAndRebind : reboot sur l'ancienne connexion → attente du retour sur la
NOUVELLE IP (verifyReboot avec host cible) → maj BDD (hostname + nom) si OK.
Sécurité : BDD inchangée si la machine ne revient pas (récupération console/backups)
- execute post_install : si identity_network + reboot coché + succès, déclenche
rebootAndRebind et joint le RebootResult ; statut error si reconnexion échoue
tsc 0 · 113 tests · build OK.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- précheck en tête : refuse proprement si OS != debian (os_not_supported),
si netplan présent (unsupported_network_manager) ou si /etc/network/interfaces
absent (ifupdown_not_found) — au lieu d'écrire une conf inopérante
- manifeste : label « (Debian/VM) » + description précisant la cible ifupdown
et l'application au reboot
Validé en réel sur Debian VM (ens18) : strophe DHCP commentée + drop-in statique.
sh -n OK · tsc 0 · 113 tests.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Le template SJ-8 était un stub (echo STATIC_TARGET sans écriture). Désormais :
- /etc/hostname + hostnamectl, ligne 127.0.1.1 <fqdn> <host> dans /etc/hosts
- IP statique via drop-in /etc/network/interfaces.d/<iface>.cfg (ifupdown),
neutralisation awk de la strophe DHCP existante + source interfaces.d
- sauvegardes horodatées avant écriture ; réseau appliqué AU REBOOT (ne coupe
jamais SSH en live) ; FILE_MODIFIED émis après écriture réelle
Cible Debian/ifupdown (netinstall). syntaxe sh -n validée sur rendu.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Branche le frontend sur le moteur post-install (SJ-8) :
- liste des profils (badge de risque), dépliage → champs de formulaire typés
(text/select/bool/secret), pré-remplis depuis defaults + utilisateur SSH
- Preview (script rendu, secrets masqués) en Popup
- Exécuter : profils sûrs en direct, profils à risque (identity_network) via
confirmation Popup → action_request approuvé ; auto-sélection machine →
flux visible dans le terminal
- api client : getProfiles / previewProfile / runProfile + types
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
L'app lit process.env sans dotenv ; les scripts npm ne fournissaient pas
SU_MASTER_KEY. Ajoute --env-file=.env pour que pnpm dev / pnpm start
fonctionnent directement.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Branche le frontend sur le backend Docker (SJ-4/5/6) :
- scan, configuration des racines Compose, liste stacks + services avec
badges de statut (candidat/activé/maj dispo/à jour)
- activer/ignorer/désactiver un stack ; pull-check (non destructif)
- apply/down/prune via action_request + confirmation Popup (design system)
- toute action streamée auto-sélectionne la machine → flux visible dans le
terminal de droite (outputHub rejoue le buffer)
- api client : docker settings/roots/scan/stacks/status + action-requests
- icônes trash/check, styles docker-* (variables CSS uniquement)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Rend le flux Docker déclenchable via l'API (prérequis SJ-5/SJ-6) :
- GET /machines/:id/docker/settings — settings + racines Compose
- POST /machines/:id/docker/roots — déclare/active les racines à scanner
- POST /machines/:id/docker/scan — scan passif (background, WS)
- GET /machines/:id/docker/stacks — liste stacks + services
- PATCH /machines/:id/docker/stacks/:stackId — cycle candidate→enabled→ignored
dockerScan: getDockerSettings, listStacks, setStackStatus. Les actions
pull-check/apply/down restent réservées aux stacks enabled.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Après une action APT appliquée avec succès, relance refreshMachine pour
que la webui reflète l'état réel des paquets. Échec de refresh = event
warning non bloquant (post_action_refresh_failed).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
tache2.md: mission design/investigation, périmètre strict, clôture obligatoire.
validation_tache2.md: grille de validation, gate avant toute phase de dev.
amelioration.md: retour d'usage (séparation terminal entre machines).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Suite au test live: retour d'usage (amelioration.md) sur la séparation
des sorties entre machines distinctes dans le terminal.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
pnpm v10 bloque les scripts de build par défaut: better-sqlite3 n'avait pas
son binaire natif dans l'image Docker. Déclarer better-sqlite3/ssh2/cpu-features/esbuild
comme builds autorisés. Conteneur vérifié: health OK, serveur démarre.
Bug attrapé par la vérif end-to-end (Task 19).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Le bundle ESM crashait au runtime (Dynamic require of 'events' via ws).
Externaliser les dépendances (skipNodeModulesBundle) — elles sont fournies
par pnpm install --prod dans l'image. Bug attrapé par la vérif end-to-end (Task 19).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>