feat(backend,application,frontend,domain,web-server,app-tauri): bouton Redémarrer l'agent dans la barre supérieure des cellules — #317 (QA verte)

La cellule expose un bouton Redémarrer l'agent valable pour les trois
modes de présentation (headless, TUI native, CLI custom), sans jamais
prendre la présentation pour vérité runtime.

- Application: use case RestartCellAgentRuntime validant le binding
  exact cellule/runtime via les snapshots live (RestartRuntimeNotFound,
  ConflictAgentVisibleElsewhere, AgentNotBoundToCell) puis déléguant au
  scheduler self-restart existant (schedule_cell); CellAgentPresentation
  purement informationnelle.
- Backend/app-tauri/web-server: commande restart_cell_agent sur contrat
  DTO identique Tauri/HTTP, stop borné par timeout typé
  (RestartStopTimeout), relance préservant routage TUI natif, géométrie
  de cellule (node/rows/cols) et conversation; évenements domaine
  enrichis.
- Frontend: bouton dans la barre de cellule avec confirmation,
  overlay d'état Redémarrage…/échec (libellés par code d'erreur, Fermer/
  Réessayer), gardes d'identité de cellule et de restarts externes,
  gateway/mock/http adapters et ports alignés.
- Tests: dto_agents, workstate_actions, contrats web-server,
  LayoutGrid.cellControlsLayering, adapters agent/mock/http.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-09-11 15:00:43 +02:00
parent 46449bdf46
commit 7fb9d8bb86
26 changed files with 1404 additions and 58 deletions

View File

@ -741,3 +741,53 @@ fn stop_live_agent_response_serialises_camelcase_with_kind() {
assert_eq!(v["alreadyStopped"], false);
assert!(v.get("session_id").is_none());
}
#[test]
fn restart_cell_agent_request_deserialises_all_presentations() {
use app_tauri_lib::dto::{CellAgentPresentationDto, RestartCellAgentRuntimeRequestDto};
for (wire, expected) in [
("headless", CellAgentPresentationDto::Headless),
("tui", CellAgentPresentationDto::Tui),
("customCli", CellAgentPresentationDto::CustomCli),
("unknown", CellAgentPresentationDto::Unknown),
] {
let raw = json!({
"projectId": Uuid::from_u128(1).to_string(),
"nodeId": Uuid::from_u128(2).to_string(),
"agentId": Uuid::from_u128(3).to_string(),
"presentation": wire,
"layoutId": Uuid::from_u128(4).to_string()
});
let dto: RestartCellAgentRuntimeRequestDto = serde_json::from_value(raw).unwrap();
assert_eq!(dto.presentation, expected);
assert_eq!(dto.layout_id, Some(Uuid::from_u128(4).to_string()));
}
}
#[test]
fn restart_cell_agent_response_uses_restart_event_correlation_contract() {
use app_tauri_lib::dto::RestartCellAgentRuntimeResponseDto;
use application::{CellAgentPresentation, LiveSessionKind, RestartCellAgentRuntimeOutput};
let agent = AgentId::from_uuid(Uuid::from_u128(11));
let node = NodeId::from_uuid(Uuid::from_u128(12));
let layout = domain::LayoutId::from_uuid(Uuid::from_u128(13));
let dto = RestartCellAgentRuntimeResponseDto::from(RestartCellAgentRuntimeOutput {
restart_id: "restart-317".to_owned(),
agent_id: agent,
node_id: node,
kind: LiveSessionKind::Structured,
presentation: CellAgentPresentation::CustomCli,
layout_id: Some(layout),
});
let value = serde_json::to_value(dto).unwrap();
assert_eq!(value["restartId"], "restart-317");
assert_eq!(value["status"], "scheduled");
assert_eq!(value["agentId"], agent.to_string());
assert_eq!(value["nodeId"], node.to_string());
assert_eq!(value["kind"], "structured");
assert_eq!(value["presentation"], "customCli");
assert_eq!(value["layoutId"], layout.to_string());
}