Commit Graph

57 Commits

Author SHA1 Message Date
gilles bdbe7af55c docs(amelioration): backlog — update-all, listing double-scroll, su fallback, scripts configurables, partages Samba/NFS
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-06 19:20:24 +02:00
gilles 1530409d3b feat(post-install): identity_network reboote et rebascule l'IP en BDD (tâche 4)
- 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>
2026-06-06 19:12:39 +02:00
gilles 3ea2e66359 fix(post-install): identity_network cadré Debian/ifupdown (VM) avec précheck
- 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>
2026-06-06 19:03:28 +02:00
gilles aaf1b4988d fix(post-install): identity_network écrit réellement hostname + /etc/hosts + IP statique
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>
2026-06-06 18:47:44 +02:00
gilles d1b0290e3b feat(apt): analyse des dépôts APT (lecture seule) (tâche 4)
- template repositories (deb lines + deb822), non destructif
- analyzeRepositories (TDD) : composants, repos, détection Proxmox
  enterprise/no-subscription, warnings (pve_enterprise_without_subscription,
  pve_repo_missing) + notes Debian/Ubuntu composants manquants
- route POST /machines/:id/apt-repositories ; api analyzeRepositories
- popup config : bloc « Dépôts APT » (composants + warnings + notes)

Analyse uniquement (modification = action validée séparée, future). tsc 0 · 113 tests · build OK.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-06 18:41:11 +02:00
gilles e3e824185f feat(probe): sonde enrichie CPU/RAM/disques + recommandations de profils (tâche 4)
- template machine-probe : lscpu Model name + nproc, MemTotal, lsblk disques
- parseProbe étendu (cpuModel/cpuCores/memoryBytes/disks) + buildRecommendations
  (KVM/QEMU → vm_guest_tools) ; tests TDD
- runProbe persiste cpu/mem/disks dans machine_hardware ; /probe renvoie recommendations
- popup Sonde affiche cpu/ram/disks + profils conseillés

tsc 0 · 110 tests · build OK.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-06 18:36:49 +02:00
gilles c390addadb feat(metrics): machine_metrics_simple — CPU/RAM/disque live par machine (tâche 4)
- template machine-metrics (loadavg/nproc, /proc/meminfo, df -B1) non destructif
- parseMetrics (TDD) → cpu load/cores, mémoire kB→B + %, filesystems, warnings >=90%
- collectMetrics (SSH léger) persiste machine_metrics_latest ; getLatestMetrics (sans SSH)
- routes GET /machines/:id/metrics + POST /metrics/collect ; api latestMetrics/collectMetrics
- section Hardware : bloc métriques live (CPU/RAM/disques + alertes) + bouton Collecter
  → comble le gap « Health » de la tâche 3

tsc 0 · 108 tests · build OK.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-06 17:01:45 +02:00
gilles 58abebf687 feat(ui): ajout machine OS/type, section Hardware, identité app (tâche 3)
- AddMachineModal : sélecteurs OS + Type machine ; createMachine accepte
  osFamily/machineKind (manuel prioritaire, "Autre/auto" → détection os-release)
- section Hardware sur la tuile + panneau détail : os/type/virt/arch/gpu/réseau
  depuis machine_hardware (sonde) via GET /machines/:id/hardware
- identité : favicon.svg (serveur + LED Gruvbox), favicon.ico, apple-touch-icon,
  PWA 192/512, site.webmanifest ; liens + theme-color dans index.html

tsc 0 · 104 tests · build OK.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-06 14:07:46 +02:00
gilles 3b16fdd52a feat(post-install): catalogue de profils — paquets, Docker officiel, partages, VM tools (tâche 2 SJ-9)
- mécanisme presetVars (variables fixes injectées au rendu, surchargées par le formulaire)
- 6 profils : base_tools / network_tools / dev_git (listes de paquets, low),
  docker_official (dépôt officiel Debian, confirmation), sharing (Samba/NFS/mDNS, confirmation),
  vm_guest_tools (qemu/vmware)
- 4 templates custom (install-package-groups, docker-official-debian, sharing, vm-guest-tools)
  émettant PKG_INSTALLED/SERVICE_ENABLED/ERR → réutilise buildPostInstallResult
- l'UI post-install générique les expose automatiquement (manifeste → formulaire → run)

tsc 0 · 104 tests · build OK · boot OK (8 profils servis). Clôt le volet moteur tâche 2.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-06 12:40:20 +02:00
gilles 4eb0335900 feat(ui): section post-install interactive (profils + preview) (tâche 3)
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>
2026-06-06 10:57:44 +02:00
gilles e6f4ae470b feat(post-install): moteur de profils + bootstrap + identité/réseau (tâche 2 SJ-8)
- templates custom/bootstrap-root + identity-network (sortie structurée parsable,
  sauvegardes, échec contrôlé, jamais de coupure réseau sans reconnexion)
- postInstall: registre de manifestes (champs typés + defaults/defaultFrom),
  validateProfileValues + maskSecretValues + buildPostInstallResult (TDD),
  renderProfile/previewProfile (masquage secrets), runPostInstall (SSH)
- execute: RunActionOpts.profileId/values + branche post_install (bloc postInstall)
- action_requests: post_install accepté, payload profileId/values transmis à approve
- routes: GET /profiles, POST .../preview (script masqué + validation),
  POST .../run (action_request si requiresConfirmation, sinon direct)

Champs = formulaire (pas de question SSH interactive) ; secrets jamais sérialisés ;
identity_network exige confirmation. tsc 0 · 101 tests · build OK · boot OK.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-06 08:02:32 +02:00
gilles faa654c95a feat(ui): config machine (sonde+proxy), mode Listing, défaut apt-cacher-ng
- popup Profil sur la tuile : sonde machine → propositions os_family/
  machine_kind/virtualization avec Appliquer ; proxy APT (mode + url) +
  appliquer persistant
- mode d'affichage Tuiles/Liste : toggle + bouton Ajouter déplacés dans le
  header de page ; vue Liste = liste compacte + panneau détail « Machine view »
  (sections Docker/Post-install dépliées ; pliées en mode tuile)
- Popup rendu via portail document.body (position fixed, z-index 1000) :
  passe au premier plan, échappe au backdrop-filter des tuiles
- Paramètres : onglet Proxy APT (défaut apt-cacher-ng + appliquer à toutes
  les machines) ; AddMachineModal pré-remplit le proxy par défaut
- api client : settings, updateMachine, probe ; icônes network/grid/list

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-06 07:53:57 +02:00
gilles 2b684da9cd feat(api): profil machine éditable, sonde, et réglages globaux apt-cacher-ng
- machines : updateMachine (PATCH /machines/:id) + POST /machines/:id/probe
  (sonde synchrone → faits + proposition de correction) ; MachineView expose
  machineKind/virtualization ; CreateMachineInput accepte aptProxyMode persistent
- app_settings (clé/valeur, migration 0006) + service appSettings :
  défaut apt-cacher-ng (mode + url) ; applyProxyToAllMachines
- routes /settings : GET, PUT /apt-proxy, POST /apt-proxy/apply-all

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-06 07:53:47 +02:00
gilles 0ab6b1d392 3 2026-06-06 07:24:30 +02:00
gilles bafb085995 feat(os): profils Proxmox/RPi + machine_probe + proxy persistent (tâche 2 SJ-7)
- templates proxmox/ (update-analyze: dépôts PVE ; full-upgrade) et raspbian/
  (update-analyze: espace disque ; full-upgrade)
- execute résout les actions APT par profil OS (resolveTemplate) → proxmox/
  raspbian si dispo, sinon fallback apt/ (non-régression debian/ubuntu vérifiée)
- machine_probe (lecture seule) : template + parseProbe/proposeCorrections (TDD)
  → propose os_family/machine_kind/virtualization, persiste machine_hardware,
  n'applique jamais auto ; branche execute + allowlist route
- apt_proxy_persistent : ActionType + template idempotent (/etc/apt/apt.conf.d/
  01proxy, backup) + TemplateVars.aptProxyUrl + allowlist route

tsc 0 · 95 tests · build OK · résolution OS vérifiée.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-06 07:14:43 +02:00
gilles b5ec14dcd8 chore: charge .env via --env-file dans dev:server et start (Node 22+)
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>
2026-06-06 07:09:07 +02:00
gilles c79c3e5ccb feat(ui): section Docker interactive sur la tuile machine (tâche 3)
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>
2026-06-06 07:09:07 +02:00
gilles 2c15b8c06b feat(docker): routes de gestion des stacks (settings/roots/scan/list/enable)
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>
2026-06-06 06:24:43 +02:00
gilles 47fe952240 feat(settings): backup/restore de la base de données (amelioration #4)
- service dbBackup : createBackup (VACUUM INTO → archive .db cohérente),
  validateSqlite (header + integrity_check + schéma), prepareRestore
  (sauvegarde de sécurité auto + dépôt <db>.incoming)
- swap hors-ligne au démarrage (db/client.ts) : aucune corruption d'une base
  ouverte ; restauration appliquée au redémarrage
- routes GET /system/db/info|backup, POST /system/db/restore
- lib api : dbInfo / dbBackup (download navigateur) / dbRestore (upload)
- SettingsModal : onglet « Base de données » (taille, télécharger, restaurer
  avec confirmation Popup), icônes database/upload, styles DS variables only

Testé end-to-end : backup 184 Ko valide, restore + safety .bak + swap au boot,
fichier invalide rejeté. tsc 0 erreur · 91 tests · build OK.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-06 06:13:03 +02:00
gilles edb22a59c7 feat(docker): apply/prune/down + socle action_requests (tâche 2 SJ-6)
- migration 0005 : tables docker_image_events + action_requests
- templates apply-compose (up -d --remove-orphans), prune-images (safe/agressif),
  down-compose (sans volumes/rmi)
- dockerApply: parsers TDD (apply recreated/running/exited, prune images+bytes,
  down removed, parseHumanBytes) + orchestration applyStack/pruneImages/downStack
  réservée aux stacks enabled, insère docker_image_events
- actionRequests: create/approve/reject/list — actions destructives validées
  explicitement (Hermes propose, opérateur approuve, run en arrière-plan) ;
  hors API directe (POST /:id/actions reste passif uniquement)
- routes /machines/:id/action-requests + /action-requests/:id[/approve|/reject]
- execute: RunActionOpts.aggressive, branches apply/prune/down, helper
  archiveExecution mutualisant le boilerplate d'archivage

tsc 0 erreur · 91 tests · build OK · boot OK (migrations 0000→0005).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-06 06:05:59 +02:00
gilles b1c81ba518 feat(docker): pull-check + comparaison déterministe par stack (tâche 2 SJ-5)
- template docker/pull-check.sh.tpl (pull sans up, inspect before/after)
- dockerPull: parseDockerPullCheck + buildDockerPullResult (TDD) — compare
  image id/digest/label OCI → services up_to_date|updates_available|error,
  changes operation=pulled ; erreurs registry nettoyées (URL/token/password)
- dockerDedupKey (digests prioritaires, fallback image ids) + DockerImageChange.dedupKey
- pullCheckStack: SSH + upsert docker_stack_services, refuse stack non enabled,
  refresh Docker séparé (hors refreshMachine, pas de pull auto)
- execute: runAction(opts.stackId), branche docker_pull_check, injection stackDir
  (corrige docker_inspect_current) ; route: allowlist Docker passifs + pull_check,
  destructives toujours hors API jusqu'à action_requests (SJ-6)

Pas de migration (schéma SJ-4 suffisant). tsc 0 erreur · 85 tests · build OK.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-05 21:02:38 +02:00
gilles 2af8e74079 feat(docker): scan/inspect passifs des stacks Compose (tâche 2 SJ-4)
- 4 tables Docker (settings/compose_roots/compose_stacks/stack_services)
  + migration 0004 (timestamps journal monotones)
- templates docker/scan-compose + inspect-compose ; renderTemplate bascule
  sur délimiteurs <% %> pour les templates docker/ afin de préserver les
  Go-templates {{.ID}} intacts
- dockerScan: parseDockerScan (TDD) + scanDockerStacks (persiste stacks
  candidats, complète la détection par labels)
- action docker_scan branchée dans execute (route dédiée, archivage report/log)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-05 20:54:52 +02:00
gilles 434a149f1f fix(execute): refresh snapshot après apt upgrade/full-upgrade (amelioration #3)
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>
2026-06-05 20:54:38 +02:00
gilles 08919752e3 feat: socle BDD (tâche 1.9 Phase 1-2) + moteur APT (tâche 2 SJ-0→3) + WIP capabilities/auth/Rust
Checkpoint multi-chantiers (arbre vert : tsc 0 erreur, 70 tests, build OK).
- tâche 1.9 Phase 1 : schéma socle (machine_state/events/reports/raw_artifacts/
  hardware/metrics + colonnes étendues) + wiring refresh/execute. Migration 0002.
- tâche 1.9 Phase 2 : machine_credentials + machine_host_keys (non destructif,
  dual-read + backfill). Migration 0003. Fix séquence journal de migration.
- tâche 2 : SJ-0 (types étendus rétro-compatibles, réducteur Docker, resolveTemplate),
  SJ-1 (update-analyze enrichi), SJ-2 (apply + diff dpkg + timeout inactivité SSH),
  SJ-3 (reboot vérifié boot_id).
- WIP parallèle inclus : /api/capabilities, auth/apiTokens/apiClients, system metrics,
  scaffold app_rust, ajustements frontend.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-05 19:50:25 +02:00
gilles 0fbca06d3d docs: roadmap tâches 1.9-8 (briefs, gates de validation, designs tâche 2) + plans d'implémentation
Cartographie complète (liste_taches/coherence_taches), briefs tacheN + gates
validation_tacheN, design tâche 2 (docs/design/tache2/), specs/plans jalon 1-2
et tâche 1.9/2 (Phase 1, Phase 2, SJ-0→3). Validations consignées (1.9 , 2-8 🟡).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-05 19:50:25 +02:00
gilles f9ce991ec5 feat(ui): classes layout header/statusbar/inputs/terminal
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-05 05:27:04 +02:00
gilles cebe991601 feat(ui): helper sumUpdates (TDD)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-05 05:26:31 +02:00
gilles b9699bfb8f feat(ui): helper de thème dark/light persisté (TDD)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-05 05:26:00 +02:00
gilles d3bf4a9fd2 feat(ui): brancher le design system (exports ESM, Font Awesome, polices offline)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-05 05:25:21 +02:00
gilles f8a8478749 docs: consignes tâche 2 (design moteur templates) + gate de validation
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>
2026-06-05 05:23:35 +02:00
gilles 1310bc1637 docs: plan d'implémentation jalon 2 (polish design system)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-05 05:09:14 +02:00
gilles 8d105b63ec docs: spec jalon 2 - séparation terminal par machine + remontée d'état
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>
2026-06-05 05:05:27 +02:00
gilles 50df83fda1 docs: spec jalon 2 (polish design system)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-05 04:52:50 +02:00
gilles 1e1be7f627 docs: fondation projet (CLAUDE.md, design system, spec + plan jalon 1)
Ignore les dépôts de référence imbriqués (linux-update-dashboard, nas-ops).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-05 04:41:30 +02:00
gilles 032287e2ab fix: autoriser le build des deps natives (pnpm onlyBuiltDependencies)
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>
2026-06-05 04:30:19 +02:00
gilles db6dd3615f fix: externaliser les deps npm dans le bundle tsup
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>
2026-06-05 04:27:22 +02:00
gilles 74371c442b feat: packaging Docker (Dockerfile + compose, volumes data/reports)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-05 04:24:03 +02:00
gilles 17134ed1a6 feat: UI 3 volets (Hermes stub, dashboard tuiles, terminal xterm.js)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-05 04:20:13 +02:00
gilles 46d27768f3 feat: librairies client API REST + WebSocket
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-05 04:18:52 +02:00
gilles bd87e84742 feat: scaffolding client Vite/React + design system Gruvbox
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-05 04:18:33 +02:00
gilles f6fcf4dbb6 feat: entrée serveur (Hono + WebSocket /api/ws + worker)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-05 04:15:42 +02:00
gilles c3584f4ec8 feat: routes HTTP Hono (machines, refresh, actions, executions)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-05 04:13:15 +02:00
gilles b4d47901b6 feat: worker in-process de refresh périodique (croner)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-05 04:12:21 +02:00
gilles f5f361a349 fix: ORDER BY sur getLatestSnapshot + lisibilité condition EXIT
Suite revue batch D.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-05 04:10:56 +02:00
gilles 1fb93873ac feat: service execute (full-upgrade/reboot -> execution + rapport archivé)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-05 04:05:58 +02:00
gilles ed3cb91cd4 feat: génération de rapport Markdown d'exécution
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-05 04:05:23 +02:00
gilles 0576820059 feat: service refresh (check APT -> snapshot canonique)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-05 04:04:28 +02:00
gilles 3724326d81 feat: service machines (CRUD, test-connection, détection OS)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-05 04:03:51 +02:00
gilles 0e8d5a9bcf feat: hub de sortie WebSocket avec buffer rejouable
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-04 21:07:20 +02:00
gilles c520ca5a17 feat: couche SSH (password, sudo -S, exec streaming)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-04 21:06:37 +02:00