Symptôme: stopper un agent (ex Main sur UnityPlugin) laissait des travaux
poursuivre, la cascade n'atteignait pas les agents lancés et la pastille
restait orange pendant que l'agent continuait à en appeler d'autres.
- barrière d'admission par génération d'exécution (ExecutionControl): un stop
ferme l'admission de tout le sous-arbre propriété/attente AVANT toute
annulation asynchrone — plus aucune nouvelle action inter-agents après stop
- arbre de propriété durable en-process (launched_by) + dépendances d'attente
actives: la cascade couvre transitivement agents et travaux lancés
- commandes d'un agent arrêté rejetées (AppError::AgentStopped); stop
lui-même admis pour rester idempotent; réactivation sur relance humaine
(génération +1) et enregistrement du propriétaire au spawn
- admission exposée aux adaptateurs hors commandes cœur (tickets, templates,
plugins) via ensure_agent_execution_active; MCP server/tools, web-server et
commandes Tauri alignés
- cohérence live-state: statut Idle avec intent « Arrêté » ou
« Arrêt incomplet — Certains travaux sont encore actifs » selon l'issue de
la cascade; workstate et surfaces UI (AgentsPanel, LayoutGrid,
ProjectWorkStatePanel) reflètent l'état réel, plus de pastille orange fantôme
- tests: orchestrator_service (cascade/générations/idempotence),
workstate_actions, background_task_cancel, error_codes, agents, layout,
workstate
QA verte sur fix/320-agent-stop-cascade. Aucun push.
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>
- détachement: le panneau Paramètres du projet devient détachable (mapping historique panel=context → projectSettings dans parseViewWindowParams, DETACHABLE/ViewPanelBody alignés, ProjectsView ne court-circuitant plus le refus); Retry d'échec de détachement préservé
- couleurs projet: projectTheme publie idea:project-theme-changed localement + BroadcastChannel inter-webviews (fenêtres OS détachées), garde de révision par projet dans ProjectsView/ViewWindow contre les lectures settings en course — plus de flash/retour au bleu par défaut
- conversation custom CLI: transcript_restore_expected ne considère plus l'absence de scrollback volatile comme une restauration échouée quand la session rouvre en SessionPlan::None (continuation vide valide); CustomAgentChatView n'affiche plus le faux « conversation liée n'a pas pu être restaurée »
- images: conservation des images de conversation après changement de projet puis retour
- menus Panneaux: retrait des entrées Projects et Project Context (panelOrder WebWorkspace, création/switch via tab-bar +, contexte projet fusionné dans Paramètres du projet)
- QA verte: tests frontend ciblés window/ViewWindow/ProjectSettingsPanel/ProjectsView.detach/projects/CustomAgentChatView/WebDesktopWorkspace + cargo test -p application lifecycle transcript_restore_expected; fichiers .ideai/* (tickets 308-315, index/counter, agents/test, chat-drafts, system-permissions, project-settings.json, attachments/) et scripts/ hors périmètre préservés en worktree; aucun push
#305: nouvel agrégat durable ScheduledProjectTask dans domain (scheduled_task.rs, ids, ports ScheduledProjectTaskStore), source de vérité <app_data_dir>/scheduled-project-tasks/<projectId>.json, schedules bornés V1 interval/daily/weekly avec fuseau, cycle À approuver/Active/Suspendue avec approbation obligatoire des tâches demandées par agent; use cases application/scheduled_task (list/create/update/delete/run_now/reconcile/fire) réutilisant BackgroundTask pour les runs avec distinction planifié/manuel; store infrastructure dédié + scheduler reconcile au boot sans rattrapage en rafale, cwd confiné au projet; 7 tools MCP idea_scheduled_task_* (list/read lecture seule, create/update/delete/run_now/set_enabled write-actions soumises aux permissions natives); commandes Tauri + routes HTTP aux contrats DTO identiques (camelCase nextRunAtMs/lastRunAtMs/lastTaskId/createdBy/updatedBy); frontend: gateways Tauri/HTTP/mock + types ports/domain, surface projet 'Tâches planifiées' (liste utilisateur+agent unifiée, création/édition avec récapitulatif avant activation, approbation/refus, exécuter maintenant, suspendre/reprendre, suppression), catalogage surface web (webSurfaceCatalog/viewPlacement/ViewPanelBody/WebWorkspace); docs/scheduled-project-tasks.md et sdk docs/services.md (047c38b: pas un service plugin V1, pas d'émulation via cron système).
#314: correction de 'Conversation liée — transcript indisponible' après reboot: restauration du transcript lié côté application (orchestrator service, lifecycle, session_limit, background sink, terminal registry) et côté frontend (adapters agent/http frames/stream/requestResponse, workStateNormalization, CustomAgentChatView avec état et action utile), tests dto_chat/agent_lifecycle/structured_registry_d1/background_completion_sink étendus.
QA verte rapportée par QA sur feature/305-scheduled-project-tasks-mcp, sans bloquant, pour #305 et #314.
Hors périmètre worktree: tickets non liés, attachments/, scripts/; aucun push.
- #310: horodatage de tous les messages et événements de conversation visibles — composant partagé EntryTimestamp, timestamps propagés dans le transcript chat, les annonces inter-agent et le viewer de conversation, normalisation côté domain/adapters (conversation_log, paginate).
- #311: stop d'agent robuste pour PTY non monté, sessions headless et CLI custom — lifecycle/orchestrator durcis, ponts chat app-tauri/web-server alignés, arrêt fiable sans session orpheline.
- #312: préférence globale d'interface terminal par défaut — nouveau store settings (domain/application/infrastructure + tests), DTO et commandes backend, adapter frontend userSettings, panneau TerminalSettings dans les paramètres globaux.
- #313: Paramètres du projet — contexte de projet éditable et couleur de thème par projet (ProjectSettingsPanel + projectTheme), teinte des onglets projet, persistance via DTO projet.
QA verte (GO QA sur feature/batch-310-311-312-313-chat-stop-prefs-theme) — vérifications Git: git diff --cached --check OK; staging borné à crates/ et frontend/ (74 fichiers, +2105/-531), commit unique de lot conforme à la convention des lots (précédents batch-151/158/159, batch-210/211/212) car les fichiers partagés (dto.rs, commands.rs, CustomAgentChatView) entrelacent les 4 tickets.
fichiers .ideai/* (agents/test.md, chat-drafts.json, system-permissions.json, tickets/counter.json, tickets/index.json, tickets/308-313/), attachments/ et scripts/ hors périmètre et préservés en worktree ; aucun push.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Backend : StructuredHumanTurnGuard pour partager la comptabilité busy/FIFO entre chat direct humain (agent_send, web chat.send) et asks inter-agents structurés, avec liveness mark_alive et retrait idempotent du tour. Web-server : tap d'événements sur chat.send pour le scrollback temps réel. Frontend : scoping des clés de progression par tour pour éviter la déduplication/ghosting des progress et outils entre appels.
L'erreur « La réponse du modèle n'a pas pu être finalisée. » indique désormais
l'adapter en cause (Session Codex / Claude / OpenCode / HTTP) pour lever
l'ambiguïté constatée sur GameTime entre session Codex et Claude.
- Attachments: projection canonique ChatPromptAttachmentDto (référence [file n]/[image n] par compteur de type, ordre d'import) insérée dans le prompt modèle et transportée par ReplyChunk::UserPrompt (attachmentRefs) ; rendu compact côté CustomAgentChatView.
- Resize: la zone chat (LeafView/LayoutGrid) est redimensionnable, taille actuelle conservée par défaut, préférence locale persistée.
- Tests: commands (projection des refs), dto_chat, chat_bridge, CustomAgentChatView, LayoutGrid.chat.
- Codex: les items agent_message sont désormais tapés en live comme progress (Message/Delta) dès item.completed, au lieu d'être bufferisés dans pending_final jusqu'à l'événement tool/MCP suivant.
- Corrélation stable progressId (codex:item:<id>) ajoutée sur ReplyProgress, propagée jusqu'au DTO (ReplyProgressDto.progressId) et au frontend ; le ProgressSettler et la vue procèdent par upsert running -> done au lieu d'empiler des lignes dupliquées.
- Tests: chat_bridge (settler par progressId), dto_chat, session codex, CustomAgentChatView (upsert par progressId).
Projette l'état d'interaction agent→projet sur la LED via des signaux explicites de la CLI custom:
- projectCliInteractionActivity: modèle d'activité d'interaction (InteractionStarted/Finished/Stopped, interactionId/seq, version).
- useProjectActivity + ProjectTabs: projection live « interaction en cours » → LED, retour immédiat à l'état attendu au stop ou à la fin réelle de l'échange (pas d'état collant).
- CustomAgentChatView: émet les signaux d'interaction CLI custom (début d'envoi, fin de tour, stop) consommés par l'activité projet — sans dériver la LED du texte streamé ou d'heuristiques.
Tout côté frontend: aucun signal runtime manquant (les signaux proviennent de la CLI custom).
Tests QA verts: projectActivity.test.ts, ProjectTabs.test.tsx (+ useProjectActivity.test.tsx, CustomAgentChatView.test.tsx).
Les progress « started » d'une même entité s'empilaient en plusieurs turns et
n'étaient dédupliqués qu'a posteriori par scan linéaire du tableau de turns,
d'où des doublons visibles et un affichage retardé (re-scan par chunk).
appendProgress opérait directement sur turns[] (chaque « started » y était poussé
puis retrouvé/remplacé par recherche séquentielle). Désormais:
- ChatViewState (turns + entityProgressMap): la Map indexée par « entité\0bucket »
(started/completed) est l'unique source de vérité pour les progress en cours;
- les progress « started » ne deviennent des turns qu'au flush
(completeChatViewProgress sur final/error), supprimant la duplication et
rendant l'affichage immédiat;
- « completed » merge depuis l'entrée running de la Map puis la retire, au lieu
de scanner le tableau;
- turnsIndicateBusy s'appuie sur la taille de la Map (état vivant) en plus du
scan des turns.
Tests: déduplication des progress par entité (started répétés → une seule entrée,
flush au final), fusion « completed » depuis la Map, état busy reflété par la
Map, et rendu non dupliqué sur l'enchaînement started/completed/final.
Corrige la perte de session à la navigation: le démontage du CustomAgentChatView
appelait close_agent_session (destructeur) au lieu de simplement détacher le
transport. Désormais:
- nouvelle commande Tauri detach_agent_chat (+ ChatBridge::detach) qui libère le
canal sans tuer la session ni le scrollback retenu; distinct de
close_agent_session qui reste le close destructeur explicite;
- le frontend appelle detachAgentChat à l'unmount puis restore sa vue depuis un
cache de session (turns + chunkCount) à la réattache;
- message « Reprise effectuée: N événements rattrapés… » quand la réattache
rejoue plus de chunks que le cache local n'en avait conservé.
Enrichit le rendu tools/MCP/progress:
- ProgressSettler (chat bridge) émet un progress completed synthétique quand un
spinner reste ouvert (nouvelle entité progress, chunk text/final/error): fini
les spinners fantômes;
- les adapters claude/codex/opencode/openai_compat extraient un aperçu du
payload (arguments/input/command/message/params) attaché au progress;
- bounded_reply_progress_preview (domain) garde les 4 premières lignes non
vides, normalisation CR/LF;
- previewText (frontend) multiligne whitespace-pre-wrap, source/nativeEvent
affichés sous le titre; suppression du flag settled et du Spinner inline
devenus redondants (l'état est porté par le stage + le settler).
Tests: detach_agent_chat gateway (Tauri + mock), ProgressSettler, bornage
reply_progress, item_preview/tool_preview par adapter, réattache avec cache et
notice de rattrapage.
Le Stop du CustomAgentChatView n'annulait que le tour courant sans libérer la
session ni toucher aux tâches enfants ou appels MCP en cours. Il appelle
désormais stop_live_agent sur l'agent vivant, qui:
- ajoute le port StopAgentExecutionCascade (best-effort, idempotent), implémenté
par OrchestratorService pour annuler les idea_run_in_background rattachés au
rendez-vous actif (via BackgroundTaskRunner.cancel);
- cascade l'arrêt aux wait-dépendances (stop_turn_watch + preempt) pour
interrompre les appels MCP et les attentes inter-agents;
- libère et supprime la session structurée.
UI: nouvel état "Arrêt en cours..." (bouton disabled + loading) pendant l'arrêt,
libération du sessionId, label expliquant la cascade demandée. La Tauri command
cancel_agent_chat est alignée sur stop_live_agent + stop_turn_watch agent et
dépendances.
Tests: SpyBackgroundRunner (cascade n'annule que les tâches rattachées),
workstate_actions cascade best-effort, CustomAgentChatView stop+cascade feedback
et fallback NOT_FOUND.
Le collage d'une image (ex. capture d'écran) échouait en environnement desktop : le presse-papier image n'est souvent pas exposé comme un File synchrone dans clipboardData.files, mais uniquement via l'Async Clipboard API. On ajoute donc un repli sur navigator.clipboard.read() (MIME image/*) quand l'événement de collage ne fournit aucun fichier. Le preventDefault() n'est émis que lorsqu'on a effectivement lu des fichiers issus de l'événement, afin de ne pas bloquer le collage texte quand le repli async ne remonte rien.
- refactor clipboardFiles(event) -> dataTransferFiles(DataTransfer) réutilisable
- dedupeKey robuste pour les images sans nom (mime + taille + contenu base64)
- ReplyChunk::UserPrompt porte désormais les labels d'attachments (DTO + accounting reply_chunk_bytes, skip_serializing_if Vec::is_empty)
- tests ciblés frontend (+219) et backend (chat_bridge/dto/attachments) verts
QA : tests ciblés verts. Réserve : environnement headless, pas de validation manuelle desktop — validation AppImage à confirmer en suivi.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Retire la surface utilisateur de reprise par cellule :
- supprime ResumeConversationPopup et son test (resumeConversationPopup.test.tsx)
- débranche l'appel dans LayoutGrid et retire l'export terminals/index
- ajuste les tests dépendants (libellé « Terminé » dans LayoutGrid.chat.test, refitEpoch)
- commentaire affiné dans ResumeProjectPanel
La reprise implicite éventuelle sera rediscutée ultérieurement (objectif immédiat : retirer la surface).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
appendProgress déduplique par entité (tool/mcp/delegation) + bucket de stage sur l'ensemble du tour, évitant le doublon entre tap live et flux autoritatif. idea_ask_agent/idea_ask_agents rendus comme Délégation. completeRunningProgress marque les entités complétées (settled) pour stopper l'animation. 2 nouveaux tests: ordre pre-MCP avant la première carte MCP, et dédup -> exactement 2 cartes Délégation pour 2 délégations.