Commit Graph

19 Commits

Author SHA1 Message Date
171c6c923c feat(wave): #119/#122/#131/#132 verts + sprint plugins ESM/persistance #135/#136/#139
É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>
2026-08-03 11:06:23 +02:00
92b17e9a69 feat(skills): capacités agent découvrables via idea_list_agents
Ajoute SkillKind (Workflow/Reference) sur Skill, extrait le use case
ResolveAgentCapabilities à partir des SkillRef assignés, et enrichit
idea_list_agents d'un champ additif capabilities (name, description,
kind) — remplace l'exposition de SkillRef opaques par un inventaire de
capacités interrogeable, source commune avec le bloc « Skills
disponibles » injecté au lancement (#119).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-01 00:26:56 +02:00
b55d12d035 test(tickets): renforce la couverture attachments web-server/app-tauri (#108)
Levée de la réserve QA sur #108 : aucun test ciblé ne matchait réellement
sur web-server et app-tauri malgré le câblage attachments tickets.

- web-server: test fonctionnel via /api/invoke pour ticket_create,
  ticket_attachment_add, ticket_attachment_read,
  ticket_attachment_mark_summarized.
- app-tauri: test fonctionnel via la surface publique tool/provider pour
  idea_ticket_create, idea_ticket_attachment_add,
  idea_ticket_attachment_read, idea_ticket_attachment_mark_summarized.

Pas de changement de wiring produit ; assertions alignées sur le contrat
public réel (contentBase64 sans padding =, summarizedBy.kind = user côté
app-tauri).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-29 11:17:05 +02:00
8158057b1d feat(tickets): ajoute les pièces jointes sur tickets (#108)
Stockage flat côté ticket + métadonnées d'attachments, lecture exposée côté
backend/MCP, et UI minimale de liste/ajout dans TicketDetail. Traverse le
domaine (Issue, ports), l'application (usecases + assistant de ticket), les
adaptateurs infra/MCP (issues store, orchestrateur), les DTO backend/web-
server/app-tauri, et le frontend (domain/ports/adapters/hooks/UI).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-29 11:08:45 +02:00
045e0984cc chantier: durcissement reprise headless inter-projets + persistance profils Opencode
- Implémentation reprise de session Opencode headless (conversational_recovery)
- Persistance des profils IA Opencode dans .ideai/memory avec JSON Schema
- Gestion des permissions MCP pour agents externes
- Tests QA verts : structured_launch_d3, conversation_log, tickets_missing_carnet, agents, ProfilesSettings
2026-07-28 12:23:34 +02:00
0b83b5bbd2 feat(lock): implémentation lock inter-process app-data-dir V1 — acquisition non-bloquante avec RAII 2026-07-27 13:57:58 +02:00
038e90ecec feat: livrable ticket #91 — notification fin BackgroundTask enrichie
- Backend: enrichissement HeadlessRendezvous avec requester/target/conversationId
- Frontend: toast 'Requester -> Target completed/...' explicite
- Clic ouvrant viewer de conversation pour visualiser l'échange
2026-07-27 09:05:34 +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
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
678ff3011b feat(web-server): élargir l'allowlist /api/invoke pour les menus Panneaux
Permet aux commandes Tauri des menus manquants (#90) d'être invoquées
depuis la version web via le proxy /api/invoke.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-21 18:31:58 +02:00
5a7431b442 feat(backend): commandes web tickets/sprints + factorisation DTO (#86 lot 1)
Expose les commandes tickets/sprints sur le transport web (web-server/lib.rs),
avec factorisation des DTO tickets partagés entre Tauri et web dans un
nouveau module backend/src/ticket_dto.rs (app-tauri/src/tickets.rs
consomme désormais ce module commun).

Lot 1 du ticket #86, backend/web-server. Le lot 2 (frontend) suit sur une
nouvelle branche depuis develop à jour.

QA vert.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-21 07:20:39 +02:00
2db37a50fa chore(fmt): reformatage cargo fmt résiduel
Deux reformatages sans changement de comportement (device.rs, web-server/lib.rs),
laissés de côté hors périmètre au fil de plusieurs tickets précédents.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-18 23:15:39 +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
75d1ce87fc feat(web-server): donner un effet réel à la confiance reverse proxy + fix port CLI (#72)
`--trust-reverse-proxy` était un drapeau creux : il n'était lu que dans
`ServerConfig::validate()` pour exiger sa propre présence. Le serveur n'a jamais
vérifié qui se connectait ni ce que le proxy annonçait. Ce lot lui donne un
effet.

- `trusted_proxies: Vec<TrustedProxy>` dans `ServerConfig` + `--trusted-proxy`
  (répétable, IP ou CIDR v4/v6). `validate()` refuse désormais au démarrage un
  bind non-loopback en mode remote sans au moins un proxy autorisé.
- Guard runtime sur les trois surfaces (statique, `/api/*`, `/api/ws`) : le
  `peer_addr` réel est vérifié AVANT toute confiance accordée aux headers. Sur
  bind loopback, seul un pair loopback est accepté ; sinon le pair doit tomber
  dans un `--trusted-proxy`.
- `X-Forwarded-Proto: https` obligatoire en mode proxy, avec un message de refus
  actionnable (la commande nginx exacte à ajouter).
- `X-Forwarded-For` n'autorise jamais rien : il n'est que journalisé. Un header
  ne donne aucun droit, seul le pair TCP en donne.
- Diagnostics : `UntrustedProxyPeer`, `ForwardedProtoRejected`,
  `ForwardedHostMismatch`.

B0 — même bug de port que celui corrigé dans #68 B1, sur le chemin CLI cette
fois : `run_server` construisait son `ServerState` AVANT le bind, donc
`idea-serve --listen 127.0.0.1:0` comparait l'origine à `http://127.0.0.1:0` et
rejetait tout en 403. La réconciliation du port effectif est factorisée dans
`config_with_effective_listen`, partagée avec le chemin embarqué.

`X-Forwarded-Host` ne provoque PAS de rejet : Architect l'a jugé redondant avec
la vérification stricte d'`Origin`, et il cassait nginx en configuration par
défaut. Il reste un warning de diagnostic. La vérification d'accès stricte
demeure l'égalité d'`Origin` contre `--public-origin`.

CHANGEMENT DE COMPORTEMENT ASSUMÉ — ce lot casse volontairement les
configurations existantes : un bind non-loopback distant sans `--trusted-proxy`
est désormais refusé au démarrage. C'est le prix d'un drapeau qui ne mentait
plus. Le message d'erreur dit quoi ajouter.

Origine du ticket : #72 est né d'une trouvaille de l'agent Git à la revue de la
doc de #65 — c'est en vérifiant une phrase de sécurité qu'il a établi que
`--trust-reverse-proxy` n'avait aucun effet runtime.

QA ré-exécutée par Git HORS SANDBOX avant merge (DevBackend et QA sont tous deux
bloqués par EPERM sur `TcpListener::bind` ; un vert sandboxé ne vaut rien ici, on
s'est déjà fait avoir sur #68 B1) : `cargo test -p web-server` 66 passed, 0
échec · `-p backend` · `-p app-tauri` verts.

Revue de sécurité par Git : guard câblé sur les 3 routes, chemin de production
propageant toujours le vrai `peer_addr` (le repli `listen.ip()` est
`#[cfg(test)]`, inatteignable en production), CIDR correct y compris `prefix 0`.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-16 23:10:40 +02:00
b7d38f1d30 feat(web-server): seam shared-core run_embedded_with_core + fix du port effectif (#68 B1)
Ouvre le point d'intégration du serveur embarqué desktop : `run_embedded_with_core`
reçoit un `Arc<BackendCore>` déjà construit, pour que l'adapter HTTP partage le
composition root de l'adapter Tauri au lieu d'en bâtir un second dans le même
processus. `ServerState` porte désormais `Arc<BackendCore>` ; `run_embedded` est
conservé en compat et délègue en construisant son propre core.

Corrige au passage un vrai bug produit, découvert en rejouant les tests hors
sandbox : `run_embedded` ne réconciliait pas le port effectif avec la config. Sur
un bind éphémère (`127.0.0.1:0`), l'état du serveur gardait `listen` à port 0,
donc `origin_allowed` comparait l'Origin entrante à `http://127.0.0.1:0` et le
serveur embarqué rejetait **toutes** les requêtes API en 403. La config reçoit
maintenant `local_addr` lu sur le listener **avant** la construction du state.

Comble le trou signalé au merge de #65 : `run_embedded().stop()` est enfin
couvert.

ATTENTION — le premier « 57 passed » de ce lot était un FAUX VERT. Le sandbox
d'exécution interdit `TcpListener::bind` ; les tests sortaient en silence sur
EPERM, dont précisément le test `stop()`. Les replis EPERM sont supprimés : un
bind refusé fait désormais échouer le test au lieu de le peindre en vert.

QA ré-exécutée par Git HORS SANDBOX avant merge (sinon on reproduit le faux
vert) : `cargo test -p web-server` 57 passed, 0 échec, avec
`run_embedded_stop_shuts_down_accept_loop` et
`run_embedded_with_core_uses_injected_core_for_http_invokes` réellement exécutés
sur le vrai chemin réseau. `-p backend` 41 · `-p app-tauri` 35, 0 échec.

DETTE CONNUE, tracée en #72 B0 : le chemin CLI standalone `run_server` garde la
même hypothèse fausse — il reçoit un `ServerState` construit AVANT le bind, donc
`idea-serve --listen 127.0.0.1:0` reste cassé à l'identique.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-16 18:50:18 +02:00
0e15482ce2 feat(web-server): extraire le serveur headless idea-serve du binaire Tauri (#65)
Sort le serveur HTTP/WS de `app-tauri` vers un crate `web-server` autonome,
exposant le binaire `idea-serve` qui sert le client web sans aucune dépendance
GUI. Le cœur (use cases, DTO, events) devient partagé entre deux driving
adapters : le desktop Tauri et le serveur headless.

Structure :
- `crates/web-server` : lib + bin `idea-serve`, consomme `backend::{dto, events}`.
- `crates/backend` : `dto.rs` et `events.rs` deviennent le propriétaire canonique
  des DTO/events transport-neutres (arbitrage Architect : pas de crate contrat
  dédié, `backend` est déjà le composition root transport-neutre).
- `crates/app-tauri` : `dto.rs` réduit à un shim de ré-export, `events.rs` réduit
  au relais Tauri (souscription au bus + emit), `server.rs` vidé au profit du
  crate partagé.
- `Cargo.toml`/`Cargo.lock` : `web-server` ajouté aux membres du workspace.

Frontière respectée : les DTO de `backend` ne tirent ni Tauri, ni HTTP/WS, ni
Axum/Hyper, ni UI ; `domain`/`application` n'en dépendent pas. Le frontend est
inchangé (`git diff 506d589...HEAD -- frontend` vide).

`web_server::run_embedded(...)` est le point d'extension prévu pour #68 (le
desktop consommera `web-server` comme lib plutôt que d'en forker le serveur).

QA (exécution réelle, re-vérifiée avant merge) :
- `cargo test -p backend` 41 passed · `-p web-server` 55 passed · `-p app-tauri`
  35 passed, 0 échec.
- Invariant headless : `ldd target/debug/idea-serve` ne tire aucun
  webkit/javascriptcore/gtk/gdk/soup/tauri/wry, là où `app-tauri` les tire bien.
- Validation live utilisateur : `idea-serve` démarre, sert le SPA, le contrôle
  d'origine strict tient, accès distant OK via reverse proxy.
- Les 10 échecs `openai_compat` de `cargo test --workspace` sont préexistants sur
  `506d589` (bind réseau interdit par la sandbox), hors périmètre.

Squash de `82e8e77` (commit de sûreté « état intermédiaire non figé », qui
rapatriait le travail réalisé par erreur sur la branche de #69) et de `ddbea7b`
(déduplication des DTO events, comblant l'écart annoncé par le premier). Les deux
n'avaient de sens qu'ensemble : ce commit fige le contrat que le premier laissait
explicitement ouvert. Arbre identique bit pour bit à `ddbea7b` ; historique
d'origine conservé sur `backup/ticket65-pre-squash-ddbea7b`.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-16 15:01:18 +02:00