Cause: la logique de suivi du bas de fil était dupliquée et ad-hoc dans chaque surface (scrollRef, followsLatestRef, showLatestButton dans CustomAgentChatView), et dérivait dans certains cas — le fil ne suivait plus les nouveaux messages.
Fix: nouveau hook partagé shared/lib/useThreadScrollController (resté collé au bas quand l'utilisateur est déjà en bas, position préservée pendant la consultation de l'historique, notice latest sinon) câblé dans CustomAgentChatView, ConversationViewer et TicketAssistantPanel.
QA verte: npm run typecheck exit 0; tests ciblés useThreadScrollController, CustomAgentChatView, ConversationViewer/useConversationThread et tickets verts; npm test 1400/1400 verts (137 fichiers); git diff --check.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Cause: the monochrome-first treatment from #351 flattened the emoji
artwork through an alpha mask (transparent fill + zero-offset
text-shadow), dropping internal details (the ghost lost its tongue and
eyes), and the watermark box did not occupy the full space available
above the chat composer.
Fix: new .project-cell-illustration-area container (container-type:
size) wrapping the scroll zone so the absolute watermark spans the
whole region between the agent toolbar and the composer; glyph keeps
the OS full-colour emoji artwork as source and is neutralised with a
non-destructive CSS filter (grayscale(1) contrast(0.92)) so internal
tones and details stay visible in black and white; glyph sized to
min(100cqw - 8px, 100cqh - 12px); text-variation selector U+FE0E
stripping removed (full emoji preserved) and project-theme tint
plumbing (accessibleProjectAccent/onProjectThemeChanged) dropped as
superseded by grayscale; empty label and overlay z-layering untouched.
QA verte reconfirmée par Git: npm test -- CustomAgentChatView.test.tsx
projectIcons.test.tsx 96/96, npm run typecheck OK, npm run build OK,
npm test 1396/1396, git diff --check OK.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
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>
Cause: the empty-state watermark filled only 92% of a centered box and
kept residual palette colors from host emoji fonts, non-compliant with
the monochrome-first project icon rule (#351 user capture).
Fix: illustration spans the cell with 6px/4px insets and an unclipped
glyph at min(88cqw, 88cqh); emoji painted as monochrome silhouettes via
transparent fill + zero-offset text-shadow tint
(--project-illustration-tint) derived from accessibleProjectAccent when
a project color exists, neutral muted fallback otherwise; empty label
anchored bottom-center and hidden first on constrained containers
(@container 280px width / 240px height); overlay priorities, composer
and z-layering untouched.
QA verte reconfirmée par Git: npm test -- CustomAgentChatView.test.tsx
80/80, git diff --check; QA: ProjectSettingsPanel 12/12, typecheck,
build OK (warning Vite chunk >500 kB préexistant).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Tabs (shared/ui): cible de drop matérialisée par écartement before/after pendant le drag/reorder, reset via rAF sans reliquat, clavier et annonces préservés.
- projectIcons: icônes projet en noir et blanc par défaut, colorisées avec la couleur du projet, occupant la cellule et visibles derrière les messages rendus légèrement transparents.
- Permissions plugin headless: PluginMcpServerSpec transporte l'allowlist exacte authorized_tools regroupée par (pluginId, serverId) depuis les PluginToolRef; projection Codex enabled_tools + default_tools_approval_mode="approve" — une permission déjà accordée au niveau projet/template ne déclenche pas de seconde approbation, un tool non assigné reste hors surface appelable; réserves orchestrator/mcp server+tools alignées, dto backend + dto_agents app-tauri.
- Skills: ref stable plugin:<pluginId>:<skillId> exposée dans le contexte agent, idea_skill_read(ref=...) canonique via read_assigned_by_ref, erreur structurée ambiguousSkillName avec candidates; SkillsPanel dédoublonné (android-build-install); agents-dev/L12-skills.md à jour.
- Docs: ARCHITECTURE.md section 22.3 (projection des autorisations agent vers les runtimes plugin).
- QA verte #350 reconfirmée avant commit.
#346 — capacités plugin SCM: le manifeste permissions.workspaceExec
(contrat SDK 8ff0f47) est appliqué côté hôte — domain PluginWorkspaceExec
Rule/Effect + audit sink, port WorkspaceToolRunner, adapter
LocalWorkspaceToolRunner sandboxé (concurrence 4, timeout, bornes
stdout/stderr, résolution bare executable sans shell), service
application + DTO backend + commandes app-tauri, gateway frontend
execTool exposée au runtime plugin — fin des lectures ad hoc du store
interne .git par les plugins.
#347 — onglets projet réordonnables par glisser-déposer (Tabs DnD,
onReorder, persistance de l'ordre via useProjects).
#348 — stop d'agent CLI custom: le message Final vert réapparaît au tour
suivant (override terminal stop armé correctement, reset de
l'interaction, refresh de la délégation requester).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Lot en un seul commit: les quatre tickets partagent les mêmes fichiers
(événements domaine/DTO, ProjectPluginsPanel, useProjectPlugins) — une
séparation par hunks aurait risqué des états intermédiaires non
compilables (convention lot des batches #310-#313, #315 et #325-#326).
#328 — section dédiée plugins dans Paramètres du projet:
- frontend: ProjectPluginsPanel intégré à ProjectSettingsPanel
(Panneaux > Paramètres du projet) — activation/désactivation par
plugin avec état actif/inactif explicite par projet, distinct de
l'assignation agents/skills/tools
- domaine: événement ProjectPluginSettingsChanged publié par
SetProjectPluginEnabled, MutateAgentPluginSkill et
MutateAgentPluginTool après persistance de .ideai/project-plugins.json
(application + backend + DTO camelCase, test dto.rs)
#329 — les menus plugin qui échouent ne sont plus muets:
- usePluginMenus: dispatcher strict (runCommandStrict) pour les
commandes réellement enregistrées au lieu du dispatcher laxiste qui
journalisait et avalait les rejets — rendait les échecs d'ouverture
de fenêtres natifs invisibles pour l'hôte de menus
- le no-op SDK historique (commande déclarée sans handler) est préservé
- échec remonté à l'hôte via commandError/clearCommandError (journal
console + état exposé); test window_usecases adapté à un plugin
installé
- le correctif côté SDK/GitPlugin vit dans le projet GitPlugin (son
commit/merge local y est fait, hors périmètre de ce dépôt)
#330 — refresh automatique des pages:
- frontend/domain: typage des événements pluginEnabled,
pluginDisabled (restartRequired), pluginUninstalled
(restartRequired), pluginLoadFailed et projectPluginSettingsChanged
- useProjectPlugins et PluginRuntimeProvider: souscription
onDomainEvent — refresh sur changement catalogue global ou sur
projectPluginSettingsChanged du projet courant; gardes
révision/projet contre les réponses obsolètes
- useProjectAgents: refresh auto quand un agent est ajouté au projet;
ProjectsView et AgentsPanel suivent (erreur de rafraîchissement
affichée avec bouton Réessayer)
#331 — droplist agents des cellules:
- SmallDropdown: liste bg-overlay + bordure border-strong (plus de
fond blanc hors thème), hover/focus bg-raised, sélection
bg-primary/15, disabled text-faint opacity-60, role=combobox
- LayoutGrid: sélecteur d'agent des cellules migré du <select> natif
vers SmallDropdown (mêmes libellés Terminal/visible
ailleurs/arrière-plan)
QA verte réelle sur les quatre lots (tests ciblés + exécution).
sdk/IdeaSDK: contenu modifié non committable ici (pointeur inchangé).
Aucun push.
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.
- #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>
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).
- #151: chevauchement des boutons dans la barre supérieure pendant une conversation agent
- #158: popup de reprise de conversation intempestive (ajout cellule / changement layout / projet)
- #159: pastille d'activité de projet
Introduit SmallDropdown comme composant partagé et le fait adopter par
AgentsPanel, ModelServerSelect, OpenCodeModeFields, TemplateEditor et
TicketViewportSelect, pour que toutes les listes déroulantes dynamiques
(agent, modèle, template, viewport) partagent la même apparence que le
sélecteur d'agent de la création de ticket.
Refs #114
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Le popup viewport-positionné utilisait zIndex.menuDropdown (40), inférieur à
zIndex.floatingWindow (50) : il s'affichait derrière une fenêtre flottante
ouverte. Ajout de zIndex.transientPopup (65), au-dessus de floatingWindow et
floatingWindowNested, pour tout popup transitoire porté par document.body
depuis une FloatingWindow.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Lots 1 et 2 du ticket #69 : rendre le client web (#13) utilisable sur un
téléphone. Le client web n'a jamais eu de docks ni de fenêtres flottantes —
il est déjà une colonne verticale unique — donc le lot 2 se réduit aux
rangées qui débordaient réellement à 360px.
- `100dvh` sur html/body/#root : `height: 100%` se résout sur le *large*
viewport, donc la barre d'URL rétractable d'un navigateur mobile masquait
le bas de l'app. Desktop inchangé (dynamic == large viewport).
- `viewport-fit=cover` + padding `env(safe-area-inset-*)` sur le header et
le workspace : l'app peut peindre sous une encoche sans perdre ses
contrôles. Le zoom reste libre (accessibilité).
- Padding responsive (`p-4 sm:p-6`) : 48px de gouttière sur 360px, c'était
13% de la largeur.
- `AgentLiveRow` et la rangée de tâche de fond empilent leurs contrôles sur
téléphone (nom / badges / actions) et retrouvent leur ligne unique dès
`sm` — à 360px les boutons Cancel+Retry ne tenaient pas.
- Code d'appairage : `inputMode="numeric"`, pas d'autocapitalisation.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Stretch B2/F2 de #54, par-dessus le MVP déjà mergé (B1/F1).
Backend : le port de téléchargement HF publie une progression débouncée
(bytes reçus / total, pourcentage) via le stream de statut du serveur
modèle, avec gestion du total inconnu (pas de faux %), du cache hit,
de l'annulation et du timeout.
Frontend : l'overlay plein-cellule de préparation du serveur affiche la
progression réelle (barre, %, octets, source) en mappant le fil de
statut, avec la règle « pas de faux % » quand le total est inconnu.
Tests : application + infrastructure (téléchargement débouncé, cancel,
timeout, cache hit, total inconnu) et vitest (overlay + formatage pur).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Sous-menus flyout dans MenuBar ; ProjectsView expose un menu unique
Panneaux et supprime les menus View/Window/File ainsi que le sélecteur
de projet ; ProjectTabs gère les onglets et le bouton +. Tests migrés
en conséquence.
QA vert : tsc --noEmit exit 0, vitest 62 fichiers / 616 tests passés,
invariants préservés.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Introduit la primitive de docking DockRegion et le modèle ViewPlacement
pour ancrer les vues dans le chrome, câblés dans ProjectsView. Tests
unitaires DockRegion et test d'intégration docking de ProjectsView.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Le focus-trap de FloatingWindow avait un useEffect dépendant de `[onClose]`.
`onClose` (ex. TicketDetail.requestClose) est une closure recréée à chaque
render : chaque frappe ré-armait l'effet et renvoyait le focus au premier
élément focusable, ne laissant saisir qu'une lettre à la fois dans le
formulaire d'édition.
Correctif : conserver le dernier `onClose` dans un `onCloseRef` et passer
l'effet focus-trap en mount-only (`[]`). Le handler Escape lit la valeur
courante via la ref. Ajout d'un test de régression prouvé rouge-sans /
vert-avec le fix.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Lot C du sprint UI rework : fenêtre dédiée de gestion des tickets,
appuyée sur la primitive FloatingWindow (#16) et la popup TicketPicker (#18).
- TicketDetail : gestion des liens de ticket via la popup TicketPicker,
assistant IA en fenêtre flottante
- FloatingWindow : ajustements pour l'usage fenêtre dédiée
Tests : tsc --noEmit clean, suite complète 530/530, suites tickets +
FloatingWindow 50/50.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Lot A du sprint UI rework : réorganisation de la navigation racine.
- shared/ui/MenuBar.tsx : barre de menus unique avec menus déroulants
- shared/ui/FloatingWindow.tsx : primitive de fenêtre flottante réutilisable
(socle du lot C #17 fenêtre dédiée gestion tickets)
- shared/ui/zIndex.ts : échelle z-index étendue pour les fenêtres flottantes
- App : intègre la barre unique et le sélecteur de projet permanent
- ProjectsView : sélecteur de projet permanent
Tests : tsc --noEmit clean, suite complète 527/527, suites impactées 33/33.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Ajoute TicketPicker, popup modale réutilisable de sélection de ticket,
socle du chemin critique du sprint UI rework (#17 et #19 en dépendent).
- TicketPicker.tsx : popup de recherche/sélection réutilisable
- useTicketSearch.ts : hook de recherche/filtrage extrait et partagé
- TicketFacetsBar.tsx : barre de facettes extraite de TicketsPanel
pour réutilisation (listing principal + picker)
- shared/ui/zIndex.ts : échelle z-index centralisée
- TicketsPanel : consomme la barre de facettes extraite
Tests : TicketPicker.test.tsx 8/8, suite tickets 37/37, tsc --noEmit clean.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>