Lots 3 et 4 du ticket #69. Sans ça un agent CLI est indriveable depuis un
téléphone : le clavier virtuel n'a ni Esc, ni Tab, ni Ctrl, ni flèches, donc
on peut taper un prompt mais pas l'interrompre, compléter un chemin, sortir
d'un éditeur ou rappeler l'historique.
- `TerminalView` expose un `onReady(api)` optionnel (donc desktop inchangé,
et inerte quand xterm ne monte pas). `api.send` passe par `term.input()` :
le *même* chemin qu'une frappe réelle, donc le relais PTY, le comptage de
lignes et la suspension du write-portal s'appliquent à l'identique. Écrire
sur le handle aurait court-circuité le portal.
- `TerminalKeyBar` (web-only) : Esc/Tab/Ctrl-C/Ctrl-D/flèches en chips
tactiles 44px, scroll horizontal. Chaque tap annule le déplacement de
focus et refocalise xterm — sinon le clavier virtuel se referme à chaque
touche.
- La cellule agent passe de `h-64` fixe (une letterbox d'~20 lignes) à
`h-[60dvh]` sur téléphone, `sm:h-80` au-delà.
- Tests : séquences d'octets émises, préservation du focus, état désactivé
avant montage de xterm, et garde de non-régression sur la frontière —
le client web ne monte aucun layout-grid/split/dock desktop.
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>
Le client live visait /ws/live alors que le serveur expose /api/ws : la
connexion échouait et la reconnexion bouclait en permanence. Chemin corrigé
et extrait en constante WS_PATH, avec deux tests de non-régression sur
l'URL construite.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Firefox exige que fetch soit appelé sur Window : passer la référence nue
`fetch` en dépendance déclenchait « 'fetch' called on an object that does
not implement interface Window » au pairing. Nouveau helper defaultFetch()
qui binde globalThis.fetch, utilisé par webSession.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Flow logout : POST /api/logout puis retour à l'écran de pairing et
déconnexion du live. 401 renvoie au pairing sans boucle. Bannière de
reconnexion couvrant le cas live-only et le serveur indisponible.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Lot F5 du chantier server/client mode : le client web consomme les frames
event.domain (B7) pour animer ses surfaces live.
- webLive.ts : consommation du flux event.domain (workstate, background,
inbox).
- useLiveReconnect.ts : reconnexion du flux live.
- wsLiveClient.ts / index.ts : câblage du transport live.
- WebWorkspace.tsx : surfaces live branchées.
- Tests : WebWorkspaceLive.test.tsx, wsLiveClientReconnect.test.ts,
WebApp.test.tsx.
Validé : frontend 753 tests verts, desktop non régressé.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Lot F4 du chantier server/client mode : le client web expose une cellule
agent branchée sur le PTY WebSocket, en face de agent.launch (B6).
- wsLiveClient.ts : launchAgent sur le transport WebSocket.
- streamGateways.ts : gateway agent alignée sur le contrat serveur B6.
- WebAgentCell.tsx : cellule agent web, câblée dans WebWorkspace et index.
- Tests : agentGateway.test.ts, WebApp.test.tsx.
Validé : frontend 749 tests verts, contrat B6↔F4 aligné (aucun écart de
frame), desktop non régressé.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Lot F3 du chantier server/client mode : le client web branche xterm.js sur
le terminal distant via WebSocket, en face de l'endpoint PTY B5.
- wsLiveClient.ts : transport WebSocket du terminal avec reconnexion.
- streamGateways.ts : gateway terminal (open/attach/data/resize/close).
- frames.ts : frames PTY alignées sur le contrat serveur B5.
- Tests : terminalGateway.test.ts, wsLiveClientReconnect.test.ts.
Validé : frontend 743 tests verts (F3 ciblé 12), cohérence des frames
B5↔F3 confirmée, desktop non régressé.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Lot F2 du chantier server/client mode : client web read-only complétant le
premier incrément livrable — pairing, liste des projets, ouverture et
snapshot de l'état, sans PTY.
- frontend/src/adapters/http/webSession.ts : session web (pairing/cookie).
- frontend/src/features/web : PairingScreen, WebWorkspace, WebApp, index.
- Câblage main.tsx et adaptations httpInvoker.ts / index.ts (cas 401).
- Tests : webSession.test.ts, WebApp.test.tsx, cas 401 dans
httpInvoker.test.ts.
Validé : frontend 736 tests verts, build vert, garde no-direct-invoke
verte, contrat B4↔F2 aligné, desktop non régressé.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Lot F1 du chantier server/client mode : nouvel adaptateur web branché
derrière les ports d'invocation et de flux live, permettant au frontend de
dialoguer avec le backend via HTTP + WebSocket en mode client/serveur. Le
mode desktop (Tauri IPC) reste inchangé.
- frontend/src/adapters/http : invoker HTTP, client live WebSocket, gateways
request/response et stream, frames, garde unsupported (7 fichiers + 2 tests).
- frontend/src/app : câblage DI (di.tsx) et son test, typage vite-env.d.ts.
Validé : build vert, garde no-direct-invoke verte, 724 tests verts,
desktop inchangé.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Introduit un variant terminal `ReplyEvent::Error { message }` (domain/ports)
propagé jusqu'au chat : l'adapter OpenAI-compat récupère `reasoning_content`
quand `content` est vide, et un `Final` vide est converti en `Error` visible
plutôt qu'un tour silencieux qui pend. Le front (`ReplyChunk` + useTicketAssistant)
rend ce message d'erreur dans la cellule.
- domain: variant `ReplyEvent::Error`, bras non terminal (readiness, structured drain)
- infra/session: parse `reasoning_content` (delta/completion), fallback visible
- app-tauri: mapping ReplyEvent::Error -> ReplyChunk::Error, Final vide -> Error
- frontend: ReplyChunk `error`, rendu dans useTicketAssistant (+ test .test.tsx)
NB: commit sur la feature branch, PAS un merge. #60 reste inProgress.
Les 10 tests `cargo test -p infrastructure --lib session` échouent SOUS SANDBOX
uniquement (bind loopback 127.0.0.1:0 interdit -> Os PermissionDenied), pas une
régression : revérification hors-sandbox requise avant tout merge vers develop.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Le sélecteur d'agent de LayoutGrid désactivait un agent en se fondant sur le
seul liveAgents.nodeId : un agent live dont l'ancienne cellule affiche désormais
un autre agent restait grisé (« visible ailleurs ») alors qu'il n'était plus
affiché nulle part, donc impossible à resélectionner.
La dérivation « visible ailleurs » s'appuie maintenant sur le layout courant
(feuille visible ≠ cellule courante ET leaf.agent === candidate). Un agent live
dont l'ancienne cellule montre un autre agent redevient sélectionnable dans une
autre cellule ; la session n'est jamais tuée (attachLiveAgent conservé). Le prop
mort visibleNodeIds est retiré du threading.
Tests : frontend/src/features/layout/singletonAgent.test.tsx. Suite frontend
verte 706/706.
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>
Ajoute un handle du téléchargement des modèles lors du démarrage de
llamacpp : le domaine et l'application émettent la progression de
téléchargement du modèle, relayée en événement côté app-tauri, et l'UI
l'affiche via un badge de lancement et un overlay de cellule pendant que
le serveur de modèle démarre.
Backend (B1) : progression de téléchargement dans domain/application,
relais d'événement app-tauri, couverture de tests.
Frontend (F1) : modelServerLaunch, badge et overlay LayoutGrid, tests.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Extrait la logique de dérivation des entrées du wizard dans un module
dédié `wizardEntries` afin de préserver les informations du profil
courant lors de l'ouverture de l'affichage d'édition des profils, au
lieu de repartir d'un état vide. Couvre le comportement par des tests
unitaires (wizardEntries + FirstRunWizard).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Ticket #50 : commande backend `list_open_view_windows` + consommateur
frontend qui réconcilie l'état du menu Panneaux avec les fenêtres
détachées réellement ouvertes. Validé QA vert (frontend
typecheck+build+677 tests ; backend cargo check/build + 7 tests
view_window).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Branche le consommateur frontend sur la commande backend
`list_open_view_windows` : le port window expose la liste des fenêtres
de panneaux détachées réellement ouvertes côté OS, l'adaptateur Tauri
(et son double mock) l'implémente, et `ProjectsView` réconcilie le
placement des vues au démarrage à partir de ce snapshot au lieu de
supposer un état. Couvre `viewPlacement` et la réconciliation par des
tests dédiés.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Retire les utilitaires `flex-1` sur la liste d'onglets et sur le
placeholder « No open tabs. » : le conteneur ne pousse plus la zone
d'onglets sur toute la largeur, si bien que le bouton d'ajout de projet
« + » vient directement à la suite des onglets au lieu d'être repoussé à
l'extrémité droite de la barre.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Le bouton + de la barre d'onglets projets était invisible (pas de variant
d'affichage). Il est désormais rendu en permanence via un variant secondary,
avec aria-pressed et title pour l'accessibilité, permettant d'ajouter un
projet en onglet.
Couvert par un nouveau test (ProjectTabs.test.tsx).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Partie frontend. Ajoute un adaptateur focusedProject et un port dédié : la
ViewWindow détachée n'est plus liée à un project_id figé, elle s'abonne à
l'event focused-project émis par la fenêtre principale et affiche le panneau
du projet courant. ProjectsView propage le focus ; le détachement crée une
fenêtre panel-only. Couvert par les tests window/ViewWindow/focusedProject/
ProjectsView.focus.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Corrige la superposition z-index dans LeafView : le bandeau d'erreur de
cellule passait sous les boutons de contrôle, rendant le message illisible.
Le voile d'annonces ciblées est réaligné en conséquence.
Couvert par un nouveau test de layering (128/128 frontend au vert QA).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Introduit le port UiPreferencesGateway et son adapter uiPreferences,
avec le module ticketFilterPersistence qui sauvegarde/restaure les
filtres (recherche, statut, sprint, agents) via useTickets,
useTicketSearch et useProjectAgents. Couvert par tests unitaires et
un test d'intégration.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Nouveau composant SprintPicker permettant de choisir un sprint lors de
la création d'un ticket depuis TicketsPanel ; export ajouté à l'index
des features tickets. Frontend-pur.
QA vert : tsc --noEmit exit 0, vitest 63 fichiers / 634 tests passés.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Les tickets restent rattachés à leur sprint ; SprintManager affiche le
statut et propose des filtres via useTicketSearch. Frontend / read-query.
QA vert : tsc --noEmit exit 0, vitest 62 fichiers / 623 tests passés.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Le TicketPicker permet la sélection multiple de tickets ; SprintManager
consomme la sélection multiple. Frontend-pur.
QA vert : tsc --noEmit exit 0, vitest 62 fichiers / 620 tests passés.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Refinement UX suite #26 : clarifie les contrôles DockControls dans
l'en-tête des panneaux. Frontend-pur.
QA vert : tsc --noEmit exit 0, vitest 62 fichiers / 616 tests passés.
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>
Refonte UX du wizard de configuration des modèles locaux du serveur
llama.cpp intégré, alignée sur la source Hugging Face et les options backend.
- choix de source sans jargon (chemin local .gguf vs dépôt Hugging Face) ;
- champs structurés -ngl (gpu_layers), -c (context_size), --jinja, --host ;
- zone d'arguments libres avec alerte sur les flags réservés ;
- preview de la commande via le backend (previewModelServerCommand, debounced) ;
- gateway/ports et mock adaptés au contrat V2.
QA : Vitest 22 verts, tsc/build OK.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Le tool-calling local ne fonctionnait jamais via Ollama. Refonte du
support local d'OpenCode autour de llama.cpp: profil, catalogue,
matérialisation de la config OpenCode et surface first-run alignés sur
llama-server (backend + frontend).
QA vert (commandes réelles): domain 244, application 81+64, infra 263
(10 échecs = bind-port sandbox identiques sur develop, non-régression),
frontend 574, tsc propre. Réserve E2E live non bloquante faute de
llama-server joignable.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Même backend réparé, le wizard restait à la merci d'une détection qui ne
répond pas : `reload()` et `detect()` awaitaient `detectProfiles` sous le
même drapeau `busy` qui grise « Save and continue » et « Detect installed
CLIs ». Une promesse IPC jamais résolue laissait donc les deux boutons
grisés à vie — sans issue pour l'utilisateur.
La détection redevient ce qu'elle est : une étape best-effort, jamais
bloquante.
- `busy` ne garde plus que ce dont le wizard ne peut pas se passer
(`firstRunState`) ou qui mute l'état (`configureProfiles`). Il ne dépend
plus jamais de `detectProfiles`. L'invariant est documenté en tête de
module.
- Un drapeau `detecting` distinct suit la sonde et n'inhibe aucune action.
Il est relâché par un timer (`DETECT_TIMEOUT_MS`), jamais par la seule
promesse : celle-ci peut rester pendante indéfiniment.
- Un identifiant de tour monotone (`detectRun`) invalide les tours périmés
et ceux qui survivent au démontage, évitant un `setState` hors montage.
- `reload()` rend les lignes immédiatement puis lance la détection en tâche
détachée. Si elle échoue, les lignes restent cochables à la main ; seul le
bouton explicite remonte l'erreur.
Tests: vitest 59 fichiers / 569 tests verts, tsc --noEmit exit 0.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Câble la surface frontend des profils IA locaux/LAN OpenAI-compatible,
en parité avec l'adapter backend additif (aab4bca).
- domain: types de profil OpenAI-compatible
- first-run: édition/validation du profil dans le FirstRunWizard
- adapters/mock: mock de profil pour les tests
- terminals: rendu des round-trips et erreurs endpoint (role=alert)
Validé QA (frontend GO): typecheck exit 0, vitest 59 fichiers / 566 tests,
0 echec ; couverture timeouts round-trip + erreur endpoint role=alert
prouvees ; pas de regression sur les tests de bail headless.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Détache les vues dans de vraies fenêtres système Tauri (multi-écran,
fullscreen). Backend : commandes de gestion de WebviewWindow, capabilities
et composition root. Frontend : nouveau port WindowGateway et son adaptateur
window, entrée panel-only ViewWindow/ViewPanelBody, détachement câblé dans
ProjectsView. QA vert : app-tauri 63, frontend typecheck + vitest 546/546.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Anchor de views — primitive de docking DockRegion + modèle ViewPlacement,
câblés dans ProjectsView. QA vert : frontend typecheck + vitest 537/537.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Ajoute le sélecteur de tri dans TicketFacetsBar et propage le critère
via useTicketSearch jusqu'à TicketsPanel et TicketPicker, sur le contrat
de tri backend (e523f44). Couvre le tri par les tests tickets et
TicketPicker.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Ajoute le paramètre de tri dans TicketListQuery et l'expose via
ticket_list (surface app-tauri + MCP). Ports et adaptateur mock
frontend alignés sur le contrat de tri. La partie UI (contrôle de tri
dans TicketFacetsBar) suivra dans un commit frontend dédié.
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 D du sprint UI rework : branche la popup réutilisable TicketPicker (#18)
dans la sélection de ticket de la création/édition de sprint.
- SprintManager : sélection de ticket déléguée à la popup TicketPicker
- TicketsPanel : ajustements liés à l'intégration
Tests : tsc --noEmit clean, suite complète 528/528, suite tickets 38/38
(dont 2 nouveaux tests #19).
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>
Aligne le contrat DTO du panneau work-state (#5).
- ajout summary: string|null à BackgroundCompletion, mappé depuis task.summary
- affichage discret du résumé sur une tâche terminale
- suppression du chemin de merge top-level mort des background tasks
Tests verts : vitest workstate.test.tsx (21), suite complète (507),
npm run build (exit 0).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Passe les filtres de la liste des tickets en sélection multiple (#12).
Backend Rust :
- IssueListFilter : statuses/priorities en Vec, filter_matches en OR intra-champ
et AND inter-champs
- TicketListRequestDto en tableaux + from_request (parse/déduplication)
- MCP idea_ticket_list aligné sur le nouveau contrat
Frontend :
- TicketListQuery.statuses/priorities
- UI de cases à cocher, toggle/clear des filtres
Tests verts : issue_store (7), app-tauri --lib (59), mcp_server (24),
issue_usecases (6), sprint_usecases (6), frontend vitest (505), npm run build (exit 0).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Ajoute la suppression complète d'un ticket (#6).
Backend Rust :
- port IssueStore::delete (NotFound si absent) + event IssueDeleted{freed_sprint}
- FsIssueStore::delete : supprime .ideai/tickets/<N>/ et l'index sous lock
- use case DeleteIssue + adaptations des tests sprint/ticket_assistant au port
- commande Tauri ticket_delete + câblage events/state/lib
Frontend :
- gateway delete (ports, adapter ticket + mock, domain)
- useTicketDetail : retrait de la liste et fermeture du détail via event issueDeleted
- intégration TicketDetail + tests
Tests verts : application/issue_usecases (6), infrastructure/issue_store (7),
app-tauri --lib (56), frontend vitest (503), npm run build (exit 0).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Ticket #11 — surface UI de gestion des sprints (frontend pur).
- Nouveau composant SprintManager : création (nom optionnel), édition et
gestion du cycle de vie d'un sprint, contrôles accessibles (pas de DnD).
- useTickets étendu aux opérations de gestion de sprint ; ports, adaptateurs
(ticket.ts, mock/index.ts) et TicketsPanel câblés en conséquence.
- Tests Vitest associés (tickets.test.tsx).
Typecheck / vitest (497+ tests) / build verts.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Ticket #9 — l'édition d'un ticket (titre, corps, champs) est désormais
persistée depuis le détail : useTicketDetail porte l'état d'édition et le
flux de sauvegarde, TicketDetail expose l'UI d'édition/validation.
Tests Vitest tickets verts (13/13), typecheck et build OK.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>