Passer le protocole agent ↔ console à gRPC #1

Merged
dxsk merged 7 commits from chantier/grpc into main 2026-09-10 15:52:39 +02:00
Owner

⚠️ La portée a dépassé le titre. Cette branche contient le passage à gRPC
plus trois chantiers décidés en cours de route (garde-fou de mise à jour,
tri des tableaux, édition vim). Si tu préfères une PR par chantier, les
commits sont découpés proprement et se rejouent séparément — dis-le et je
scinde.

Remplace le cadrage maison [u32 BE][JSON] par gRPC (tonic), après évaluation
chiffrée des candidats dans spike/ (voir spike/RAPPORT.md).

1. Passage à gRPC

Le défaut le plus visible n'était pas le format des messages mais l'absence
de multiplexage
: pendant un transfert de fichier, une frappe du shell mettait
232 ms au p90 (jusqu'à 347 ms), mesuré sur le mesh. Le contrôle de flux par
stream
de HTTP/2 ramène ça à 44 ms — tout en transférant plus vite (40 contre
31 Mio/s).

Ce que le transport prend en charge désormais, et qui disparaît du code :

  • corrélation requête/réponse (plus d'id, plus de table pending, plus de
    thread lecteur démultiplexeur) ;
  • fin de flux (is_terminal() et ses vingt bras à tenir à jour) ;
  • annulation (lâcher un flux suffit : l'op Cancel, le registre d'AbortHandle
    et la table de sessions shell n'ont plus de raison d'être — et une console qui
    disparaît ne laisse plus de PTY orphelin) ;
  • tolérance de version (UNIMPLEMENTED au lieu d'une session coupée, donc plus
    besoin du décodeur tolérant decode_request).

Défaut corrigé au passage : FilePut mettait le fichier entier en base64
dans une trame unique plafonnée à MAX_FRAME. Au-delà de ~48 Mio, l'agent
refusait la trame et coupait la connexion sans message d'erreur. Le
client-streaming supprime la limite — vérifié sur le mesh à 64 et 200 Mio,
empreintes SHA-256 comparées.

Choix de conception : les types applicatifs (serde) sont conservés à côté
des types générés, avec une couche de conversion explicite
(protocol/src/conv.rs). C'est ce qui permet de migrer le transport sans
toucher au frontend
— la forme de l'événement agent-msg est inchangée — ni
aux analyseurs de comptes, de pare-feu et de runbooks, ni à leurs tests. Le
compte de lignes monte (≈670 lignes de conversions contre 240 de plomberie
supprimées) ; ce qui baisse, c'est le risque : le code parti était celui des
courses critiques.

console/src/identity.rs garde exprès un client de l'ancien dialecte : un
agent pré-gRPC ne répond pas du tout, et une erreur de transport nue
n'apprendrait rien à l'utilisateur. La sonde le reconnaît et rend le chemin de
son binaire pour le redéployer.

2. Garde-fou de mise à jour de l'agent

La console proposait la mise à jour quel que soit le binaire candidat. Deux
conséquences, dont une grave.

La grave : la release roulante agent-latest de la forge porte encore le
binaire d'avant gRPC (commitish 8c90418, 4 172 464 octets), puisque cette
branche n'est pas fusionnée. Cliquer « Dernier paquet de la forge » sur un hôte
migré téléchargeait ce binaire, le poussait avec succès — l'agent en place
étant gRPC, il l'acceptait — puis l'agent se remplaçait, redémarrait, et
devenait injoignable jusqu'à un redéploiement par SSH.

La gênante : le bouton était proposé même quand l'agent tournait déjà sur le
binaire candidat.

L'agent grave donc une ligne d'identité dans son propre binaire
(NBOPS-AGENT-META/1 protocol=<n> commit=<sha>), que la console retrouve par
recherche d'octets. Ce choix plutôt qu'un sidecar publié par la CI parce que la
console a toujours les octets sous la main : ça couvre les trois sources —
forge, agent embarqué, fichier choisi à la main — avec un seul mécanisme, là où
un sidecar laisse la troisième découverte. Et un binaire d'avant gRPC n'a pas le
marqueur, ce qui l'identifie exactement comme il faut.

La décision est une fonction pure, verdict_maj, couverte par 9 tests.

3. Tableaux triables, et retrait de la bascule « live »

Les 8 tableaux de l'application se trient en cliquant sur un en-tête :
processus / interfaces / disques du tableau de bord, unités systemd,
gestionnaire de fichiers, règles nftables et ufw, groupes locaux.

Logique partagée (compareCells / sortRows / nextSort + un composant
SortBtn) plutôt que recopiée huit fois. Trois choix qui méritent d'être dits :

  • le comparateur traite nombres et texte, avec localeCompare numérique :
    « ens10 » se range après « ens9 » ;
  • le tri est stable, ce qui compte plus qu'il n'y paraît — le tableau des
    processus est réécrit à chaque échantillon poussé, un tri instable ferait
    sauter les lignes une fois par seconde ;
  • les valeurs absentes vont en dernier dans les deux sens.

SortBtn ne fournit que le bouton, pas le <th> : chaque tableau a sa propre
mise en forme d'en-tête dans son style scopé, et un <th> émis par un composant
tiers en sortirait. aria-sort reste donc sur la cellule.

La bascule « live (push ~1 s) » disparaît avec le bouton « Rafraîchir » :
l'abonnement est permanent. Elle datait d'un temps où le push était optionnel.

4. Édition d'un fichier via vim

Cliquer un fichier ouvre vim dessus dans l'onglet Shell. ShellIn.Open porte
désormais program et args séparés, exécutés sans shell.

Ce découpage est un choix de sûreté : une commande unique à découper obligerait
à échapper le chemin, et un nom de fichier avec une espace, une apostrophe ou un
point-virgule deviendrait une injection. Fixé par un test : un argument
contenant ; touch <témoin> # doit ressortir entier et ne rien exécuter — le
test échoue si le fichier témoin apparaît.

Vérifications

  • 140 tests : 64 (protocol + agent), 49 (console), 27 (frontend).
    make ci passe : fmt, clippy -D warnings, tests, frontend, cohérence du dist.
  • Cross-compile Windows (make win) : OK.
  • Bout en bout sur le mesh, contre ep1 et vps.kxh-studio.fr via
    agent probe : appels unaires, flux, annulation par abandon, PTY
    bidirectionnel, code de sortie propagé, transferts 8 / 64 / 200 Mio avec
    empreintes comparées, et --edit pour vim.
  • Avec la vraie console Windows : connexion, tableau de bord alimenté en
    push, shell bidirectionnel, déconnexion qui referme bien le TCP.

Ce qui n'est pas couvert par des tests, sciemment

L'implémentation du service gRPC et la pompe de flux de la console sont du
câblage qui demande un agent vivant ou un AppHandle Tauri : couvertes par
agent probe de bout en bout. Les composants Svelte n'ont pas de harnais de
test dans ce dépôt — seule la logique extraite dans util.js est testée. Le
rendu visuel du tri et de l'édition vim n'a pas pu être contrôlé à l'écran.

À savoir avant de fusionner

  1. protoc >= 3.21.12 devient un prérequis de build (ajouté à
    scripts/ci-rust.sh avec contrôle de version ; Debian 13 fournit exactement
    ce plancher).
  2. Chaque agent déployé doit être redéployé une fois par SSH : la rupture de
    transport le rend injoignable autrement. État du parc au 2026-09-10 —
    à jour : ep1, vps.kxh-studio.fr · à redéployer : ep2, forge,
    monitor, pbs1, pve1 · mtmg était injoignable.
  3. La fusion referme d'elle-même le piège de agent-latest : la CI republiera
    un agent gRPC.

🤖 Generated with Claude Code

https://claude.ai/code/session_01GzHyvUbKutGrRcWjyfwDkT

> ⚠️ **La portée a dépassé le titre.** Cette branche contient le passage à gRPC > **plus trois chantiers** décidés en cours de route (garde-fou de mise à jour, > tri des tableaux, édition vim). Si tu préfères une PR par chantier, les > commits sont découpés proprement et se rejouent séparément — dis-le et je > scinde. Remplace le cadrage maison `[u32 BE][JSON]` par gRPC (tonic), après évaluation chiffrée des candidats dans `spike/` (voir `spike/RAPPORT.md`). ## 1. Passage à gRPC Le défaut le plus visible n'était pas le format des messages mais **l'absence de multiplexage** : pendant un transfert de fichier, une frappe du shell mettait 232 ms au p90 (jusqu'à 347 ms), mesuré sur le mesh. Le contrôle de flux *par stream* de HTTP/2 ramène ça à 44 ms — tout en transférant plus vite (40 contre 31 Mio/s). Ce que le transport prend en charge désormais, et qui disparaît du code : - corrélation requête/réponse (plus d'`id`, plus de table `pending`, plus de thread lecteur démultiplexeur) ; - fin de flux (`is_terminal()` et ses vingt bras à tenir à jour) ; - annulation (lâcher un flux suffit : l'op `Cancel`, le registre d'`AbortHandle` et la table de sessions shell n'ont plus de raison d'être — et une console qui disparaît ne laisse plus de PTY orphelin) ; - tolérance de version (`UNIMPLEMENTED` au lieu d'une session coupée, donc plus besoin du décodeur tolérant `decode_request`). **Défaut corrigé au passage** : `FilePut` mettait le fichier entier en base64 dans une trame unique plafonnée à `MAX_FRAME`. Au-delà de ~48 Mio, l'agent refusait la trame et **coupait la connexion sans message d'erreur**. Le client-streaming supprime la limite — vérifié sur le mesh à 64 et 200 Mio, empreintes SHA-256 comparées. **Choix de conception** : les types applicatifs (serde) sont conservés à côté des types générés, avec une couche de conversion explicite (`protocol/src/conv.rs`). C'est ce qui permet de migrer le transport **sans toucher au frontend** — la forme de l'événement `agent-msg` est inchangée — ni aux analyseurs de comptes, de pare-feu et de runbooks, ni à leurs tests. Le compte de lignes monte (≈670 lignes de conversions contre 240 de plomberie supprimées) ; ce qui baisse, c'est le risque : le code parti était celui des courses critiques. `console/src/identity.rs` garde **exprès** un client de l'ancien dialecte : un agent pré-gRPC ne répond pas du tout, et une erreur de transport nue n'apprendrait rien à l'utilisateur. La sonde le reconnaît et rend le chemin de son binaire pour le redéployer. ## 2. Garde-fou de mise à jour de l'agent La console proposait la mise à jour quel que soit le binaire candidat. Deux conséquences, dont une grave. **La grave** : la release roulante `agent-latest` de la forge porte encore le binaire d'avant gRPC (commitish `8c90418`, 4 172 464 octets), puisque cette branche n'est pas fusionnée. Cliquer « Dernier paquet de la forge » sur un hôte migré téléchargeait ce binaire, le poussait **avec succès** — l'agent en place étant gRPC, il l'acceptait — puis l'agent se remplaçait, redémarrait, et devenait **injoignable** jusqu'à un redéploiement par SSH. **La gênante** : le bouton était proposé même quand l'agent tournait déjà sur le binaire candidat. L'agent grave donc une ligne d'identité dans son propre binaire (`NBOPS-AGENT-META/1 protocol=<n> commit=<sha>`), que la console retrouve par recherche d'octets. Ce choix plutôt qu'un sidecar publié par la CI parce que la console a **toujours** les octets sous la main : ça couvre les trois sources — forge, agent embarqué, fichier choisi à la main — avec un seul mécanisme, là où un sidecar laisse la troisième découverte. Et un binaire d'avant gRPC n'a pas le marqueur, ce qui l'identifie exactement comme il faut. La décision est une fonction pure, `verdict_maj`, couverte par 9 tests. ## 3. Tableaux triables, et retrait de la bascule « live » Les 8 tableaux de l'application se trient en cliquant sur un en-tête : processus / interfaces / disques du tableau de bord, unités systemd, gestionnaire de fichiers, règles nftables et ufw, groupes locaux. Logique partagée (`compareCells` / `sortRows` / `nextSort` + un composant `SortBtn`) plutôt que recopiée huit fois. Trois choix qui méritent d'être dits : - le comparateur traite nombres **et** texte, avec `localeCompare` numérique : « ens10 » se range après « ens9 » ; - le tri est **stable**, ce qui compte plus qu'il n'y paraît — le tableau des processus est réécrit à chaque échantillon poussé, un tri instable ferait sauter les lignes une fois par seconde ; - les valeurs absentes vont en dernier **dans les deux sens**. `SortBtn` ne fournit que le bouton, pas le `<th>` : chaque tableau a sa propre mise en forme d'en-tête dans son style scopé, et un `<th>` émis par un composant tiers en sortirait. `aria-sort` reste donc sur la cellule. La bascule « live (push ~1 s) » disparaît avec le bouton « Rafraîchir » : l'abonnement est permanent. Elle datait d'un temps où le push était optionnel. ## 4. Édition d'un fichier via vim Cliquer un fichier ouvre `vim` dessus dans l'onglet Shell. `ShellIn.Open` porte désormais `program` et `args` **séparés**, exécutés sans shell. Ce découpage est un choix de sûreté : une commande unique à découper obligerait à échapper le chemin, et un nom de fichier avec une espace, une apostrophe ou un point-virgule deviendrait une injection. **Fixé par un test** : un argument contenant `; touch <témoin> #` doit ressortir entier et ne rien exécuter — le test échoue si le fichier témoin apparaît. ## Vérifications - **140 tests** : 64 (protocol + agent), 49 (console), 27 (frontend). `make ci` passe : fmt, clippy `-D warnings`, tests, frontend, cohérence du dist. - **Cross-compile Windows** (`make win`) : OK. - **Bout en bout sur le mesh**, contre `ep1` et `vps.kxh-studio.fr` via `agent probe` : appels unaires, flux, annulation par abandon, PTY bidirectionnel, code de sortie propagé, transferts 8 / 64 / 200 Mio avec empreintes comparées, et `--edit` pour vim. - **Avec la vraie console Windows** : connexion, tableau de bord alimenté en push, shell bidirectionnel, déconnexion qui referme bien le TCP. ### Ce qui n'est pas couvert par des tests, sciemment L'implémentation du service gRPC et la pompe de flux de la console sont du câblage qui demande un agent vivant ou un `AppHandle` Tauri : couvertes par `agent probe` de bout en bout. Les composants Svelte n'ont pas de harnais de test dans ce dépôt — seule la logique extraite dans `util.js` est testée. Le **rendu visuel** du tri et de l'édition vim n'a pas pu être contrôlé à l'écran. ## À savoir avant de fusionner 1. **`protoc >= 3.21.12` devient un prérequis de build** (ajouté à `scripts/ci-rust.sh` avec contrôle de version ; Debian 13 fournit exactement ce plancher). 2. **Chaque agent déployé doit être redéployé une fois par SSH** : la rupture de transport le rend injoignable autrement. État du parc au 2026-09-10 — à jour : `ep1`, `vps.kxh-studio.fr` · à redéployer : `ep2`, `forge`, `monitor`, `pbs1`, `pve1` · `mtmg` était injoignable. 3. La fusion referme d'elle-même le piège de `agent-latest` : la CI republiera un agent gRPC. 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01GzHyvUbKutGrRcWjyfwDkT
Trois candidats implémentant les mêmes opérations difficiles (logs streamés,
PTY bidirectionnel, transfert de fichier), mesurés sur ep1 à travers le mesh.

Le comptage d'octets se fait sous le protocole, dans une enveloppe
AsyncRead/AsyncWrite : le cadrage HTTP/2 et le multiplexage de remoc sont
comptés, pas seulement la charge utile.

Constats principaux (détail dans spike/RAPPORT.md) :

* La latence n'est pas un argument : sur le mesh les trois rendent la frappe
  à 21 ms, le RTT du tunnel écrase les 60-120 µs de surcoût processeur.
* Le vrai défaut actuel est l'absence de multiplexage : pendant un transfert,
  une frappe met 232 ms au p90 (jusqu'à 347 ms). gRPC descend à 44 ms grâce au
  contrôle de flux par stream, tout en transférant plus vite.
* Le plafond de 48 Mio de FilePut est un bug réel, pas théorique : un fichier
  de 56 Mio produit une trame de 75 Mio, refusée, et la connexion tombe en
  BrokenPipe sans message d'erreur.
* remoc gagne sur le fil (17 octets par frappe contre 34) et évite protoc,
  mais paie le débit de petits messages : 76 ms pour 20 000 lignes contre 8 ms.

Recommandation : gRPC (tonic), pour l'interactivité sous charge, le débit de
streaming, et la suppression d'environ 240 LOC de plomberie de session.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Qv1KxgghZsCDRRaf781ns2
passer le protocole agent <-> console à gRPC
Some checks failed
CI / Frontend (tests, build, cohérence de dist) (pull_request) Has been cancelled
CI / Agent Linux (pull_request) Has been cancelled
CI / Console Linux (pull_request) Has been cancelled
CI / Publication sur la forge (pull_request) Has been cancelled
CI / Console Windows (cross-compilation) (pull_request) Has been cancelled
CI / Rust (format, lint, tests) (pull_request) Has been cancelled
7421f5c630
Le contrat de fil vit désormais dans protocol/proto/agent.proto, généré au
build. Une opération = une méthode, et le mode de streaming porte la
sémantique qui était auparavant conventionnelle : server-streaming pour les
flux, client-streaming pour les envois volumineux, bidirectionnel pour le PTY.

Ce que le transport prend en charge, et qui disparaît du code :

* la corrélation requête/réponse — plus d'`id` croissant, plus de table
  `pending` côté console, plus de thread lecteur démultiplexeur ;
* la fin de flux — `is_terminal()` et ses vingt bras à tenir à jour s'en vont
  avec les trames terminales ;
* l'annulation — lâcher un flux suffit. L'opération `Cancel`, le registre
  d'`AbortHandle` de l'agent et sa table de sessions shell indexée par `id`
  n'ont plus de raison d'être, et une console qui disparaît ne laisse plus de
  PTY orphelin ;
* la tolérance aux versions — une méthode inconnue répond UNIMPLEMENTED sur un
  flux normal, là où l'agent fermait la session faute de savoir désérialiser la
  trame. `decode_request` et sa struct fantôme disparaissent.

Corrige au passage un vrai défaut : `FilePut` mettait le fichier entier en
base64 dans une trame unique, plafonnée par MAX_FRAME. Au-delà de ~48 Mio
l'agent refusait la trame et coupait la connexion, sans message d'erreur.
Le client-streaming supprime la limite. Vérifié sur le mesh à 64 et 200 Mio,
empreintes comparées.

Choix de conception : les types applicatifs (serde) sont conservés à côté des
types générés, avec une couche de conversion explicite dans protocol/src/conv.rs.
C'est ce qui permet de migrer le transport sans toucher au frontend — la forme
de l'événement `agent-msg` est inchangée — ni aux analyseurs de comptes, de
pare-feu et de runbooks, ni à leurs tests. Le base64 ne subsiste qu'à la
frontière IPC de Tauri, qui sérialise en JSON.

console/src/identity.rs garde exprès un client de l'ancien dialecte : un agent
pré-gRPC ne répond pas du tout, et une erreur de transport nue n'apprendrait
rien à l'utilisateur. La sonde le reconnaît et rend le chemin de son binaire
pour le redéployer. Couvert par des tests montant un faux agent d'avant en
local, sans réseau.

protoc >= 3.21.12 devient un prérequis de build : ajouté à scripts/ci-rust.sh
avec contrôle de version, documenté dans le README et le Makefile.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Qv1KxgghZsCDRRaf781ns2
console : arrêter la sonde de vivacité à la déconnexion
All checks were successful
CI / Frontend (tests, build, cohérence de dist) (pull_request) Successful in 17s
CI / Console Linux (pull_request) Successful in 9m54s
CI / Rust (format, lint, tests) (pull_request) Successful in 12m36s
CI / Agent Linux (pull_request) Successful in 2m19s
CI / Console Windows (cross-compilation) (pull_request) Successful in 7m39s
CI / Publication sur la forge (pull_request) Successful in 4s
de7a798544
La tâche qui sonde l'agent pour émettre `agent-closed` n'était pas
interrompue par `disconnect` : elle continuait d'interroger un hôte dont
l'utilisateur ne voulait plus, en gardant sa connexion TCP ouverte, et une
nouvelle s'ajoutait à chaque reconnexion. L'ancien transport, lui, fermait
franchement la socket.

Son handle est donc conservé dans `Conn` et révoqué à la déconnexion, ce qui
laisse tomber le dernier clone du `Channel` — et ferme réellement la connexion.

Ajoute au passage des tests sur la traduction des statuts gRPC en texte lu par
l'utilisateur : `UNIMPLEMENTED` doit produire une consigne de redéploiement
nommant l'opération, pas un code d'erreur, et un statut sans message doit se
replier sur son code plutôt que d'afficher une erreur sans cause.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Qv1KxgghZsCDRRaf781ns2
dxsk self-assigned this 2026-09-10 14:59:08 +02:00
dxsk changed title from Passer le protocole agent ↔ console à gRPC to WIP: Passer le protocole agent ↔ console à gRPC 2026-09-10 14:59:17 +02:00
La console proposait de mettre à jour un agent quel que soit le binaire
candidat. Deux conséquences concrètes, dont une grave.

La grave : la release roulante `agent-latest` de la forge porte encore le
binaire d'avant gRPC, puisque la migration n'est pas sur `main`. Cliquer
« Dernier paquet de la forge » sur un hôte migré téléchargeait ce binaire, le
poussait avec succès — l'agent en place étant gRPC, il l'acceptait — puis
l'agent se remplaçait, redémarrait, et devenait injoignable depuis la console.
Il fallait un redéploiement par SSH pour le récupérer. Vérifié sur l'artefact
réellement publié : 4 172 464 octets, commitish 8c90418, sans marqueur.

La gênante : le bouton était proposé même quand l'agent tournait déjà sur le
binaire candidat.

L'agent grave donc une ligne d'identité dans son propre binaire (contrat +
commit), que la console retrouve par recherche d'octets. Ce choix plutôt qu'un
sidecar publié par la CI parce que la console a toujours les octets sous la
main : ça couvre les trois sources — forge, agent embarqué et fichier choisi à
la main — avec un seul mécanisme, là où un sidecar laisse la troisième
découverte. Et un binaire d'avant gRPC n'a pas le marqueur, ce qui l'identifie
exactement comme il faut.

La décision est une fonction pure, `verdict_maj`, couverte par 9 tests : refus
d'un binaire sans marqueur, refus d'un downgrade de protocole, refus du même
build, renvoi vers SSH pour un agent pré-gRPC, et les cas qui doivent passer —
build plus récent, montée de contrat, sonde en échec, agent construit hors
dépôt.

Vérifié que le marqueur survit à `strip` + LTO, et qu'il est bien absent du
binaire publié sur la forge.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GzHyvUbKutGrRcWjyfwDkT
Chaque tableau de l'application se trie maintenant en cliquant sur l'en-tête
d'une colonne : processus, interfaces et disques du tableau de bord, unités
systemd, gestionnaire de fichiers, règles nftables et ufw, groupes locaux.

La logique est partagée plutôt que recopiée huit fois : `compareCells`,
`sortRows` et `nextSort` dans util.js, avec un composant `SortBtn` pour le
libellé cliquable. Trois choix qui méritent d'être dits :

* le comparateur traite nombres et texte, parce qu'une même ligne mêle pid,
  cpu et nom — comparer « 10 » et « 9 » comme des chaînes est l'erreur
  classique. Le texte passe en `localeCompare` numérique, donc « ens10 » se
  range après « ens9 » ;
* le tri est stable, ce qui compte plus qu'il n'y paraît : le tableau des
  processus est réécrit à chaque échantillon poussé, et un tri instable ferait
  sauter les lignes de valeur égale une fois par seconde ;
* les valeurs absentes vont en dernier dans les deux sens, plutôt que de
  remonter en tête au premier clic inverse.

`SortBtn` ne fournit que le bouton, pas le `<th>` : chaque tableau a sa propre
mise en forme d'en-tête dans son style scopé, et un `<th>` émis par un
composant tiers sortirait de cette portée. `aria-sort` reste donc sur la
cellule, portée par le helper `ariaSort`.

Le tri du tableau de bord remplace le sélecteur CPU/Mémoire des processus, qui
faisait le même travail sur deux colonnes seulement. Le gestionnaire de
fichiers garde les dossiers groupés devant quel que soit le critère.

La bascule « live (push ~1 s) » disparaît avec son bouton « Rafraîchir » :
l'abonnement aux métriques est désormais permanent. Elle datait d'un temps où
le push était le mode optionnel.

La liste des utilisateurs et celle des clés SSH ne sont pas des tableaux mais
des listes de sélection : elles n'ont pas d'en-têtes à cliquer et restent
inchangées.

11 tests de plus sur le tri (25 au total côté frontend).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GzHyvUbKutGrRcWjyfwDkT
gestionnaire de fichiers : éditer un fichier via vim
Some checks failed
CI / Rust (format, lint, tests) (pull_request) Successful in 10m2s
CI / Frontend (tests, build, cohérence de dist) (pull_request) Successful in 15s
CI / Agent Linux (pull_request) Successful in 1m46s
CI / Publication sur la forge (pull_request) Has been cancelled
CI / Console Linux (pull_request) Has been cancelled
CI / Console Windows (cross-compilation) (pull_request) Has been cancelled
e0d97f58f8
Cliquer sur un fichier ouvre `vim` dessus dans l'onglet Shell. Le clic était
jusqu'ici désactivé pour les fichiers — seuls les dossiers réagissaient.

`ShellIn.Open` porte maintenant `program` et `args`. Vide, c'est le shell de
connexion, le comportement d'origine ; renseigné, l'agent exécute le programme
**directement**, sans shell.

Ce découpage est un choix de sûreté, pas de commodité : une commande unique à
découper obligerait à échapper le chemin, et un nom de fichier avec une espace,
une apostrophe ou un point-virgule deviendrait une injection. Vérifié sur ep1
avec le chemin `/tmp/essai avec espace; touch /tmp/PWNED.txt #.txt` : vim le
reçoit comme un seul argument et `/tmp/PWNED.txt` n'est pas créé.

`agent probe --edit <chemin>` exerce ce chemin de bout en bout : ouverture du
PTY sur vim, écran rendu, sortie. C'est aussi le moyen de vérifier qu'un hôte
a bien vim installé.

Le programme et les arguments sont mémorisés sur l'onglet et non seulement
passés à l'ouverture : une reconnexion relance la même chose plutôt que de
retomber sur un shell nu.

Corrige au passage un défaut du build.rs de l'agent : surveiller `.git/HEAD`
ne suffit pas, son contenu ne change pas quand on committe sur la même branche
— c'est le fichier de la référence qui bouge. L'identifiant de build se figeait
donc au premier build de la branche, ce qui était cosmétique jusqu'ici mais
faussait désormais la comparaison de commits du garde-fou de mise à jour.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GzHyvUbKutGrRcWjyfwDkT
combler les trous de couverture, et retirer une commande devenue morte
All checks were successful
CI / Rust (format, lint, tests) (pull_request) Successful in 2m3s
CI / Agent Linux (pull_request) Successful in 1m47s
CI / Console Windows (cross-compilation) (pull_request) Successful in 7m46s
CI / Frontend (tests, build, cohérence de dist) (pull_request) Successful in 17s
CI / Console Linux (pull_request) Successful in 4m52s
CI / Publication sur la forge (pull_request) Successful in 4s
07b4bd6b6d
Revue de couverture des trois derniers chantiers. Trois manques réels :

* **La garantie « pas de shell » n'était vérifiée qu'à la main**, sur ep1.
  Elle est maintenant fixée par trois tests de PTY : un argument contenant
  `; touch <témoin> #` doit ressortir entier ET ne rien exécuter — le test
  échoue si le fichier témoin apparaît. Plus l'ordre des arguments, et le
  message d'erreur d'un programme absent, qui est ce que la console affichera
  si `vim` manque sur l'hôte.
* `ariaSort` était exporté sans test alors qu'il porte l'annonce du tri aux
  lecteurs d'écran : deux cas ajoutés.
* La commande Tauri `sys_info` et son enveloppe `api.sysInfo` étaient devenues
  **mortes** en retirant le bouton « Rafraîchir » du tableau de bord. Aucun
  appelant depuis le frontend, vérifié en confrontant les 42 commandes
  déclarées aux appels réels. L'appel gRPC `GetSysInfo`, lui, reste : c'est
  `agent probe` qui l'exerce.

Ce qui reste hors test, sciemment : l'implémentation du service gRPC et la
pompe de flux de la console sont du câblage qui demande un agent vivant ou un
`AppHandle` Tauri — ils sont couverts par `agent probe` de bout en bout. Les
composants Svelte n'ont pas de harnais de test dans ce dépôt ; seule la logique
extraite dans util.js est testée.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GzHyvUbKutGrRcWjyfwDkT
dxsk changed title from WIP: Passer le protocole agent ↔ console à gRPC to Passer le protocole agent ↔ console à gRPC 2026-09-10 15:52:23 +02:00
dxsk merged commit 6296f44e27 into main 2026-09-10 15:52:39 +02:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
dxsk/netops!1
No description provided.