Le corps d'une leaf (layout-leaf-body) crée désormais son propre stacking context (z-index 0). Les vues CLI custom peuvent comporter des enfants à haut z local (toolbar z-20) qui restaient au-dessus des contrôles de cellule (CELL_Z 5) et captaient les clics ; ils restent désormais sous les contrôles. Test de layering dédié ajouté dans LayoutGrid.cellControlsLayering.test.tsx.
Boucle le gap end-to-end de #165 : à l'exécution d'une commande slash plugin
depuis le composer custom, l'UI traite l'effet pluginCallback et le dispatche
au PluginRuntimeRegistry pour que la callback du plugin s'exécute réellement.
- runtime/registry: runCommandStrict (échec explicite si handler absent) +
propagation de la valeur de retour ; élargit les types de retour (unknown).
- runtime/loader: chargement de contributes.slashCommands au registre +
propagation du retour du handler.
- features/plugins/usePluginMenus: runCommand retourne unknown.
- features/agents/CustomAgentChatView: handler de l'effet pluginCallback ->
pluginRuntime.registry.runCommandStrict, avec retour utilisateur en cas
d'échec (commande indisponible / callback absente).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Permet à un plugin de contribuer des commandes slash adossées à une callback,
transitant par le registry/contrat unifié (#162) :
- sdk/IdeaSDK: manifeste contributes.slashCommands (déclaratif) — pointer bumpé.
- domain: source Plugin étendue + effet PluginCallback (la commande ne
s'exécute pas directement : elle renvoie une référence à la callback du plugin).
- application: registration des commandes plugin dans le registry + exécution
renvoyant l'effet PluginCallback ; métadonnées UI suffisantes pour l'autocomplete.
- backend + app-tauri: DTO + commandes Tauri listant/invoquant les commandes plugin.
- frontend (contrat): types adapters/domain/ports/mock pour pluginCallback et
l'invocation avec arguments.
L'exécution effective de la callback côté runtime UI est livrée par #166.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Ajoute /profile comme commande slash first-class dont la sémantique de reset
de session reste explicite et testable, séparée de la palette générique :
- domain + application: /profile est enregistrée et renvoie un effet
SlashCommandEffect::ProfileSwitch { session_id }. La commande ne reset pas
directement : elle délègue l'effet au frontend pour imposer une confirmation.
- frontend (CustomAgentChatView): à l'exécution de /profile, ouverture d'un
popup de sélection de profil informant que la validation reset la session,
avec confirmation explicite (confirmedReset) requise avant changeAgentProfile.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
À la saisie d'un « / » en début de draft (sans espace), ouverture d'un menu
contextuel listant les commandes matchant le préfixe, via le contrat unifié
listSlashCommands — aucune liste codée en dur côté UI. Rafinement incrémental
des suggestions à la frappe, navigation clavier + sélection, exécution par
executeSlashCommand.
- adapters/agent: listSlashCommands(prefix?) + executeSlashCommand (invoke Tauri).
- domain + ports: types SlashCommand / ExecuteSlashCommandResult.
- mock: données de test.
- CustomAgentChatView: détection de préfixe (/ sans espace), fetch avec séquence
anti-retard, gestion ouverture/active index, navigation clavier, fermeture
quand le préfixe cesse d'être éligible.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Ajoute completeRunningProgress() qui passe les stages started/delta à
completed lors des événements final/error. La ligne Progress conserve son
contenu statique utile mais n'affiche plus l'animation de chargement une
fois le tour terminé.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Extrait le bouton Cancel du banner inline et le rend en position absolue
(top:24, right:20) avec zIndex CELL_Z.turnActions. Le banner de statut est
décalé (right:76 en état busy) et rétrogradé en CELL_Z.banner, afin que
Cancel reste au premier plan et cliquable sans recouvrement en état busy.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- frontend: onPaste sur CustomAgentChatView, détection MIME image, chip/preview d'attachment, envoi via le contrat #154 (adapters/agent, ports)
- backend: import d'image par bytes dans le store attachments (commands, chat_attachments app+infra, dto, ports) + tests
- #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
- Ajoute cellKind dans AgentChatHandle et vérifie que launchAgentChat reçoit cellKind:chat
- Rejette avec erreur STRUCTURED_ROUTED_TO_PTY si le backend route vers PTY
- Ajoute cellKind:chat dans MockAgentGateway.launchAgentChat
- Corrige l'overflow du layout CustomAgentChatView (bounded shell avec scroll + composer fixe)
- Dédouble les prompts utilisateur quand le stream les echo
- Ajoute les tests launchAgentChat returns handle only when confirms chat et launchAgentChat rejects PTY-routed launch
- Ajoute les tests does not duplicate user prompt when echoed et keeps chat shell bounded
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Elargit isNotFound() pour reconnaitre aussi la forme brute
'not found: structured session <uuid>' que Tauri peut retourner,
en plus de la forme typée {code: 'NOT_FOUND'}.
Ajoute deux tests couvrant:
- fallback sur reattach avec erreur brute
- retry prompt sur send avec erreur brute
QA: tests passés sur cette correction.
Ajoute des points de traçage ciblés sur le cycle de vie de session
CustomAgentChatView/LayoutGrid pour isoler la cause du fallback
silencieux CLI custom avant tentative de fix.
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>
Sur reattach NOT_FOUND, le composant retentait implicitement l'attach sur le
même sessionId mort au lieu de nettoyer l'état avant de relancer, ce qui
produisait l'erreur "not found: structured session …" côté utilisateur.
recoverStructuredSession() nettoie désormais sessionId/conversationId avant
de relancer et retente une seule fois le reattach sur NOT_FOUND post-launch.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
reattachAgentChat pouvait échouer avec NOT_FOUND (session structurée fermée
ou jamais vivante) et laisser fuiter l'erreur brute jusqu'à l'utilisateur
("not found: structured session ... not found") au lieu de relancer une
session fraîche. Le fallback ne s'applique qu'au code NOT_FOUND ; toute
autre erreur de reattach continue de remonter telle quelle.
QA vert 2026-08-05 : npx vitest run CustomAgentChatView.test.tsx,
npx vitest run agents.test.tsx CustomAgentChatView.test.tsx, npm run typecheck.
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>
Ajoute la vue window host qui charge le layout plugin dans une fenêtre OS
détachée, expose react/react-dom/jsx-runtime hébergés sous
frontend/public/plugin-host pour que le runtime SDK y résolve React, et
câble services.windows.open() côté runtime plugin (loader/services/registry).
npm test -- --run src/adapters/window.test.ts src/app/ViewWindow.test.tsx
src/plugins/runtime/loader.test.ts src/plugins/runtime/services.test.ts : 39/39
npm run typecheck : OK
npm run build : OK
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Étend le flux de création de layout backend (DTO, usecases, store) et le
frontend (sélecteur, adaptateurs, LayoutTabs/LayoutGrid) pour permettre
d'ouvrir un layout déclaré par un plugin installé (ex. Android Health),
sans passer par le message bloquant "extension backend pas encore livrée".
Ticket #141 — QA vert.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Plugins can now declare activationScope ("app" | "project") in their
manifest; loader/runtime honor it to defer activation of project-scoped
plugins until a project is focused instead of activating everything at
app bootstrap. Bumps sdk/IdeaSDK to the commit that adds the field.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Le contexte projet d'un agent s'affichait "[object Object]" et se
vidait à la réouverture du panneau : read_agent_context renvoie déjà
{content} côté backend, mais les gateways front traitaient la réponse
comme une string brute. Les deux gateways (Tauri + HTTP) unwrap
maintenant .content ; type AgentContextDocument ajouté au domaine.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
État d'intégration confiné à la branche batch. Les tickets #119 (skills →
capacités agent découvrables), #122 (override permissions par défaut), #131
(effort par agent/presets) et #132 (outil MCP d'édition du contexte projet)
sont verts en périmètre. Le sprint plugins multi-fichiers ESM / persistance
plugin-owned (#135/#136/#139) est co-implémenté dans les MÊMES fichiers de
câblage (frontend/src/ports/index.ts, backend/src/lib.rs, domain/ports.rs,
backend/dto.rs), inséparable sans staging interactif (indisponible ici).
Commit unique volontaire : préserve l'état vert QA sans découpe hunk risquée.
NON mergé vers develop tant que #137 (QA e2e plugins) n'est pas vert.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Les espaces et autres frappes étaient interceptés par un handler parent ;
stopPropagation sur le onKeyDown de l'input args laisse la saisie intacte.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- capability manifeste tooling supportée backend + transport runtime catalog
- ctx.services publique côté SDK/runtime, gated par tooling
- surface honnête: workspace, terminal, et tasks en observation/contrôle uniquement
- docs/exemple/tests mis à jour
- QA PASS sur feature/sdk-plugin-tooling-build-debug-surface
- carnet.md: enregistre la livraison CORS et la décision Git du 2026-08-01
- issue.md + index.json: mise à jour version/timestamp
- plugins.test.tsx: tests d'intégration frontend liés
- Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- plugin.ts: normalizeReview() garantit issues/installable définis même si backend omet ces champs
- mock/index.ts: MockPluginGateway.uninstall() retourne removalOutcome pour cohérence avec le domaine
- domain/index.ts: PluginUninstallResult ajoute removalOutcome optionnel
- Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- usePlugins.ts: remplace les mises à jour optimistes du state par des appels listPlugins() après chaque opération backend
- PluginsPanel.tsx: ajoute la normalisation isInstallable() pour éviter les crashes si installable est undefined
- Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Requalification Architect du 2026-08-01: le crash INTERFACE INTERROMPUE au
chargement d'un plugin (menu + item) remonte via ProjectsView -> usePluginMenus
-> MenuBar jusqu'à RootErrorBoundary, quel que soit le plugin (ancien ou
reconstruit via SDK).
- usePluginMenus isole la résolution/conversion des contributions plugin :
toute erreur retombe sur [] au lieu de propager.
- ProjectsView sépare les menus natifs des menus enrichis par plugin et rend
MenuBar derrière une error boundary locale (fallback menus natifs seuls).
- hello-plugin (SDK) et les tests d'installation associés durcis en cohérence.
Bookkeeping ticket #120 uniquement (issue.md, carnet.md) ; les fichiers
counter.json/index.json et le dossier tickets/122/ restent hors commit car
une collision de numérotation #122 existe entre cette base et
feature/ticket120-hello-plugin-install-path-audit (deux tickets différents
revendiquent #122) — à arbitrer avant de committer le bookkeeping global.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Complète le diagnostic backend (#120) côté frontend : un crash React non
capturé (ex. plugin cassant le rendu) laissait un écran noir sans trace, et
une activation de plugin qui ne se résout jamais (promesse infinie) bloquait
le chargement sans échouer. Ajoute RootErrorBoundary + logging d'erreurs
globales autour de l'arbre React, et un timeout sur l'import/l'activation de
chaque plugin dans loadPlugins pour transformer un hang silencieux en échec
explicite et diagnosticable.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Le champ contrôlé de ModelServersPanel/FirstRunWizard perdait les
espaces saisis dans les arguments llama.cpp (trim/split prématuré sur
chaque frappe au lieu de la seule sérialisation finale) (#113).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Le loader accepte désormais aussi la forme export default { activate }
en plus de l'export nommé, les subscriptions partiellement établies
sont nettoyées en cas d'échec d'activation, et une erreur de
runtime-catalog est remontée visuellement dans PluginsPanel avec un
badge Invalide/Isolé sur les plugins concernés (#116/#120).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Point de départ de la réinvestigation #120 : commandIdsFromContributes
et layoutTypesFromContributes typaient implicitement leurs Set en
unknown, masquant les valeurs vides potentielles issues des
contributions de plugin (piste du crash d'affichage à l'installation).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
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>
L'ancien correctif (traîne de refits à nombre de frames fixe,
MOUNT_SETTLE_REFIT_FRAMES) restait insuffisant : une cellule CLI pouvait
rester mal dimensionnée après un changement de projet/layout si l'agent
écrivait en arrière-plan pendant la fenêtre de stabilisation, nécessitant
un resize manuel pour corriger l'affichage. TerminalView détecte
désormais la stabilité réelle du fit (dimensions inchangées sur des
mesures successives) au lieu de s'appuyer sur un nombre de frames fixe
avant de rendre la main au ResizeObserver.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Le chargement de l'archive hello-plugin (build/hello-plugin-0.1.0.zip)
vidait la fenêtre principale : une contribution plugin fautive
remontait jusqu'au rendu global au lieu de rester locale à la cellule.
Ajoute un boundary local dans PluginLayoutCellView/PluginLayoutSelectorSection
et durcit menus.ts/loader.ts/registry.ts contre les entrées de menu ou
contributions malformées.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>