Commit Graph

106 Commits

Author SHA1 Message Date
02603441c1 fix: livrable tickets #70 #100 #102 — UX surface scoping
- #70: implémentation suppression modèles locaux téléchargés
- #100: correction scroll OpenCode
- #102: correction fit TUI après switch/layout
- memory note scoping UX
2026-07-26 19:42:06 +02:00
ca70ec75f4 feat: catalogue dynamique modèles Codex/Claude avec compatibilité CLI locale
Ajout du catalogue enrichi pour les modèles Codex et Claude avec:
- Compatibilité estimée avec la version CLI locale détectée
- Source d'origine (catalogue/Provider) pour chaque entrée
- Support du catalogue Provider API externe
- Matrice de compatibilité embarquée dans l'application

Frontend:
- UI de configuration des modèles avec affichage des états de compatibilité
- Suggestions dynamiques avec badges de compatibilité
- Messages d'aide contextuels (compatible/unknown/likelyTooRecent)
- Alertes non-bloquantes pour les modèles trop récents
- Gestion des échecs de catalogue avec saisie manuelle conservée

Backend:
- Ports CliVersionReader, ProviderModelCatalogue, CompatibilityMatrixSource
- Implémentations: ProcessCliVersionReader, HttpProviderModelCatalogue, EmbeddedCompatibilityMatrix
- Enrichissement des DTOs avec compatibility, cli_version, warnings
- Tests unitaires complets pour le resolver de catalogue
2026-07-26 16:09:10 +02:00
0821739924 feat: finalise ticket99 - implémentation agent model configuration v2
- agent/lifecycle.rs: lifecycle management per profile
- agent/provider_catalogue.rs: provider registration with model support
- agent/usecases.rs: usecases for profile-based agent invocation
- agent/mod.rs: expose agent capabilities via AgentManager
- backend/dto.rs: AgentModelConfig, AgentProviderConfig DTOs
- domain/profile.rs: extend Profile avec agent capabilities
- domain/permission.rs: permission checks pour agent access
- infrastructure/assistant/mod.rs: agent integration
- infrastructure/permission/{claude,codex}.rs: permission handlers
- web-server/lib.rs: agent endpoints
- commands.rs: agent commands
- frontend/adapters/{http,profile,mock,domain}.ts: adapters
- frontend/first-run/FirstRunWizard.{test.tsx,tsx}: first-run flow
2026-07-26 13:38:18 +02:00
dae07d35bb feat: implémentation et QA ticket99 - agent model configuration v2
- backend A-C: VO Codex/Claude, renderers/projecteurs modèle, SecretRef/env, catalogues/use cases/Tauri commands
- frontend D: profils Codex/Claude provider->model->secret, validations, conservation SecretRef
- fix: app-tauri embedded_server isolant IDEA_WEB_ROOT

QA: backend 57/57 tests, frontend 74/74 tests OK
2026-07-26 11:56:25 +02:00
13fb538880 fix(permissions): validate network access flow 2026-07-26 10:52:46 +02:00
3047dc9195 feat(permissions): expose network permission state (#103) 2026-07-25 23:06:50 +02:00
6e98fd89f7 fix(runtime): isolate agent state by project (#101) 2026-07-25 22:14:02 +02:00
ad491e765f fix(opencode): make models.dev providers cache-independent 2026-07-25 14:26:15 +02:00
0f0a76d806 fix(backend): exclusion mutuelle des backends OpenCode (llamacpp vs cloud) (#97)
Les builders `with_opencode` / `with_opencode_provider` s'évacuent
réciproquement (dernier appel gagnant) pour honorer l'invariant
`opencode_backend_is_consistent`. Le use case SaveOpenCodeProviderProfile
route désormais via le builder au lieu de muter le champ directement — c'est
ce qui dupliquait `opencode` + `opencodeProvider` et forçait un repli sur
llamacpp même quand l'utilisateur choisissait un provider cloud.

Défense en profondeur côté store :
- `read_doc` répare les profils corrompus sur disque (drop du stale `opencode`)
- `save` refuse de persister un profil violant l'invariant via le nouveau
  variant `StoreError::Invalid` (mappé vers `AppError::Invalid`)

Tests verts : builders last-wins (domain), save rejets + read repair
(infra, profile_store 10/10).

Refs #97
2026-07-24 19:52:34 +02:00
6e9a3ff657 fix(agent): timeout MCP OpenCode aligné sur le plafond du rendez-vous (#95)
Le timeout hardcoded 15000ms (15s) dans le bloc mcp.idea de l'opencode.json
généré par IdeA était far too short pour idea_ask_agent, qui bloque pendant
que l'agent cible travaille. OpenCode tuait la requête à 15s avec l'erreur
-32001 « Request timed out », même si la cible répondait correctement
(visible dans le workstate). Claude/Codex n'étaient pas affectés car leur
config MCP n'a pas de champ timeout.

Désormais le timeout est résolu par resolve_opencode_mcp_timeout_ms() :
- défaut 4h (14_400_000 ms), aligné sur DEFAULT_RENDEZVOUS_CEILING ;
- overridable via IDEA_OPENCODE_MCP_TIMEOUT_MS ;
- fallback sûr sur 0/parse-error (jamais d'expiration instantanée).

Les 4 occurrences (lifecycle.rs x2 + assistant/mod.rs x2) utilisent la même
fonction exportée depuis application::agent. Aucune modification des configs
MCP Claude/Codex.
2026-07-24 15:00:53 +02:00
56631bd3c8 fix(backend): projeter les EffectivePermissions dans le bloc permission d'opencode.json
Les 4 générateurs opencode.json/opencode_provider.json codaient en dur
{"bash":"ask","edit":"ask"}, ignorant les permissions configurées côté
IdeA pour l'agent. Claude et Codex appliquaient déjà PermissionProjector,
seul OpenCode passait à côté.

Ajoute domain::opencode_permission_block(eff: Option<&EffectivePermissions>)
qui mappe bash ← posture bash effective, edit ← posture Write effective
(Read/Delete non exprimables dans le schéma OpenCode, déjà enforcées par
le sandbox Landlock). eff == None omet la clé permission entièrement,
préservant le prompting natif OpenCode — même invariant que Claude/Codex.

Câble eff jusqu'aux 4 sites d'appel (lifecycle.rs + assistant/mod.rs,
variantes llamacpp et provider cloud). Le chemin ticket-assistant
(assistant/mod.rs) n'a pas de PermissionStore par agent pour l'instant,
donc eff y reste None (comportement inchangé, pas de régression).

Réf ticket #94.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-23 18:14:20 +02:00
0f57e7323a fix(backend): lecture du texte JSONL OpenCode niché sous part.text
Le parseur lisait value.text/value.content à la racine alors que
`opencode run --format json` niche le texte réel sous value.part.text
(cf. packages/opencode/src/cli/cmd/run.ts). Conséquence : idea_ask_agent
vers un profil OpenCode échouait systématiquement avec « OpenCode n'a
produit aucun final textuel » malgré une réponse CLI normale.

Ajoute aussi la gestion des événements type "error" (ParsedEvent::Error,
ReplyEvent::Error) pour distinguer un échec explicite d'un final vide,
et des tests de conformité sur le format JSONL réel confirmé.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-23 16:23:50 +02:00
557d1c3f24 fix(backend): sélection GGUF prioritaire au fichier fusionné sur les shards
Quand un repo HuggingFace héberge à la fois le fichier GGUF fusionné et
ses shards pour une même quantisation, select_gguf_file (tri alphabétique
naïf) pouvait retenir un shard partiel plutôt que le fichier fusionné ou
l'ensemble complet des shards, causant un échec immédiat au démarrage du
serveur llama.cpp (agent Context).

select_gguf_files renvoie désormais soit le fichier fusionné seul (priorité),
soit tous les shards correspondants triés par index — jamais un shard isolé.
Le téléchargement, le cache et la reprise gèrent le cas multi-fichiers
(manifest de shards, chemins locaux préservant le nom distant pour
l'autoload de llama.cpp).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-23 13:23:55 +02:00
e943a0efed feat(backend): catalogue de providers OpenCode dynamique + provider personnalisé (#92)
Le catalogue de providers OpenCode lit désormais le cache local
~/.cache/opencode/models.json pour refléter les providers réellement
disponibles, avec repli garanti sur le catalogue statique en cas
d'absence ou d'erreur de lecture du cache. Ajout d'un champ additif
`custom` sur OpenCodeProviderConfig pour permettre à l'utilisateur de
déclarer un provider hors catalogue (id + clé API en saisie libre).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-23 12:43:59 +02:00
23a3c2788f feat(backend): support des providers OpenCode cloud (#92)
Ajoute le catalogue statique de providers OpenCode (lot B3), le stockage
sécurisé des secrets (SecretStore + adapter infrastructure), et les
use cases SaveOpenCodeProviderProfile/DeleteProfile câblés en composition
root. Couvre le fix B1 et les tests de régression demandés par QA.

cargo build --workspace propre, cargo test --workspace -- --test-threads=1
intégralement vert.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-23 08:03:03 +02:00
bb35641715 feat(backend): système de plugins — domaine, application, infrastructure (#43)
Lots B1-B4 : modèle de domaine des plugins (manifeste, capacités menus/layouts/MCP),
port et registre applicatif, chargement/validation en infrastructure, exposition DTO
et commandes Tauri. Tests cargo verts.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-22 07:37:03 +02:00
ef84d5cc49 feat(backend): MCP d'édition de templates (#81)
Ajoute le MCP dédié à l'édition de templates : catalogue et classification
des templates (mcp/templates.rs infrastructure + app-tauri), use cases et
provider (application/template), enforcement de la policy des tools (mod.rs,
server.rs, tools.rs), avec la parité côté chemin OpenAI-compatible
(openai_tools.rs x2).

Lots B1 (catalogue/classification), B2 (use cases/provider) et B3
(enforcement policy) livrés en un seul commit cohérent.

QA vert (seul l'échec de bind loopback #80, connu et non-régression, écarté).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-20 18:45:02 +02:00
37ead61911 feat(backend): enforcement des permissions tools MCP au serveur (#82 lot B2)
orchestrator/mcp/server.rs applique désormais les règles de permission du
domaine mcp_tool_permissions (lot B1) à l'invocation d'un tool, y compris
le cas requester vide.

Lot B2 du ticket #82 : ferme la boucle enforcement sur le socle B1, la
parité OpenAI-compatible suit en B3 sur la même branche.

QA vert (32 tests dont le nouveau cas requester vide).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-18 22:54:42 +02:00
5175589aa5 feat(backend): domaine + catalogue et store durable des permissions tools MCP (#82 lot B1)
Introduit le domaine mcp_tool_permissions (règles de permission par tool
MCP) et étend le port de store correspondant. Le catalogue read/write des
tools MCP (orchestrator/mcp/tools.rs) s'appuie désormais sur ces règles, et
un store durable (mcp_tool_permission.rs) persiste les permissions au-delà
d'une session.

Lot B1 du ticket #82 : pose le socle domaine/store, l'enforcement suit en
B2 sur la même branche.

QA vert.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-18 22:45:32 +02:00
b4a34b40e5 fix(backend): identité requester explicite + policy des tools OpenAI-compatible (#62)
AgentSessionFactory::start propage désormais l'identité du requester aux
sessions structurées ; OpenTicketAssistant et LaunchAgent la portent
correctement de bout en bout. ToolPolicyRegistry est branché sur
AppOpenAiToolInvoker pour combler le trou de parité : TicketToolProvider
n'appliquait pas la policy des tools sur le chemin OpenAI-compatible,
contrairement au chemin structuré natif.

QA vert (échecs de bind loopback écartés comme non-régression préexistante,
tracés en #80).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-18 22:35:17 +02:00
8fe93d1652 feat(backend): appareils appairés persistants, révocables et code éphémère (#77 B1-B4)
L'appairage ne survivait pas au redémarrage et son code, permanent, était
imprimé sur la sortie standard. Un appareil appairé devient une entité
persistante, nommée et révocable, derrière un code désormais éphémère.

- B1 : port DeviceSessionStore et adapter FsDeviceSessionStore, entités de
  domaine (PairedDevice, DeviceId, SessionTokenHash, DeviceName). Les tokens
  sont hachés en SHA-256 et comparés en temps constant (subtle) : le store
  ne peut pas rejouer une session qu'il a servie. Cookie Max-Age 400 j à
  renouvellement glissant, lastSeenAtMs throttlé.
- B2 : code éphémère en mémoire, TTL 10 min et usage unique, toute
  génération invalidant la précédente. POST /api/pairing-code authentifiée,
  flag --new-code. Le code est retiré du boot et l'eprintln! qui l'imprimait
  est supprimé.
- B3 : endpoints devices (list/rename/revoke/revoke-all/logout), event
  DeviceRevoked et ActiveConnectionRegistry par device_id, fermant sans
  délai les WebSockets d'un appareil révoqué.
- B4 : port PairAttemptLimiter et adapter mémoire, rate-limit par origine et
  global sur horloge injectée, donc testable sans attente réelle.

La normalisation du code passe côté serveur : elle absorbe la dette #76, que
la seule normalisation frontend de #75 ne faisait que masquer.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-17 13:26:56 +02:00
ebad5ff9f2 Merge feature/ticket60-ticket-assistant-no-reply into develop (#60)
Rendre visible l'échec « aucune réponse » de l'assistant de ticket :
stream sans Final ou Final vide → ReplyChunk::Error terminal visible,
plus jamais de tour muet. Backend + frontend, tests verts.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-15 08:48:04 +02:00
f7cae4c0a8 fix(model-server): deadline de warmup configurable pour le cold-start llama.cpp (#55)
Corrige la régression high « Error on loading local model » : le premier chargement
du serveur modèle local (cold-start llama.cpp) dépassait la fenêtre de readiness et
échouait. Le warmup dispose désormais d'un deadline par défaut de 600 s, surchargable
par config optionnelle `warmup_deadline_secs` (validée dans [30, 1800]).

- domain: champ `warmup_deadline_secs: Option<u64>` + validation de borne
- application: policy de readiness effective (défaut 600 s, override par config)
- app-tauri: DTO `warmupDeadlineSecs`
- infrastructure: application de la deadline effective au warmup

Verdict QA (vert) : domain 252, application 81 + 22 model_server, app-tauri
dto_model_servers 6, infrastructure model_server 2, build OK. Contrat readiness
couvert sur ports mockés.
Caveat : le cold-start end-to-end réel (llama-server) sort du sandbox de test ->
vérification manuelle utilisateur restante, non couverte par les tests unitaires.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-15 08:41:44 +02:00
2f7f111545 fix(ticket-assistant): rendre visible l'échec « aucune réponse » de l'assistant de ticket (#60)
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>
2026-07-15 08:32:59 +02:00
62b71776f5 fix(background-task): découpler la détection de fin de tâche du drain output PTY (#2)
Le runner de tâches de fond détectait la fin d'un process via l'EOF du drain de
sortie PTY, couplant le cycle de vie du process au flux d'output. Un output
encore ouvert (ou drainé ailleurs) pouvait masquer ou retarder la détection de
fin.

Ajoute wait/try_wait au port figé PtyPort :
- wait : bloquant, rend un ExitStatus idempotent ;
- try_wait : non bloquant, rend Option<ExitStatus> ;
- exit status mémorisé pour garder wait/try_wait/kill cohérents.
Implémentation dans PortablePtyAdapter (état d'exit mémorisé). Le
CommandBackgroundRunner détecte désormais la fin via pty.wait (select sur
cancel/deadline) au lieu de l'EOF du drain. Tous les fakes PtyPort du workspace
sont complétés en conséquence.

Le tee live UI reste hors périmètre (traité en #58). Aucun breaking IPC/front.

Tests : infrastructure/tests/background_task_runner.rs (nouveau) + pty_adapter.rs
verts, non-régression application/app-tauri OK (hors échecs réseau du sandbox).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-14 23:42:40 +02:00
bd5d8d864a fix(tickets): matching exact du #ref et curseur de pagination opaque/stable pour ticket_list (#20)
Épurement de la dette de ticket_list sur deux axes :

Recherche texte — matching exact du numéro/#ref via parse_issue_search_ref,
court-circuité avant load_issue, sans matching par substring numérique
(« 1 » ne remonte plus « 12 », « 123 »…).

Pagination — curseur opaque et stable anchor-based au lieu d'un offset fragile :
token v1.<base64url-no-pad-json> encodant le tri + l'ancre {number, sortKey},
reprise strictement après l'ancre. Curseur legacy / invalide / de version
inconnue / avec sort divergent rejeté par une erreur explicite « Invalid
cursor ». Le DTO cursor reste String → non-breaking côté UI.

Fichiers : infrastructure/src/issues.rs, app-tauri/src/tickets.rs,
app-tauri/Cargo.toml (+ base64 0.22). Tests : issue_store_text_filter,
ticket_list_ 7/7 (anchor-based + rejets).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-14 19:20:40 +02:00
2183dfd291 feat(model-server): progression fine du téléchargement du modèle llamacpp (#54)
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>
2026-07-14 10:37:14 +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
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
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
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
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
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
aab4bcafb6 feat(session): adapter HTTP OpenAI-compatible pour profils locaux/LAN (#14)
Ajoute un adapter de session HTTP OpenAI-compatible, purement additif,
permettant d'intégrer des modèles locaux/LAN comme profils IdeA canoniques
avec parité tool-calling/MCP.

- domain: extension du profil et des ports pour l'adapter OpenAI-compatible
- infrastructure: adapter openai_compat + routage factory
- app-tauri: mapping des outils OpenAI (openai_tools) + wiring state/lib
- application: catalogue d'agents + tests de use-cases profils

Validé QA (backend GO): round-trip byte-identique Claude/Codex, mapping
erreurs, dégradation tools, conversation_id None, conformance un seul Final,
routage factory. Suites vertes domain 467 / application 530 /
infrastructure 523 / app-tauri 247, 0 échec.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-07 22:09:16 +02:00
e523f44425 feat(tickets): tri de la liste de tickets côté backend (#21)
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>
2026-07-07 11:45:59 +02:00
feeca3462c feat(tickets): filtres multi-critères par cases à cocher (backend + frontend)
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>
2026-07-06 06:41:01 +02:00
5417bd756b feat(tickets): suppression d'un ticket (backend + frontend)
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>
2026-07-06 06:27:09 +02:00
1fdf62c089 feat(tickets): création d'un assistant IA de ticket (backend + frontend)
Ajoute le chat assistant IA attaché à un ticket (#8).

Backend Rust :
- use cases OpenTicketAssistant/CloseTicketAssistant + tests
- politique d'outils par agent (domain/agent_tool_policy) et policy MCP
- store de contexte assistant + gabarit default_ticket_assistant.md + tests
- events TicketAssistantOpened/Closed
- commandes Tauri open_ticket_chat/close_ticket_chat et câblage state/lib/events

Frontend :
- gateway (ports, adapters ticket + mock, domain)
- hook useTicketAssistant + composant TicketAssistantPanel
- intégration dans TicketDetail

Tests verts : vitest tickets.test.tsx (23), cargo test application::ticket_assistant (1),
infrastructure::assistant_context_store (2).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-06 06:06:24 +02:00
48b652ff91 feat(sprints): modèle de sprints — domaine, use-cases, persistance et surfaces (backend)
Ticket #10 — introduction du modèle de sprints côté backend.

- Domaine : nouvel agrégat Sprint (sprint.rs), IDs, événements et invariants ;
  rattachement des issues à un sprint (issue.rs) et ports associés.
- Application : use-cases sprints (application/src/sprints) + erreurs dédiées.
- Infrastructure : store de sprints (infrastructure/src/sprints.rs), adaptation
  du store d'issues et exposition MCP via orchestrator/mcp/tickets.rs.
- app-tauri : commandes, state et events pour piloter les sprints depuis l'UI.

Tests domaine/application/infra/app-tauri verts (sprint_usecases, sprint_store,
issue_store, mcp_server).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-05 10:57:33 +02:00
aa5a4f30ae feat(inter-agent): backend des annonces live d'agent (B0-B3)
Redémarre le ticket #4 sur la base develop. Émission d'annonces live d'un
agent vers l'UI, distinctes du Final de délégation :

- domain: ReplyEvent::Announcement/Final et DomainEvent::AgentAnnouncement
  (events.rs), port d'émission (ports.rs), gating de readiness (readiness.rs).
- application: mapping des événements structurés en annonces
  (agent/structured.rs, agent/mod.rs, lib.rs) et relais côté orchestrateur
  (orchestrator/service.rs).
- infrastructure/session: parse des annonces + fix du Final pour Claude et
  Codex, propagé aux adaptateurs et à la conformance
  (claude.rs, codex.rs, conformance.rs, mod.rs, process.rs, sandbox_e2e.rs).
- app-tauri: relais Tauri des annonces vers le front (events.rs, chat.rs).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-04 19:50:03 +02:00
eb9cc16181 feat(background): livraison auto au propriétaire + projection des tâches de fond dans le work-state (T1+T3)
T1 — Wake automatique du propriétaire à la complétion.
La complétion d'une tâche de fond est désormais livrée à l'agent
propriétaire dès que la session accepte l'envoi (wake.rs :
mark_completion_delivered au send accepté), via un drain de flux dédié
(structured.rs : drain_reply_stream_with_readiness). L'inbox médiée
enfile l'item sans démarrer de tour ni marquer l'agent busy
(input/mod.rs : enqueue FIFO silencieux). Régression couverte
(tests/agent_wake.rs, tests input/mod.rs).

T3 — Tâches de fond projetées dans le read-model du panneau Work.
AgentWorkState porte désormais background_tasks
(VO AgentBackgroundTaskState), alimenté par un builder best-effort
with_background_tasks(store) : union list_open_for_agent + dispatch des
completions non livrées par owner_agent_id, erreur store => Vec vide
(aucune régression live/busy/tickets). DTO Tauri backgroundTasks et
wiring du BackgroundTaskStore côté state.rs. Le frontend, déjà câblé,
affiche Cancel/Retry (mapping queued/waiting -> pending, tri sur
updatedAtMs). Borne V1 : une tâche terminale déjà livrée n'est plus
énumérable (Retry limité à la fenêtre non livrée).

Tests : cargo build --workspace OK ; cargo test -p application /
-p app-tauri / -p infrastructure verts ; frontend build + vitest verts.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-04 00:21:33 +02:00
f08dae62eb feat(background): déclencheur in-app des tâches de fond via MCP idea_run_in_background (BE-1+BE-2)
Ferme la boucle B8 côté surface agent : un agent peut lancer une commande
en tâche de fond depuis l'app, sans dépendance à un déclencheur externe.

- domain : variante OrchestratorCommand::RunInBackground.
- infrastructure : outil MCP idea_run_in_background (déclaration + schéma +
  map_tool_call), tests de mapping et compteur de catalogue.
- application : handler → SpawnBackgroundCommand (owner=requester, WakeOwner).
- app-tauri : câblage .with_spawn_background_command + catalogue MCP 23→24.

Tests verts : domain 452 / application 467 / infrastructure 489 /
app-tauri 236, build --release vert.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-03 22:44:48 +02:00
41278bd632 Merge branch 'feature/issue-ticket-system' into feature/background-tasks-first-class
Intègre le système de tickets/issues V1 (validé QA vert de bout en bout,
mémoire tickets-v1-e2e-validated-qa) dans la branche des tâches de fond.
Conflits résolus : app-tauri/state.rs, domain/events.rs, domain/lib.rs, domain/ports.rs.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-03 15:15:43 +02:00
8cac1470ac feat(background): runner PTY B8 + boucle sink fermée + refactor point-2
Livre le lot backend B8 des tâches de fond :

- infrastructure : runner de commandes concret (CommandBackgroundRunner)
  sur le port BackgroundTaskRunner, tail borné (bounded_tail/BoundedTail),
  éclatement du module background_task en sous-modules (mod/runner/tail,
  sink extrait de l'ancien background_task.rs).
- application : nouveau module background exposant les cas d'usage
  SpawnBackgroundCommand, CancelBackgroundTask, RetryBackgroundTask et le
  port BackgroundCommandArchive.
- domain : refactor point-2 de l'arbitrage Architect — sortie du trait
  BackgroundCommandArchive de la couche domaine vers application.
- app-tauri : câblage runtime (commands, dto, state, lib) des commandes
  spawn/cancel/retry et de la boucle de complétion sink fermée en
  composition root.

Build workspace + tests application/infrastructure verts (QA).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-03 14:48:46 +02:00
8de7be01a8 feat(tickets): checkpoint backend V1 du système de tickets (T1-T5)
Checkpoint de travail — QA formelle encore à venir (après reset Codex).
`cargo build` workspace OK, tests ticket/issue verts (domaine, store,
use cases, app-tauri 47/51). Le domaine s'appelle `Issue`, exposé
« ticket » côté MCP/UI.

- T1 domaine : entité Issue (statut, priorité, liens, carnet),
  events, ids, ports.
- T2 infra : store FS Markdown + allocator de références #N.
- T3 application : use cases Issue (create/read/list/update/status/
  priority/carnet/link/unlink/assign) + erreurs dédiées.
- T4 surface MCP : 10 outils publics idea_ticket_* (23 outils au
  total), mappés vers les use cases Issue.
- T5 app-tauri : commandes Tauri ticket_* + DTOs d'events Issue +
  câblage state.rs.

Dette de test PRÉ-EXISTANTE héritée de develop (4 tests app-tauri
mcp_e2e_loopback / mcp_serve_peer rouges) hors périmètre tickets,
non traitée ici.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-02 22:34:04 +02:00
c537da54ef feat(infrastructure): store, sink de complétion et mailbox des tâches de fond (B2-B4)
Adapters de persistance des BackgroundTask (store), sink de récupération
de complétion post-tour et boîte de réception (mailbox) pour les messages
concurrents, câblés sur l'entrée. Couvert par background_task_store,
background_completion_sink, agent_inbox et orchestrator_watcher (verts).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-02 15:47:28 +02:00
62915eec4d fix(codex): dernier agent_message = Final (bootstrap canal)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-02 14:49:00 +02:00
a9653bc417 fix(orchestrator): délégation inter-agent toujours headless, jamais d'injection PTY
La conversation inter-agent (idea_ask_agent) doit rester strictement
headless : la cible répond via une session structured capturée par IdeA,
sans jamais écrire dans le PTY d'une cellule visible ni fermer le terminal
que l'utilisateur observe.

- lifecycle: flag `allow_structured_alongside_pty` — ouvre une session
  structured pour la délégation sans fermer le PTY visible (coexistence).
- orchestrator/service: `ensure_structured_session` ne ferme plus le PTY
  visible ; mapping typé de l'erreur no-reply ; coexistence PTY/structured.
- infrastructure/input: garantit zéro `DelegationReady` et zéro write PTY
  pour une délégation headless, même quand l'entrée est `front_owned`.
- app-tauri (commands/state): câblage du flag de coexistence.
- tests: fixtures portées vers le modèle structured/headless, assertions
  cibles mises à jour (aucun #[ignore] ajouté, aucun test retiré).

Validé réel : cargo build OK ; orchestrator_service 60/0, agent_lifecycle
62/0, structured_launch_d3 22/0, infrastructure input 35/0.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-02 10:22:06 +02:00
1fc7869160 agent conversation fix 2026-06-27 12:42:37 +02:00