Merge feature/ticket65-idea-serve-headless into develop (#65)

Intègre le serveur headless `idea-serve` : le cœur (use cases, DTO, events)
devient partagé entre deux driving adapters, le desktop Tauri et le crate
`web-server` autonome, sans dépendance GUI.

Vert avant merge : `cargo test -p backend` 41 · `-p web-server` 55 ·
`-p app-tauri` 35, 0 échec, ré-exécuté sur la branche. Invariant headless
vérifié (`ldd idea-serve` sans webkit/gtk/tauri) et validation live utilisateur
du serveur (démarrage, SPA servi, contrôle d'origine strict, accès distant).

Débloque #68 (activer le serveur depuis le desktop, via `run_embedded`) et #66
(Docker).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-16 15:02:28 +02:00
38 changed files with 9680 additions and 8894 deletions

3
.gitignore vendored
View File

@ -9,6 +9,9 @@ target/
# Dependencies and build output (package-lock.json IS committed).
frontend/node_modules/
frontend/dist/
# Sortie du build web (VITE_TRANSPORT=http) servie par idea-serve : meme
# classe que dist/, rebuildable depuis les sources — not versioned (#65).
frontend/dist-web/
# Root-level node_modules (dev tooling installs at repo root — never versioned).
/node_modules/
# npm/yarn/pnpm debug logs

File diff suppressed because one or more lines are too long

View File

@ -62,3 +62,4 @@
- [ticket13-f5-web-live-surfaces-delivered](ticket13-f5-web-live-surfaces-delivered.md) — Les surfaces live web (workstate live via event.domain, background tasks cancel/retry, inbox, re-synchro au reconnect) du chantier client/serveur #13 sont livrées et vertes.
- [frontend-uses-npm-not-pnpm](frontend-uses-npm-not-pnpm.md) — memory note frontend-uses-npm-not-pnpm
- [idea-distribution-strategy-desktop-vs-docker](idea-distribution-strategy-desktop-vs-docker.md) — memory note idea-distribution-strategy-desktop-vs-docker
- [web-client-is-single-column-no-desktop-shell](web-client-is-single-column-no-desktop-shell.md) — memory note web-client-is-single-column-no-desktop-shell

View File

@ -0,0 +1,44 @@
---
name: web-client-is-single-column-no-desktop-shell
description: memory note web-client-is-single-column-no-desktop-shell
metadata:
type: project
---
# Le client web n'a pas de shell desktop (ni docks, ni layout grid)
Constat établi en livrant le ticket #69 (adaptibilité téléphone), sur `develop @ 506d589`.
## Le fait
Le client web livré par #13 (`VITE_TRANSPORT=http`) **n'a jamais eu** de docks
gauche/droite, de fenêtres flottantes, de `LayoutTree`, de tabs projet, de menus ni
de toasts. `main.tsx` route `isWeb` vers `WebApp`, qui est une surface autonome :
- `WebApp``PairingScreen` **ou** `WebWorkspace` (rien d'autre) ;
- `WebWorkspace` → une **colonne verticale unique** (`flex flex-col overflow-y-auto`) ;
- `WebAgentCell``TerminalView`.
Les seuls imports `@/features/*` de tout `features/web/` sont `terminals` et
`workstate/useProjectWorkState`. Le shell desktop (`App`, layout, docks) n'est
atteignable que par la branche non-web de `main.tsx`.
## Pourquoi ça compte
Le cadrage de #69 prévoyait un lot « remplacer les docks gauche/droite/floating par
une pile verticale, drawer ou bottom sheet ». Ce lot était **sans objet** : il n'y a
pas de dock à remplacer, et l'arbitrage produit « bottom sheet vs drawer » ne se pose
pas sur cette surface. Le vrai travail téléphone était ailleurs (terminal xterm
pilotable au doigt, `dvh`, safe-area, rangées qui débordent à 360px).
**Avant de cadrer un ticket « responsive / mobile » sur le client web, partir de
`features/web/`, pas du shell desktop.** Les deux surfaces ne partagent que
`TerminalView` et les hooks transport-neutres.
## Garde en place
`frontend/src/features/web/WebMobile.test.tsx` épingle la frontière : le client web
ne doit monter aucun `layout-grid` / `layout-grid-container` / `layout-split` /
`layout-tabs`. Si un jour on veut du desktop-shell dans le web, ce test tombe — et
c'est le signal qu'il faut re-cadrer, pas le supprimer.
Voir aussi [[ui-rework-sprint-scoping-contracts]].

View File

@ -1,8 +1,8 @@
---
issueRef: "#13"
version: 18
version: 19
updatedBy: {"kind":"agent","agent_id":"a6ced819-b893-4213-b003-9e9dc79b9641"}
updatedAt: 1784184002362
updatedAt: 1784193634690
---
# Ticket #13 — Server/client mode (carnet de chantier)

View File

@ -2,7 +2,7 @@
id: "036783fa-9856-4643-8c28-653b93ac36e1"
number: 13
title: "Server/client mode"
status: "inProgress"
status: "closed"
priority: "low"
sprint: "028179b1-eaf4-41e9-9c1f-7c37125117e6"
links: []
@ -10,7 +10,7 @@ agentRefs: [{"agentId":"a6ced819-b893-4213-b003-9e9dc79b9641","role":"assigned"}
createdBy: {"kind":"user"}
updatedBy: {"kind":"agent","agent_id":"a6ced819-b893-4213-b003-9e9dc79b9641"}
createdAt: 1783184188272
updatedAt: 1784184002362
version: 18
updatedAt: 1784193634690
version: 19
---
J'aimerais pouvoir utiliser IdeA sous forme de client/server. C'est a dire que IdeA aurait son backend sur une machine et son interface qui serait un frontend web. Les agents etc seraient tous côté server. C'est a dire que la cli de Claude serait celle côté serveur, l'interface client ne serait que l'affichage frontend, une UI. Je pense que tout est faisable, il faudrait cependant parler du côté CLI. Est ce qu'il serait possible de garde rle CLI natif comme il est actuellement, de l'afficher côté client tout en gardant l'installation claude code, codex etc côté serveur ? Peut etre qu'en ssh ça passerait ? Ce ticket ne pourra pas être fait en autonomie par un agent sans une review agent-utilisateur avant.

View File

@ -1,6 +1,6 @@
---
issueRef: "#60"
version: 2
updatedBy: {"kind":"agent","agent_id":"a6ced819-b893-4213-b003-9e9dc79b9641"}
updatedAt: 1784095176619
version: 3
updatedBy: {"kind":"user"}
updatedAt: 1784194089605
---

View File

@ -4,14 +4,14 @@ number: 60
title: "[Bug] Assistant IA d'édition de ticket : aucune réponse dans la conversation (stream sans Final non signalé)"
status: "inProgress"
priority: "high"
sprint: null
sprint: "e28a4d53-8bd2-446a-b0ac-2a017373b8b2"
links: [{"target":"#25","kind":"relatesTo"},{"target":"#27","kind":"relatesTo"}]
agentRefs: []
createdBy: {"kind":"agent","agent_id":"a6ced819-b893-4213-b003-9e9dc79b9641"}
updatedBy: {"kind":"agent","agent_id":"a6ced819-b893-4213-b003-9e9dc79b9641"}
updatedBy: {"kind":"user"}
createdAt: 1784094260499
updatedAt: 1784095176619
version: 2
updatedAt: 1784194089605
version: 3
---
Rapporté par l'utilisateur (2026-07-15) : dans l'édition d'un ticket, le bouton « Assistant IA » ouvre une conversation, mais l'envoi d'un message ne produit JAMAIS de réponse visible — la conversation reste muette. PROFIL UTILISÉ : modèle local OpenAI-compatible (llamacpp).

View File

@ -1,6 +1,6 @@
---
issueRef: "#64"
version: 2
version: 5
updatedBy: {"kind":"agent","agent_id":"a6ced819-b893-4213-b003-9e9dc79b9641"}
updatedAt: 1784187610934
updatedAt: 1784193766706
---

View File

@ -4,14 +4,14 @@ number: 64
title: "Web : créer/ajouter un projet depuis le navigateur (folder browser serveur)"
status: "open"
priority: "medium"
sprint: null
links: [{"target":"#13","kind":"dependsOn"},{"target":"#66","kind":"dependsOn"}]
sprint: "028179b1-eaf4-41e9-9c1f-7c37125117e6"
links: [{"target":"#13","kind":"dependsOn"}]
agentRefs: []
createdBy: {"kind":"agent","agent_id":"a6ced819-b893-4213-b003-9e9dc79b9641"}
updatedBy: {"kind":"agent","agent_id":"a6ced819-b893-4213-b003-9e9dc79b9641"}
createdAt: 1784183727404
updatedAt: 1784187610934
version: 2
updatedAt: 1784193766706
version: 5
---
Issu de la validation live de #13 (mode client/serveur web). En web, le bouton « Browse » (choisir un dossier de projet) est inopérant : `pickFolder()` renvoie `UNSUPPORTED_ON_WEB` car il s'appuie sur le dialogue natif OS de Tauri, absent du navigateur. Sélectionner un projet EXISTANT est déjà couvert par la liste (list_projects/open_project). Il manque CRÉER/AJOUTER un projet = choisir un dossier côté SERVEUR.

View File

@ -1,6 +1,46 @@
---
issueRef: "#65"
version: 1
version: 6
updatedBy: {"kind":"agent","agent_id":"a6ced819-b893-4213-b003-9e9dc79b9641"}
updatedAt: 1784187583229
updatedAt: 1784202758668
---
# Ticket #65 — Serveur headless `idea-serve` (carnet de chantier)
Statut : **QA — en attente de validation live utilisateur (non-régression desktop)**.
Branche : `feature/ticket65-idea-serve-headless` (base `develop` @ `506d589`). Local, aucune action sortante.
## Arbitrages Architect (tranchés)
- **DTO/events → propriétaire canonique = crate `backend`.** PAS de crate `presentation-dto`/`backend-api` : `backend` est déjà le composition root transport-neutre et la façade des use cases pour adapters entrants. `web-server` ET `app-tauri` le consomment ⇒ contrat canonique partagé entre deux driving adapters.
- **Frontière** : les DTO dans `backend` ne tirent NI Tauri, NI HTTP/WS/cookies, NI Axum/Hyper, NI UI. `domain`/`application` ne dépendent PAS des DTO. Vérifié QA.
- **Dédup events = dans L1, pas en dette** (sinon deux sources de vérité au moment où #65 stabilise le contrat). Dette acceptable uniquement pour le Tauri-spécifique (relay `app_handle.emit`, wiring runtime).
## Structure cible (livrée)
- `crates/backend/src/dto.rs` + `crates/backend/src/events.rs` ; `lib.rs` expose `pub mod dto; pub mod events;`
- `app-tauri/src/dto.rs` = shim `pub use backend::dto::*;`
- `app-tauri/src/events.rs` = relay Tauri uniquement, DTO importés de `backend::events`.
- `web-server` consomme `backend::{dto, events}`.
## Livré — L1/L2/L3 + run_embedded
Commits : `82e8e77` (wip de sûreté, ne fige rien) · `ddbea7b` (dédup DTO events).
`web_server::run_embedded(...)` présent : `ServerConfig`, `EmbeddedServerHandle`, `url()`, `pairing_code()`, `state()`, `stop()`, shutdown via `oneshot`. **C'est le point d'extension qui prépare #68** (le desktop consommera `web-server` comme lib, pas de fork).
## Vérif QA (exécution réelle) — VERT
- `cargo build -p web-server --bin idea-serve` + `-p app-tauri --bin app-tauri` : OK.
- `cargo test -p backend` 41 passed · `-p web-server` 55 passed · `-p app-tauri` 35 passed.
- **Invariant clé** : `ldd target/debug/idea-serve | rg -i 'webkit|javascriptcore|gtk|gdk|soup|tauri|wry'`**aucune sortie**. Comparatif `app-tauri` tire bien libwebkit2gtk/libgtk/libsoup/libjavascriptcore.
- Contrat HTTP/WS inchangé (55 tests web-server : pair/invoke/logout/ws/static/allowlist/B8). `git diff --name-only 506d589...HEAD -- frontend`**vide**.
## Faux mystère élucidé (à ne pas refaire paniquer)
`cargo test -p app-tauri` est passé de **45 → 35** : les tests ne sont PAS perdus, ils ont MIGRÉ. Écart réel depuis develop = **68 tests déplacés** (`src/lib.rs` : 104 → 36) : 55 `server::tests::*``web-server`, 10 `events::tests::*``backend::events`, 3 `dto::ls6_pagination_tests::*``backend::dto`. Vérifié par `cargo test -p app-tauri -- --list` comparé sur `506d589`.
## Faux négatif connu (arbitré NON bloquant)
`cargo test --workspace` : 10 échecs `infrastructure::session::openai_compat::*` + `factory_routes_openai_compatible_to_http_session` sur `bind: Os { code: 1, kind: PermissionDenied }` = la sandbox interdit l'écoute réseau. **Confirmé préexistant sur `506d589`** (même liste). Validation retenue par crates ciblés.
## Réserve QA restante
Aucun test dédié à `run_embedded().stop()` (un test de bind réel serait soumis à la même restriction sandbox). À couvrir dans #68, qui consommera ce handle.
## Incident de topologie (résolu — leçon)
DevBackend a d'abord travaillé sur la branche de #69 sans committer. Git a rapatrié le diff Rust (stash `-u` limité à `Cargo.lock Cargo.toml crates/`), intégrité vérifiée par empreinte SHA-256 avant/après (`c1aecea8…c499d3b` / `701bc7ee…4d6ff016`), rien perdu. **Leçon : vérifier la branche courante AVANT de commencer.**
## Prochaine étape
Validation live utilisateur : (1) le desktop ne perd rien, (2) `idea-serve` sert le client web. Si OK → Git merge dans develop (Git refuse de merger sans QA réelle sur les DEUX binaires ; point sensible = workspace `Cargo.toml` members). Débloque ensuite #68 (via `run_embedded`) et #66 (Docker).

View File

@ -2,16 +2,16 @@
id: "f9f7067b-92b7-4737-ad99-4487ad8c8b13"
number: 65
title: "Serveur headless : extraire idea-serve du binaire Tauri (cœur partagé)"
status: "open"
status: "qa"
priority: "high"
sprint: null
sprint: "028179b1-eaf4-41e9-9c1f-7c37125117e6"
links: [{"target":"#13","kind":"dependsOn"}]
agentRefs: []
createdBy: {"kind":"agent","agent_id":"a6ced819-b893-4213-b003-9e9dc79b9641"}
updatedBy: {"kind":"agent","agent_id":"a6ced819-b893-4213-b003-9e9dc79b9641"}
createdAt: 1784187583229
updatedAt: 1784187583229
version: 1
updatedAt: 1784202758668
version: 6
---
Objectif : produire un binaire serveur headless (`idea-serve`) SANS dépendance Tauri/WebKit, bâti sur le même cœur backend que le desktop (pas de fork). Prérequis de l'image Docker serveur/client. Cadré par Architect (suite #13).

View File

@ -1,6 +1,6 @@
---
issueRef: "#66"
version: 1
updatedBy: {"kind":"agent","agent_id":"a6ced819-b893-4213-b003-9e9dc79b9641"}
updatedAt: 1784187597004
version: 2
updatedBy: {"kind":"user"}
updatedAt: 1784193460805
---

View File

@ -4,14 +4,14 @@ number: 66
title: "Image Docker serveur/client IdeA"
status: "open"
priority: "medium"
sprint: null
sprint: "028179b1-eaf4-41e9-9c1f-7c37125117e6"
links: [{"target":"#65","kind":"dependsOn"}]
agentRefs: []
createdBy: {"kind":"agent","agent_id":"a6ced819-b893-4213-b003-9e9dc79b9641"}
updatedBy: {"kind":"agent","agent_id":"a6ced819-b893-4213-b003-9e9dc79b9641"}
updatedBy: {"kind":"user"}
createdAt: 1784187597004
updatedAt: 1784187597004
version: 1
updatedAt: 1784193460805
version: 2
---
Objectif : livrer une image Docker exécutant le mode serveur/client d'IdeA, bâtie sur le binaire headless `idea-serve` (#65), pas sur le binaire Tauri. Cadré par Architect (suite #13).

View File

@ -1,6 +1,6 @@
---
issueRef: "#67"
version: 1
updatedBy: {"kind":"agent","agent_id":"a6ced819-b893-4213-b003-9e9dc79b9641"}
updatedAt: 1784187618710
version: 2
updatedBy: {"kind":"user"}
updatedAt: 1784193467784
---

View File

@ -4,14 +4,14 @@ number: 67
title: "Lock inter-process de l'app-data-dir (desktop ↔ idea --serve)"
status: "open"
priority: "low"
sprint: null
sprint: "028179b1-eaf4-41e9-9c1f-7c37125117e6"
links: [{"target":"#13","kind":"dependsOn"}]
agentRefs: []
createdBy: {"kind":"agent","agent_id":"a6ced819-b893-4213-b003-9e9dc79b9641"}
updatedBy: {"kind":"agent","agent_id":"a6ced819-b893-4213-b003-9e9dc79b9641"}
updatedBy: {"kind":"user"}
createdAt: 1784187618710
updatedAt: 1784187618710
version: 1
updatedAt: 1784193467784
version: 2
---
Issu de la validation live #13. `idea --serve` et l'app desktop peuvent écrire le même app-data-dir (`~/.local/share/app.idea.ide`) simultanément — pas de lock inter-process → risque de corruption d'état (projects.json/profiles.json/tasks). Aujourd'hui contourné par une simple consigne de doc (« ne pas lancer les deux en même temps »).

View File

@ -0,0 +1,6 @@
---
issueRef: "#68"
version: 5
updatedBy: {"kind":"agent","agent_id":"a6ced819-b893-4213-b003-9e9dc79b9641"}
updatedAt: 1784193767292
---

View File

@ -0,0 +1,16 @@
---
id: "13821b24-f566-402e-bc10-02ac6e8a5f7c"
number: 68
title: "Ajouter dans l'app desktop, la possibilité d'activer le serveur"
status: "open"
priority: "medium"
sprint: "028179b1-eaf4-41e9-9c1f-7c37125117e6"
links: [{"target":"#65","kind":"dependsOn"}]
agentRefs: [{"agentId":"a6ced819-b893-4213-b003-9e9dc79b9641","role":"assigned"}]
createdBy: {"kind":"user"}
updatedBy: {"kind":"agent","agent_id":"a6ced819-b893-4213-b003-9e9dc79b9641"}
createdAt: 1784193318419
updatedAt: 1784193767292
version: 5
---
J'iamerais que depuis l'app desktop, on puisse quand même embarquer le serveur. Comme ça un utilisateur pourrait continuer son travail en cours en remote

View File

@ -0,0 +1,41 @@
---
issueRef: "#69"
version: 9
updatedBy: {"kind":"agent","agent_id":"a6ced819-b893-4213-b003-9e9dc79b9641"}
updatedAt: 1784202783353
---
# Ticket #69 — Adaptibilité client téléphone (carnet de chantier)
Statut : **QA — en attente de validation live utilisateur sur un VRAI téléphone**.
Branche : `feature/ticket69-mobile-responsive-client` (base `develop` @ `506d589`). Commits : `e22ea5b` (shell), `8f15ad6` (terminal + tests), `6ed0087` (fix typecheck). Frontend uniquement — vérifié.
## Cadrage Architect
Ticket **frontend-pur** : aucun changement DTO, use case, ni modèle `LayoutTree`. Contrats HTTP/WS et layout/terminal inchangés. Mais PAS du « CSS pur ».
## ⚠️ Le cadrage initial reposait sur un modèle FAUX (constat majeur)
Le lot 2 prévoyait « remplacer les docks gauche/droite/floating par une pile verticale/drawer/bottom sheet ». **Il n'y a rien à remplacer** : le client web n'a JAMAIS eu de docks, de fenêtres flottantes ni de `LayoutTree`. `main.tsx` route le mode `http` vers `WebApp`, surface autonome livrée par #13 : pairing **ou** `WebWorkspace`, déjà une colonne verticale unique. Les seuls imports `@/features/*` de tout `features/web/` sont `terminals` et `workstate` — le shell desktop n'est pas atteignable depuis le web.
**La question « bottom sheet vs drawer » ne se pose pas.** Frontière épinglée par un test (`WebMobile.test.tsx`) + mémoire `web-client-is-single-column-no-desktop-shell`, pour que le cadrage ne reparte pas du même modèle faux.
## Le vrai blocage était le terminal, pas le layout
Le clavier virtuel n'a ni Esc, ni Tab, ni Ctrl, ni flèches : on pouvait taper un prompt à un agent CLI mais pas l'interrompre, compléter un chemin, sortir d'un éditeur ou rappeler l'historique.
## Livré
- **Lot 1 (shell)** : `100dvh` (le `height:100%` se résolvait sur le *large* viewport ⇒ la barre d'URL rétractable masquait le bas), `viewport-fit=cover` + safe-area insets, padding responsive, `inputMode="numeric"` sur le code d'appairage. Zoom laissé libre (accessibilité).
- **Lot 2 (réinterprété)** : `AgentLiveRow` + rangée de tâche de fond (statut/kind/Cancel/Retry ne tenaient pas à 360px) s'empilent sous `sm`, ligne unique dès `sm`.
- **Lot 3 (terminal)** : `TerminalView` expose `onReady(api)` **optionnel** (desktop inchangé) ; `api.send` passe par `term.input()` — même chemin qu'une frappe réelle, donc relais PTY + suspension du write-portal s'appliquent à l'identique (écrire sur le handle aurait court-circuité le portal). `TerminalKeyBar` : Esc/Tab/Ctrl-C/Ctrl-D/flèches en chips 44px ; **chaque tap annule le déplacement de focus** puis refocalise xterm (sinon le clavier virtuel se referme à chaque touche). Cellule `h-64``h-[60dvh]`.
## Vérif QA (exécution réelle) — VERT
- `npm run typecheck` exit 0 · `npx vitest run` → 85 files / **774 passed** · `VITE_TRANSPORT=http npx vite build` OK.
- **CSS mobile confirmé DANS le bundle** (les valeurs arbitraires Tailwind avec `env()` no-opent en silence) : `100dvh`, `60dvh`, les 4 `safe-area-inset-*`, `viewport-fit=cover`, `.h-\[60dvh\]{height:60dvh}`.
- Non-régression desktop : `LayoutGrid` ne passe pas `onReady` ; chemin desktop inchangé.
- Rendu réel Chrome headless 360×780 : pairing tient sans débordement horizontal.
## Réserve ASSUMÉE — trou de couverture réel
**jsdom n'évalue PAS les media queries** : les tests sont structurels, pas visuels. Ils ne prouvent NI le rendu aux breakpoints, NI l'effet réel de `dvh`, NI les safe areas, NI le clavier virtuel/focus sur navigateur mobile. QA : « acceptable pour merger avec réserve explicite », pas rouge. **C'est exactement ce que la validation utilisateur doit couvrir.**
Workspace + keybar non vérifiés visuellement à 360px (demande un serveur appairé + PTY vivant = territoire #65) — angle mort restant.
## Écart de périmètre à arbitrer (Playwright)
Lot 4 demandait « Playwright ou équivalent ». DevFrontend a livré l'équivalent (vitest/jsdom) et REFUSÉ d'installer Playwright unilatéralement (binaires navigateur + surface CI = décision de dépendance qui remonte à Architect/Main). Avis QA : non bloquant pour ce lot, mais vitest/jsdom **n'est pas un équivalent complet** pour un ticket dont le risque principal est visuel mobile. ⇒ **Follow-up à décider** : ticket « tests de rendu réel aux breakpoints » si le projet accepte une dépendance navigateur/CI.
## Prochaine étape
Validation live utilisateur sur un vrai téléphone (build `VITE_TRANSPORT=http`, servi par `idea --serve`/`idea-serve`, accès LAN). Si OK → Git merge dans develop (Git passera #69 avant #65 si les deux sont prêts : petit, frontend-pur, faible risque).

View File

@ -0,0 +1,16 @@
---
id: "7f5a40cf-837f-46f7-8c5f-653c80975396"
number: 69
title: "Adaptibilité client téléphone"
status: "qa"
priority: "medium"
sprint: "028179b1-eaf4-41e9-9c1f-7c37125117e6"
links: []
agentRefs: [{"agentId":"a6ced819-b893-4213-b003-9e9dc79b9641","role":"assigned"}]
createdBy: {"kind":"user"}
updatedBy: {"kind":"agent","agent_id":"a6ced819-b893-4213-b003-9e9dc79b9641"}
createdAt: 1784193391258
updatedAt: 1784202783353
version: 9
---
J'aimerais un format vertical qui rende l'app client compatible téléphone

View File

@ -0,0 +1,6 @@
---
issueRef: "#70"
version: 4
updatedBy: {"kind":"user"}
updatedAt: 1784194049447
---

View File

@ -0,0 +1,16 @@
---
id: "e73ed25f-8e22-48a5-84ea-521212ea80b5"
number: 70
title: "Pouvoir gérer les models AI locaux téléchargés via les serveur llamacpp"
status: "open"
priority: "low"
sprint: null
links: []
agentRefs: [{"agentId":"a6ced819-b893-4213-b003-9e9dc79b9641","role":"assigned"}]
createdBy: {"kind":"user"}
updatedBy: {"kind":"user"}
createdAt: 1784194016529
updatedAt: 1784194049447
version: 4
---
Avec les serveurs de models locaux llamacpp, on télécharge des modeles, j'aimerais aussi pouvoir les supprimer

View File

@ -1,3 +1,3 @@
{
"nextNumber": 68
"nextNumber": 71
}

View File

@ -149,13 +149,13 @@
"issueRef": "#13",
"path": "13",
"title": "Server/client mode",
"status": "inProgress",
"status": "closed",
"priority": "low",
"sprint": "028179b1-eaf4-41e9-9c1f-7c37125117e6",
"assignedAgentIds": [
"a6ced819-b893-4213-b003-9e9dc79b9641"
],
"updatedAt": 1784184002362
"updatedAt": 1784193634690
},
{
"issueRef": "#14",
@ -627,9 +627,9 @@
"title": "[Bug] Assistant IA d'édition de ticket : aucune réponse dans la conversation (stream sans Final non signalé)",
"status": "inProgress",
"priority": "high",
"sprint": null,
"sprint": "e28a4d53-8bd2-446a-b0ac-2a017373b8b2",
"assignedAgentIds": [],
"updatedAt": 1784095176619
"updatedAt": 1784194089605
},
{
"issueRef": "#61",
@ -669,19 +669,19 @@
"title": "Web : créer/ajouter un projet depuis le navigateur (folder browser serveur)",
"status": "open",
"priority": "medium",
"sprint": null,
"sprint": "028179b1-eaf4-41e9-9c1f-7c37125117e6",
"assignedAgentIds": [],
"updatedAt": 1784187610934
"updatedAt": 1784193766706
},
{
"issueRef": "#65",
"path": "65",
"title": "Serveur headless : extraire idea-serve du binaire Tauri (cœur partagé)",
"status": "open",
"status": "qa",
"priority": "high",
"sprint": null,
"sprint": "028179b1-eaf4-41e9-9c1f-7c37125117e6",
"assignedAgentIds": [],
"updatedAt": 1784187583229
"updatedAt": 1784202758668
},
{
"issueRef": "#66",
@ -689,9 +689,9 @@
"title": "Image Docker serveur/client IdeA",
"status": "open",
"priority": "medium",
"sprint": null,
"sprint": "028179b1-eaf4-41e9-9c1f-7c37125117e6",
"assignedAgentIds": [],
"updatedAt": 1784187597004
"updatedAt": 1784193460805
},
{
"issueRef": "#67",
@ -699,9 +699,45 @@
"title": "Lock inter-process de l'app-data-dir (desktop ↔ idea --serve)",
"status": "open",
"priority": "low",
"sprint": null,
"sprint": "028179b1-eaf4-41e9-9c1f-7c37125117e6",
"assignedAgentIds": [],
"updatedAt": 1784187618710
"updatedAt": 1784193467784
},
{
"issueRef": "#68",
"path": "68",
"title": "Ajouter dans l'app desktop, la possibilité d'activer le serveur",
"status": "open",
"priority": "medium",
"sprint": "028179b1-eaf4-41e9-9c1f-7c37125117e6",
"assignedAgentIds": [
"a6ced819-b893-4213-b003-9e9dc79b9641"
],
"updatedAt": 1784193767292
},
{
"issueRef": "#69",
"path": "69",
"title": "Adaptibilité client téléphone",
"status": "qa",
"priority": "medium",
"sprint": "028179b1-eaf4-41e9-9c1f-7c37125117e6",
"assignedAgentIds": [
"a6ced819-b893-4213-b003-9e9dc79b9641"
],
"updatedAt": 1784202783353
},
{
"issueRef": "#70",
"path": "70",
"title": "Pouvoir gérer les models AI locaux téléchargés via les serveur llamacpp",
"status": "open",
"priority": "low",
"sprint": null,
"assignedAgentIds": [
"a6ced819-b893-4213-b003-9e9dc79b9641"
],
"updatedAt": 1784194049447
}
]
}

19
Cargo.lock generated
View File

@ -90,6 +90,7 @@ dependencies = [
"thiserror 2.0.18",
"tokio",
"uuid",
"web-server",
]
[[package]]
@ -5236,6 +5237,24 @@ dependencies = [
"semver",
]
[[package]]
name = "web-server"
version = "0.3.0"
dependencies = [
"application",
"backend",
"base64 0.22.1",
"bytes",
"cookie",
"domain",
"http",
"http-body-util",
"serde",
"serde_json",
"tokio",
"uuid",
]
[[package]]
name = "web-sys"
version = "0.3.99"

View File

@ -5,6 +5,7 @@ members = [
"crates/application",
"crates/infrastructure",
"crates/backend",
"crates/web-server",
"crates/app-tauri",
]
@ -31,6 +32,7 @@ domain = { path = "crates/domain" }
application = { path = "crates/application" }
infrastructure = { path = "crates/infrastructure" }
backend = { path = "crates/backend" }
web-server = { path = "crates/web-server" }
# Tauri v2
tauri = { version = "2", features = [] }

View File

@ -24,6 +24,7 @@ domain = { workspace = true }
application = { workspace = true }
infrastructure = { workspace = true }
backend = { workspace = true }
web-server = { workspace = true }
tauri = { workspace = true }
tauri-plugin-dialog = { workspace = true }
# `io-std` gives the headless `mcp-server` bridge access to

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1743,15 +1743,6 @@ fn required_str<'a>(arguments: &'a Value, key: &str) -> Result<&'a str, TicketTo
.ok_or_else(|| TicketToolError::new("invalid", format!("missing {key}")))
}
impl ErrorDto {
fn invalid(message: impl Into<String>) -> Self {
Self {
code: "INVALID".to_owned(),
message: message.into(),
}
}
}
#[cfg(test)]
mod tests {
use super::*;

3495
crates/backend/src/dto.rs Normal file

File diff suppressed because it is too large Load Diff

1314
crates/backend/src/events.rs Normal file

File diff suppressed because it is too large Load Diff

View File

@ -83,6 +83,8 @@ use infrastructure::{
VECTOR_HTTP_ENABLED, VECTOR_ONNX_ENABLED,
};
pub mod dto;
pub mod events;
pub mod mcp_endpoint;
pub mod openai_tools;
pub mod stream;

View File

@ -159,7 +159,7 @@ pub fn mcp_endpoint(project_id: &ProjectId) -> McpEndpoint {
/// `/tmp/.mount_*` qui disparaît au redémarrage ⇒ `ENOENT` au respawn du pont MCP.
/// Hors AppImage `$APPIMAGE` est absent ⇒ on retombe sur `current_exe()`. `None` si
/// aucun des deux n'est résolvable (ne devrait pas arriver) ⇒ déclaration minimale.
pub(crate) fn idea_exe_path() -> Option<String> {
pub fn idea_exe_path() -> Option<String> {
std::env::var("APPIMAGE").ok().or_else(|| {
std::env::current_exe()
.ok()

View File

@ -0,0 +1,33 @@
[package]
name = "web-server"
version = "0.3.0"
edition.workspace = true
license.workspace = true
rust-version.workspace = true
description = "IdeA headless HTTP/WebSocket driving adapter, reusable by desktop and server binaries."
[lib]
name = "web_server"
path = "src/lib.rs"
[[bin]]
name = "idea-serve"
path = "src/bin/idea-serve.rs"
[dependencies]
backend = { workspace = true }
application = { workspace = true }
domain = { workspace = true }
tokio = { workspace = true, features = ["io-std", "rt", "net"] }
serde = { workspace = true }
serde_json = { workspace = true }
uuid = { workspace = true }
base64 = "0.22"
bytes = "1.11"
cookie = "0.18"
http = "1.4"
http-body-util = "0.1"
[features]
vector-http = ["backend/vector-http"]
vector-onnx = ["backend/vector-onnx"]

View File

@ -0,0 +1,5 @@
use std::process::ExitCode;
fn main() -> ExitCode {
web_server::run_from_args(std::env::args().skip(1).collect())
}

4140
crates/web-server/src/lib.rs Normal file

File diff suppressed because it is too large Load Diff