Commit Graph

327 Commits

Author SHA1 Message Date
ea7a98be03 Merge chore/fmt-agent-lifecycle into develop
Applique rustfmt sur agent_lifecycle.rs pour que develop repasse
`cargo fmt --check`. Fix de formatage pur, aucun changement de comportement.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-13 18:01:14 +02:00
7ddf4d46b9 chore(fmt): appliquer rustfmt sur agent_lifecycle.rs
Reformate `launch_opencode_omits_api_key_when_profile_has_none` selon
rustfmt (le fichier committé échouait `cargo fmt --check`). Aucun
changement de comportement, purement du formatage.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-13 17:59:26 +02:00
afbf315e97 feat(view-windows): exposer list_open_view_windows pour l'état du menu
Ajoute la commande Tauri `list_open_view_windows` qui retourne un
`ViewWindowSnapshot` (panel, label, visible) par fenêtre de panneau
détachée, avec le parseur `view_panel_from_window_label` (labels stables
et legacy suffixés du project id). Enregistre la commande dans le
handler. Backend seul pour le ticket #50 ; pas encore de consommateur
frontend.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-13 17:59:15 +02:00
9326a4897a chore(memory): nettoyer les notes transitoires et supersédées (#49)
Suppression de 31 notes de mémoire projet devenues transitoires
(checkpoints, plans de test datés, findings résolus) ou supersédées, et
remise en parité de l'index MEMORY.md (52 entrées = 52 fichiers).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-13 13:20:07 +02:00
8bbd8d3d68 Merge feature/ticket30-session-limit-handle-main into develop
Fix du handle de limite de session sur le chemin direct (#30) + émission
AgentRateLimited sur le chemin délégué (#7/F2). QA verte.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-13 13:19:46 +02:00
225890b57a fix(session-limit): émettre AgentRateLimited sur le chemin délégué (#7)
Sur le rendez-vous délégué (idea_ask_agent), quand la cible touchait sa
limite de session, l'événement AgentRateLimited n'était pas émis : l'écart
backend documenté (ticket #7/F2) laissait la surface UI sans signal de
limite pour la cible déléguée.

Le service orchestrateur relaie désormais la limite de la cible vers le
service de limite de session, fermant l'écart en cohérence avec le chemin
direct (#30).

Couverture QA (sortie réelle) : orchestrator_service 63 passed,
session_limit_service 15 passed, session_limit_t4 7 passed,
cargo test -p application 0 failed.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-13 13:19:21 +02:00
9430c65050 fix(session-limit): brancher le handle de limite sur le chemin direct (#30)
Le handle de limite de session ne se déclenchait pas quand un agent
directement adressé (dont Main) touchait sa propre limite : le ReplyEvent
::RateLimited du chemin structuré direct n'était pas relayé au service de
limite.

On tap désormais ReplyEvent::RateLimited dans le registre terminal vers
SessionLimitService::on_rate_limited, qui émet AgentRateLimited puis
AgentResumeScheduled et arme la reprise auto annulable, exactement comme le
chemin délégué.

Couverture QA (sortie réelle) : structured_registry_d1 12 passed,
session_limit_wiring 6 passed.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-13 13:19:11 +02:00
631dd4eccf Merge feature/ticket46-project-tab-add-button into develop
fix(projects): rendre visible le bouton + d'ajout d'onglet projet (#46)

Dernier ticket du sprint « Gestion des bugs » (#48, #45, #27, #47, #46).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-13 12:42:38 +02:00
b152e33b60 fix(projects): rendre visible le bouton + d'ajout d'onglet projet (#46)
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>
2026-07-13 12:42:31 +02:00
0e594adaf3 Merge feature/ticket47-panel-only-windows into develop
fix(windows): restauration panel-only des fenêtres détachées suivant le projet en focus (#47)

Backend + frontend : fenêtres/panneaux détachés restaurés en mode panel-only
(sans project_id figé), suivant le projet en focus de la fenêtre principale
via l'event focused-project.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-13 12:37:56 +02:00
221cc8be78 fix(windows): fenêtres de panneau détachées suivent le projet en focus côté UI (#47)
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>
2026-07-13 12:37:45 +02:00
6387fac34f fix(windows): restauration panel-only des fenêtres détachées suivant le projet en focus (#47)
Partie backend. Les fenêtres/panneaux détachés étaient restaurés avec un
project_id figé au moment du détachement, si bien qu'ils restaient collés à
un projet mort ou incohérent après redémarrage. Ils sont désormais restaurés
en mode panel-only, sans project_id figé, et suivent le projet en focus de la
fenêtre principale via un event focused-project exposé par la couche fenêtre.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-13 12:37:25 +02:00
1e0cb16ead Merge feature/ticket27-ticket-assistant-mcp-tools into develop
fix(ticket-assistant): édition de ticket via les tools MCP idea_ticket_* (#27)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-13 09:10:31 +02:00
8570adb8e0 fix(ticket-assistant): édition de ticket via les tools MCP idea_ticket_* (#27)
L'assistant IA d'édition de ticket éditait les fichiers du ticket en direct,
hors de tout contrôle. Il passe désormais par les tools MCP idea_ticket_* :
préparation d'un environnement structuré dédié et policy d'enforcement scopée
au ticket courant, de sorte que l'assistant ne peut agir que sur son ticket
via la surface MCP plutôt que sur le système de fichiers.

Couvert par de nouveaux tests QA (mcp_server, assistant_context_store).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-13 09:10:23 +02:00
e54ffae0c3 Merge feature/ticket45-model-server-singleflight into develop
fix(model-server): singleflight au démarrage du serveur de modèle local (#45)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-13 08:52:49 +02:00
3fff3402ec fix(model-server): singleflight au démarrage du serveur de modèle local (#45)
Corrige la race « port_occupied:8080 » au démarrage OpenCode/model server :
plusieurs demandes concurrentes tentaient chacune de lancer le serveur de
modèle local, provoquant un conflit de port. Le démarrage est désormais
sérialisé en singleflight — une seule tentative de lancement partagée entre
les appelants concurrents.

Couvert par un nouveau test de concurrence (cargo test -p application vert :
81 unit + 9 model_server).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-13 08:52:43 +02:00
f24f8f12aa Merge feature/ticket48-cell-error-banner into develop
fix(layout): bandeau d'erreur cellule au-dessus des boutons de contrôle (#48)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-13 08:42:23 +02:00
e64c0b7840 fix(layout): bandeau d'erreur cellule au-dessus des boutons de contrôle (#48)
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>
2026-07-13 08:42:13 +02:00
1331c5b2c2 Merge feature/ticket40-persist-restore-windows into develop
Persistance et restauration des fenêtres au redémarrage (#40).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-13 08:00:25 +02:00
2eb51d3335 feat(windows): persistance et restauration des fenêtres au redémarrage (#40)
Persiste l'état des fenêtres (layout/position) et le restaure au
relancement de l'application. Découpage hexagonal :
- domaine : modèle et port d'état des fenêtres (layout, ports)
- application : use cases de persistance/restauration
- infrastructure : store window_state (adapter de persistance)
- présentation : câblage app-tauri (state, commands, lib)
Couvert par des tests ciblés domaine/application/infrastructure.

Depend de #39 (fermeture des fenêtres auxiliaires).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-13 08:00:20 +02:00
55087b5d9b Merge feature/ticket29-persist-ticket-filters into develop
Persistance des filtres tickets entre redémarrages (#29).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-13 07:45:56 +02:00
79f06c26d9 feat(tickets): persistance des filtres tickets entre redémarrages (#29)
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>
2026-07-13 07:45:50 +02:00
e6f10d2b74 Merge feature/ticket39-close-main-closes-all-windows into develop
Fermeture des fenêtres auxiliaires à la fermeture de la fenêtre principale (#39).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-13 07:45:34 +02:00
13d45cb752 feat(app-tauri): fermeture des fenêtres auxiliaires quand la principale se ferme (#39)
Ajoute close_non_main_webview_windows sur l'event de fermeture de la
fenêtre principale, avec le prédicat should_close_with_main_window qui
exclut la fenêtre "main" et cible toutes les fenêtres auxiliaires
(vues détachées, settings…). Couvert par 3 tests unitaires.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-13 07:45:27 +02:00
9ee7290cde Merge feature/ticket38-assign-sprint-on-create into develop
Attribution d'un sprint à la création de ticket via popup SprintPicker
(#38). QA vert (tsc + 634 tests).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-12 20:03:45 +02:00
0039958b82 feat(tickets): attribution d'un sprint à la création via popup SprintPicker (#38)
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>
2026-07-12 20:03:41 +02:00
a3c0dd410a Merge feature/ticket37-sprint-tickets-status-filters into develop
Conservation des tickets en sprint + statut + filtres (#37). QA vert
(tsc + 623 tests).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-12 19:55:58 +02:00
1c28754b58 feat(tickets): conservation des tickets en sprint, affichage du statut & filtres (#37)
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>
2026-07-12 19:55:54 +02:00
338b8707de Merge feature/ticket41-ticketpicker-multiselect into develop
Multi-sélection TicketPicker (#41). QA vert (tsc + 620 tests).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-12 19:45:44 +02:00
daa93525d7 feat(tickets): multi-sélection dans TicketPicker (#41)
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>
2026-07-12 19:45:39 +02:00
61e5e41f0d Merge feature/ticket42-dockcontrols-header into develop
Refinement UX DockControls (#42) suite #26 : clarification des
contrôles d'en-tête. QA vert (tsc + 616 tests).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-12 19:32:42 +02:00
73859a05e1 feat(ui): clarification des contrôles d'en-tête DockControls (#42)
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>
2026-07-12 19:32:37 +02:00
c864d4a692 Merge feature/ticket26-ui-rework-menus into develop
Refonte menus & fenêtres (#26) : menu unique Panneaux, onglets projet
avec bouton +, sous-menus flyout. QA vert (tsc + 616 tests).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-12 15:08:52 +02:00
09e7f212b7 feat(ui): refonte menus & fenêtres — menu unique Panneaux et onglets projet (#26)
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>
2026-07-12 15:08:34 +02:00
805d4b70a2 Merge feature/model-server-hf-source-wizard-v2 into develop
Support natif d'une source modèle Hugging Face (-hf) en alternative au
chemin .gguf local pour le serveur llama.cpp intégré, options structurées
llama.cpp (host/gpu_layers/context_size/jinja), preview de commande, et
refonte UX du wizard V2. Migration store model-servers.json V1 -> V2.

QA : suites ciblées vertes (domain 7, application 8, infra model_server 4,
app-tauri dto 5, Vitest 22, tsc/build OK).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-12 14:32:21 +02:00
efa081b074 feat(model-server): wizard V2 config modèles locaux — source, options structurées & preview
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>
2026-07-12 14:32:04 +02:00
38aecf2cac feat(model-server): source Hugging Face (-hf) + options structurées llama.cpp + migration store V2
Backend du support natif d'une source modèle Hugging Face en alternative au
chemin .gguf local pour le serveur llama.cpp intégré, et refonte des options.

- domaine : ModelSource {LocalPath|HuggingFace} + HfModelRef,
  LlamaCppOptions {host,gpu_layers,context_size,jinja}, invariant auto_start
  exigeant une source, validate_free_args (rejet des flags réservés).
- infra : build_argv partagé avec build_spawn_spec, émission -hf vs --model,
  ordre argv figé ; migration model-servers.json V1 -> V2.
- app-tauri : DTO V2 (modelSource, compat modelPath, conflit = INVALID),
  commande preview_model_server_command.

QA : cargo test ciblés verts (domain 7, application 8, infra model_server 4,
app-tauri dto 5). Échecs des suites complètes infra/app-tauri environnementaux
(sandbox bind/socket), hors périmètre.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-12 14:31:54 +02:00
bc96285fa5 Merge feature/modeles-locaux into develop
Sprint « Modeles locaux » terminé et vert : serveur de modèle local
llama.cpp intégré (#35) et profils OpenCode locaux multiples (#36).
Backend (domain/application/infra/app-tauri) + frontend.

Tests verts (exécution réelle) : cargo build workspace Finished ;
domain+application ; app-tauri dto_model_servers 3/3, dto_profiles 10/10 ;
infra model_server 2/2 ; application model_server+profile_usecases 19/19 ;
frontend tsc propre + vitest 608/608.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-11 15:51:05 +02:00
a244f32f31 chore(ideai): versionne le store tickets/sprints/mémoire du sprint Modeles locaux
Store d'orchestration du sprint « Modeles locaux » : sprint 883534aa,
tickets #35/#36 (et #32/#37–#41 du store), compteurs et index, notes
mémoire de livraison (#35 CRUD/statut, #36 multi-profils, OpenCode↔llama.cpp).

Runtime transitoire volontairement exclu (background-tasks/, agent scratch
testllamacpp.md).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-11 15:50:46 +02:00
72476a650a feat(model-server): frontend modèles locaux — badge de statut & CRUD serveurs (#35) et wizard multi-profils OpenCode (#36)
Sprint « Modeles locaux », couche frontend.

#35 :
- F35.1 badge de statut de lancement du serveur local
  (ModelServerLaunchBadge + useAgentsModelServer).
- F35.2 feature model-servers : CRUD (ModelServersPanel / useModelServers /
  gateway modelServer) et ModelServerSelect.

#36 :
- Liste multi-profils OpenCode dans le wizard de premier lancement,
  gateway de clonage (clone_opencode_profile_from_seed).

Tests verts (exécution réelle) : tsc propre, vitest 608/608.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-11 15:50:18 +02:00
b82ac76f8b feat(model-server): backend modèles locaux — serveur llama.cpp intégré (#35) et profils OpenCode locaux multiples (#36)
Sprint « Modeles locaux », couche backend (domain/application/infra/app-tauri).

#35 — Serveur de modèle local intégré (llama.cpp) :
- domain: model_server.rs (agrégat + statut), ports ModelServerProbe /
  ManagedProcess / ModelServerRuntime / ModelServerRegistry, événements
  model_server_status_changed et agent_launch_failed.
- application: use case EnsureLocalModelServer branché sur LaunchAgent.
- infrastructure: adapters HttpOpenAiCompatibleProbe, LlamaCppRuntime,
  LocalManagedProcess, FsModelServerRegistry.
- app-tauri: DTO plat LocalModelServerConfigDto, commandes
  list/save/delete_model_server avec garde model_server_in_use, wiring.

#36 — Profils OpenCode locaux multiples :
- domain: VO LocalModelServerId, OpenCodeConfig.local_model_server_id.
- application: use case CloneOpenCodeProfileFromSeed.
- app-tauri: commande clone_opencode_profile_from_seed, DTO/wiring.

Tests verts (exécution réelle) : domain+application OK, app-tauri
dto_model_servers 3/3 et dto_profiles 10/10, infra model_server 2/2,
application model_server+profile_usecases 19/19, cargo build workspace Finished.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-11 15:50:08 +02:00
2e98f1fbb9 Merge feature/opencode-llamacpp into develop
Remplace le provider Ollama par llama.cpp dans l'intégration OpenCode
(tool-calling local). QA vert, réserve E2E live non bloquante.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-11 00:41:31 +02:00
4e70631c40 feat(opencode): remplace le provider Ollama par llama.cpp
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>
2026-07-11 00:41:19 +02:00
eaba05d27d feat(opencode): remplace le profil Ollama HTTP par OpenCode
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-09 15:48:07 +02:00
2fa226e413 chore(tickets): versionne le store de tickets et de sprints du projet
`.ideai/tickets/` et `.ideai/sprints/` sont le registre durable du projet (les
tickets sont déjà référencés par les messages de commit : #14, #21..#25, #28),
au même titre que `.ideai/memory/`. Ils entrent donc dans le dépôt.

À l'inverse, `.ideai/background-tasks/` (snapshots de rendez-vous headless) et
`.ideai/proposals/` (amendements de contexte en attente d'arbitrage) restent de
l'état d'exécution transitoire, de la même classe que `live-state.json` et
`.ideai/requests/` : ils doivent être ignorés (patch `.gitignore` à venir).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-08 08:38:33 +02:00
56757c7e1b chore(ideai): contextes des agents UX/TestOllama, MAJ DevFrontend et permissions associées
Ajoute les contextes des deux nouveaux agents et enregistre leurs règles dans
`.ideai/permissions.json`. Aucun impact applicatif : état de configuration
projet, isolé du code de feature.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-08 08:38:21 +02:00
ffc458e477 docs(memory): notes projet du sprint UI rework et des tickets #7/#14/#16/#17/#18/#25/#28
Capitalise les notes durables produites pendant le sprint UI rework et les
tickets livrés depuis. Commit séparé du code : `.ideai/memory/` est le store
durable versionné, il ne doit jamais être mélangé aux commits de feature.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-08 08:38:16 +02:00
710fa8fdd7 Merge feature/ticket28-firstrun-detect-hang into develop (#28)
First-run wizard figé : boutons « Save and continue » et « Detect installed
CLIs » grisés à vie.

Cause racine à deux étages, corrigée aux deux :
- backend : `AgentRuntime::detect` était un `fn` synchrone pilotant un
  spawner async via un `block_on` imbriqué — panique sous le runtime Tauri,
  commande IPC sans réponse. Le port passe en `async fn`, la sonde est bornée
  par un timeout, et les profils OpenAI-compatible sont sondés en HTTP.
- frontend : `busy` awaitait `detectProfiles`, si bien qu'une promesse
  pendante grisait les actions sans issue. La détection devient best-effort,
  suivie par un drapeau `detecting` séparé qui n'inhibe rien.

QA vert (exécution réelle) : domain 241, application 81, infrastructure 269,
app-tauri 63+15 ; vitest 569 tests / 59 fichiers ; tsc --noEmit exit 0.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-08 08:12:00 +02:00
0389e2e0b0 fix(first-run): découple busy de la détection des CLI (#28)
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>
2026-07-08 08:11:24 +02:00
3abf2fce98 fix(runtime): detection non bloquante, bornée dans le temps, HTTP pour les profils locaux (#28)
Le first-run wizard restait figé : `CliAgentRuntime::detect` construisait un
runtime tokio courant-thread via `futures_block_on` pour piloter un
`ProcessSpawner` async. Appelé depuis le runtime async de Tauri, ce
`block_on` imbriqué panique ; la commande IPC ne répond alors jamais, la
promesse `detectProfiles` reste pendante et `busy` ne redescend plus.

Ce commit s'attaque à la cause côté backend :

- `AgentRuntime::detect` devient `async fn` (`#[async_trait]`) : le port cesse
  de mentir sur sa nature. Il pilote un spawner async, il est async. Le
  `futures_block_on` disparaît, et avec lui le runtime imbriqué.
- La sonde CLI est bornée par `tokio::time::timeout(DETECTION_TIMEOUT)` :
  un binaire qui ne rend jamais la main dégrade la détection en `Err`, il
  ne gèle plus l'appelant.
- Les profils `StructuredAdapter::OpenAiCompatible` n'ont pas de CLI à
  spawner : les sonder revenait à tester un binaire inexistant. Ils sont
  désormais sondés par un GET HTTP sur l'endpoint `/models` dérivé de
  `chat_http.endpoint`, borné par le même timeout.

`DetectProfiles` séquence les `await` sur les candidats. Les fakes
`AgentRuntime` des crates application/infrastructure/app-tauri suivent la
nouvelle signature.

Tests: cargo test -p domain (241), -p application (81), -p infrastructure
(269), -p app-tauri (63+15) — verts. `rg futures_block_on crates` sans match.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-08 08:11:14 +02:00