Custom CLI composer stays active during busy turns: submitting while the
agent works enqueues the message instead of sending it. Local FIFO queue
scoped per cell (projectId+agentId+layoutId+nodeId), entries carry id,
text, attachments snapshot and createdAtMs; single in-flight
transmission, entry removed at send time, auto-drain only on final
chunk, queue preserved on error/Stop with 'Relancer l'agent' action on
stopped cells. 'En attente · N' panel anchored above the composer:
order, 2-line preview, per-entry edit/delete with transient undo, clear
all with confirmation; main button switches Send / 'Mettre en attente'
with live announcement; layout contract updated (CLI visible while
busy, textarea enabled, Stop available). Chat navigation: round up-arrow
under the agent bar jumps to previous Final, round down-arrow above the
composer appears when not at bottom to jump to latest message,
auto-scroll suspended while reading history, prefers-reduced-motion and
44px a11y targets respected.
Ports unchanged (AgentGateway send/cancel/reattach, restartCellAgentRuntime).
QA verte reconfirmée par Git: targeted suites 115/115
(CustomAgentChatView/LayoutGrid/LayoutGrid.chat), git diff --check;
QA: npm run typecheck OK, npm run build OK.
Réserves documentées: queue renderer-local (non persistée après restart
complet), validation visuelle cellules très étroites restante.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Lot en un seul commit: les deux features partagent les mêmes contrats
(domain/settings.rs, DTO, commandes Tauri/HTTP, web-server) et les mêmes
surfaces UI — la séparation par fichiers était impossible sans chirurgie
de hunks risquant des états intermédiaires non compilables (convention
lot des batches #310-#313 et #315).
#325 — icône configurable par projet, watermark CLI custom:
- domaine: ProjectIconSet (devicon, simple-icons, lucide, idea),
ProjectIconRef validé (nom ASCII 1..=64, -_. internes), champ icon
optionnel sur ProjectSettings; sérialisation camelCase et try_from
strict
- application: UpdateProjectSettings.execute accepte un patch
theme_color OU icon (absent = inchangé, null = défaut produit), tests
in-dependants avec store mémoire
- backend/app-tauri/web-server: ProjectIconRefDto, UpdateProjectSettingsRequestDto
avec icon optionnel (désérialisation additive), commandes
update_project_settings alignées Tauri/HTTP, tests DTO et HTTP
(défaut null, set, clear, nom invalide rejeté)
- frontend: catalogue projectIcons (recherche EN), ProjectIconPicker en
grille multi-lignes dans Paramètres projet, affichage de l'icône dans
ProjectTabs et watermark grand format à faible opacité en fond de CLI
custom; ports ProjectSettings.icon, Partial<ProjectSettings>,
adapters tauri/mock/http et tests alignés
#326 — localisation FR/EN et traduction des textes IdeA:
- domaine: IdeaLanguage (fr | en), champ language optionnel sur
IdeaUserSettings (absence = défaut produit, série additive validée)
- backend/web-server: UserSettingsDto.language, update_user_settings
accepte language, tests HTTP alignés; fixtures structured_launch_d3
mises à jour
- frontend: i18n/ (catalogue FR/EN, I18nProvider, scan anti-régression
des sources visibles), GeneralSettings avec sélecteur de langue dans
les paramètres, setupI18n dans vitest; migration de l'ensemble des
textes hardcodés vers le catalogue sur toutes les surfaces (agents,
layout, projets, tickets, sprints, web, plugins, permissions, git,
templates, skills, mémoire, model servers, embedder, first-run,
devices, scheduled tasks, workstate, dialogs), FR conservé par défaut;
recherche d'icônes #325 en anglais conformément au ticket
QA verte sur feature/batch-325-326-project-icons-localisation. Aucun push.
Symptôme: après changement de projet puis retour, une cellule en CLI
custom retombait en TUI native et un nouveau switch CLI custom repartait
à neuf (aucune conversation reprenable) car le mode préféré de la
cellule n'était pas persisté dans l'arbre de layout.
- domaine frontend: type PreferredView (tui | chat) et champ
preferredView optionnel sur LeafCell; opération de layout
setCellPreferredView persistant la surface préférée (tui = défaut,
champ omis pour garder les arbres existants compacts)
- LayoutGrid: le mode de présentation d'une cellule agent dérive de
preferredView persisté; le cache localStorage du mode custom n'est
plus qu'un cache de migration secondaire; remount par clé
projectId:layoutId:nodeId à chaque changement de projet pour éviter
tout état résiduel inter-projets; la conversation/engine session/
session/agentWasRunning de la cellule sont préservés par les
bascules chat <-> TUI
- useLayout: setCellPreferredView exposé au view model
- tests: layout_usecases (persistance chat puis retour TUI en
conservant session/conversation/engine/running), layout.test
(setCellPreferredView chat persiste, tui omet le champ),
LayoutGrid.chat et cellControlsLayering alignés
QA verte sur fix/batch-322-323-session-restore-prompt-history. Aucun push.
Les cellules custom CLI ne rendent plus le TargetAnnouncementsOverlay quand
l'agent est busy : le badge busy canonique et le lock du composer (comportement
du chat après envoi d'un message) suffisent, la vue terminal/chat reste visible.
Les cellules TUI natives conservent le voile plein panneau.
- 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.
Surface UI du LayoutGrid pour un agent de cellule stoppé:
- Affichage d'un état explicite quand runtimeState vaut « stopped » ou « failedStart », avec actions refresh / reopen from scratch (freshStart) et état restarting pendant la relance.
- theme.css: styles .stopped-agent-cell (boutons primary/secondary, états disabled).
Consomme le contrat runtime issu de #196 (AgentRuntimeState stopped/failedStart, freshStart) déjà présent dans develop; aucune modification runtime ici.
Tests QA verts: LayoutGrid.test.tsx, LayoutGrid.chat.test.tsx (rejoué aussi: agent_lifecycle launch_fresh_start_ignores_existing_conversation_id_and_mints_new_one).
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>
Le fallback custom→TUI se redéclenchait après le premier chargement dès que
refreshProfiles() renvoyait un instant un profil pinné sans structuredAdapter
(refetch en vol), coupant la CLI custom ~0.5s après son ouverture. Introduit
un binding "trusted" (agent+profil validés) qui reste valide tant qu'aucun
changement légitime de profil n'est observé via agentProfileChanged, et ne
retombe en TUI que sur perte réelle du CLI custom.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Cause racine restante après le fix de la course au premier chargement : le
garde-fou de LayoutGrid retombait sur `tui` dès que agents/profiles semblaient
indisponibles, y compris quand le cache était simplement stale (refresh en
cours), écrasant silencieusement la préférence custom. Le fallback n'agit
désormais qu'une fois le catalogue confirmé à jour.
QA verte : LayoutGrid.chat.test.tsx (7 tests), src/features/layout (16
fichiers, 130 tests), cas ciblé "stale catalog refresh".
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Implémente la vue chat structurée par cellule agent (toggle TUI/CLI custom,
préférence persistée `preferred_view`, reattach live, composer + pièces
jointes) avec le socle backend AgentSession/ChatBridge (UserPrompt,
cancel_current_turn, routage interrupt_agent, commande cancel_agent_chat).
Corrige le bug bloquant relevé par QA : le bouton Cancel de
CustomAgentChatView interrompait tout le tour via closeAgentChat au lieu
de n'annuler que le tour courant via cancelAgentChat, ce qui tuait la
session contrairement au contrat produit validé.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Le frontend consomme l'exécution structurée livrée en D4 :
- AgentChatView : jumeau chat de TerminalView. Accumule les textDelta du
tour courant, badges toolActivity, fige sur final (le contenu final
remplace les deltas, pas de double rendu). Saisie Enter/Shift+Enter.
Au montage : reattach (rejoue le scrollback) ou launch ; au démontage :
détache seulement (jamais de close). Vue pure pilotée par le port.
- LayoutGrid/LeafView : routage cellKind — AgentChatView si "chat",
TerminalView sinon (chemin PTY inchangé). Cache cellKindBySession pour
router correctement après ré-attache/navigation.
- Port AgentGateway : sendPrompt / reattachChat / closeAgentSession ;
cellKind sur TerminalHandle. Adapter Tauri (invoke + Channel<ReplyChunk>)
et mock (MockChatSession, _setChatAgents) étendus.
- Types TS mirrors : CellKind, ReplyChunk, ReattachChatDto + cellKind sur
TerminalSession.
Tests (QA) : 21 Vitest verts — routage chat/pty (non-régression terminal),
accumulation/non-doublon (garde anti-always-green delta!=final), ré-attache
sans re-spawn, envoi Enter vs Shift+Enter, badges toolActivity, mock stream.
npx vitest run : 345 passed, 0 failed. npm run build vert.
Reste D6 (messagerie inter-agents via send_blocking) et D7 (menu restreint
Claude/Codex + retrait custom) pour clore §17.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>