Commit Graph

8 Commits

Author SHA1 Message Date
b05d04ab7a feat(permissions): LP4-0 — fondations domaine de l'enforcement OS (pur)
Fondations pures (zéro I/O, zéro dépendance landlock, aucun câblage
runtime — SpawnSpec.sandbox posé mais jamais lu ⇒ zéro régression) de la
voie « airtight » des permissions, complément de la voie projection LP3.

- domain/sandbox.rs : SandboxPlan/PathGrant/PathAccess (RO|RW|EXEC),
  SandboxContext, SandboxKind/Status/Error, port SandboxEnforcer, et la
  fonction pure compile_sandbox_plan(EffectivePermissions → plan OS).
- domain/permission.rs : render_permission_summary (bloc Markdown injecté
  plus tard ; mentionne explicitement fichiers OS-enforced vs commandes
  advisory).
- domain/ports.rs : SpawnSpec.sandbox: Option<SandboxPlan> (None ⇒ natif),
  propagé à tous les sites de construction.

Sémantique de compile_sandbox_plan :
- Invariant produit : eff == None ⇒ None (rien posé ⇒ CLI 100 % native).
- Borne Landlock : seules les capabilities fichier produisent des grants
  (Read→RO, Write/Delete→RW) ; ExecuteBash reste advisory (non verrouillable
  par chemin).
- Deny-wins PAR CLASSE D'ACCÈS (RO/RW), fail-closed intra-classe : un Deny
  ne ferme que les grants de sa propre classe (un Deny Write n'ampute pas un
  Allow Read). Choix retenu pour maximiser l'autonomie des agents : on
  respecte exactement la politique pré-renseignée sans sur-restreindre, donc
  moins de blocages qui forceraient l'agent à redemander l'utilisateur.
- Globs réduits à leur préfixe statique ; grant abandonné si une barrière de
  même classe chevauche (égal/ancêtre/descendant) — sous-approximation
  conservatrice (un sandbox additif ne peut pas carver un deny sous-arbre).

Tests : 16 tests purs sur sandbox + 3 sur render_permission_summary,
cargo test --workspace 100 % vert, 0 ignored.

Reste LP4 : LP4-1 adapter LandlockSandbox + pre_exec PTY (fail-open+warning
sauf posture Deny), LP4-2 câblage application, LP4-3 composition root.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 21:37:34 +02:00
fdcf16c387 chore(wip): checkpoint P8/C avant chantier Codex inter-agents
Sauvegarde de l'arbre de travail en cours (persistance P8, conversations
C-series, write-portal frontend, médiation d'entrée) avant d'attaquer le
support de la délégation inter-agents pour les profils Codex.

Le round-trip inter-agent question/réponse est couvert sans tokens par
les tests loopback existants (state::mcp_e2e_loopback_tests).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-13 21:42:53 +02:00
d87b8f6ed2 feat(persistence): P8c — routage --resume moteur via providers.json (structuré)
Referme la régression latente de P8a : pour un profil structuré, le resumable
passé au moteur vient de providers.json[provider] (vrai id Claude/Codex), jamais
de l'id de paire désormais porté par la cellule.

- resolve_session_plan devient async + prend root ; branche structurée câblée :
  get(pair, provider_key) ⇒ Resume{engine_id}, sinon None ; repli gracieux sur
  l'ancien comportement si le store n'est pas câblé (zéro régression tests) ;
  branche non structurée strictement inchangée
- tests : 6 cas (claude/codex Resume{engine} avec assert_ne! vs id de paire,
  discrimination de clé provider, store vide/cellule neuve/non-uuid ⇒ None) ;
  structured_launch_d3 22 verts, domain+application+app-tauri sans régression

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-12 18:42:35 +02:00
9b053216e3 feat(persistence): P8b — écriture providers.json (resumable par provider)
Au lancement structuré, le resumable exposé par le moteur est rangé dans
providers.json sous (id de paire, provider) — best-effort, n'altère jamais le
lancement.

- domaine : StructuredAdapter::provider_key() ⇒ "claude"/"codex" (clé stable
  par famille, lisible, indépendante de l'uuid d'instance)
- application : port ProviderSessionProvider (root par appel) +
  with_provider_session_provider ; helper persist_provider_session dans
  launch_structured (skip si provider/adapter/id moteur absents ou set KO)
- app-tauri : AppProviderSessionProvider (FsProviderSessionStore sur le root)
- tests : 6 cas (nominal claude/codex, no-op sans provider/sans id moteur,
  best-effort, mapping provider_key) ; domain+application verts

Lecture du store pour --resume = P8c.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-12 18:36:19 +02:00
e583b2b49f feat(persistence): P8a — cohérence de clé conversation (id de paire stable)
Corrige l'incohérence P6/P7 : la cellule et la persistance partagent désormais
le MÊME id de paire IdeA, déterministe et stable au redémarrage — la clé sous
laquelle P6b sauve log/handoff == celle sous laquelle P7 les charge.

- domaine : ConversationId::for_pair(a,b) pur/déterministe (User↔Agent = uuid
  agent ; Agent↔Agent = XOR commutatif) ; LeafCell gagne engine_session_id
  (cache resumable moteur, additif serde default)
- infrastructure : InMemoryConversationRegistry::resolve utilise for_pair au
  lieu de new_random() → id recalculable sans état, identique après restart
- application : launch_structured persiste l'id de paire sur la cellule (et l'id
  moteur sur engine_session_id) ; cellule neuve ⇒ dérive for_pair(User,agent) ;
  resolve_conversation repli factorisé sur for_pair ; withers layout clone-and-
  mutate (préservent les champs additifs)
- app-tauri : engine_session_id propagé dans les DTO

Suites domain/infra/application/app-tauri vertes (assertion structured_launch_d3
recodée sur le contrat). Test déterminisme/restart dédié à ajouter au retour de
quota agent (binôme Test interrompu par limite de session).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-12 18:10:50 +02:00
cf89b3b9a5 feat(agent): bind transport S-MCP — outils idea_* vivants de bout en bout (M5a-e) — §14.3.1
Dernier kilomètre de l'orchestration native : une CLI MCP réellement lancée
joint le serveur MCP du projet et ses outils idea_* aboutissent au vrai dispatch.

- M5a endpoint loopback par projet (interprocess UDS/named pipe, source unique
  mcp_endpoint, cleanup au close) — zéro port réseau, AppImage/SSH-safe.
- M5b sous-commande `idea mcp-server` : pont stdio↔loopback headless (avant init
  Tauri), handshake {"project","requester"}, endpoint-absent borné, EOF propre.
- M5c McpServerHandle boucle accept + serve_peer par pair ; requester réel
  propagé jusqu'à OrchestratorRequestProcessed (fin du "mcp" figé) ; isolation
  des pairs ; terminaison propre.
- M5d apply_mcp_config écrit la déclaration réelle (current_exe + --endpoint
  mcp_endpoint + --project simple-uuid + --requester) ; McpRuntime injecté comme
  donnée (application ne dépend pas de app-tauri).
- M5e smoke e2e sur vrai loopback : list/ask inline, cible PTY → erreur typée,
  JSON malformé → pas de panic, requester propagé.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-10 18:09:41 +02:00
6ca519b815 feat(agent): robustesse routage ask — fix registre session + concurrence (R0+A0) — §14.3/§15
Stabilise le routage de `ask` avant le bind transport MCP (v5). Invariant
« 1 agent = 1 employé » durci ; un agent traite un tour à la fois.

- R0a garde LaunchAgent : lève AgentAlreadyRunning pour un lancement neuf
  ciblant un agent déjà vivant sur un autre node (PTY + structuré) ; rebind
  seulement même-node ou réattache explicite (conversation_id). Idem spawn_agent.
- R0b list_live_agents agrège PTY + structuré (LiveSessions) + dédup.
- R0c réconciliation des layouts.json à doublons à l'ouverture (host déterministe,
  idempotent) — corrige « une cellule reset au retour d'onglet ».
- R0d UI : option agent désactivée si vivant ailleurs + « aller à la cellule »,
  mapping AGENT_ALREADY_RUNNING.
- A0 sérialisation FIFO des tours par agent_id dans ask_agent (verrou tokio par
  agent ; agents différents en parallèle ; timeout tour 300s, cap attente 600s).

Cadrage : .ideai/briefs/orchestration-v5-transport-bind-cadrage.md.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-10 17:34:57 +02:00
56913b9053 feat(agent): routage LaunchAgent structuré vs PTY + réconciliation A/B (D3) — §17
- LaunchAgent route sur profile.structured_adapter : Some ⇒ AgentSession via
  factory + enregistrement StructuredSessions (aucun pty.spawn) ; None ⇒ PTY
  inchangé. Dépendances structurées injectées par builders additifs
  with_structured (signatures publiques inchangées ⇒ A/B legacy verts).
- LaunchAgentOutput étendu d'un champ optionnel structured (non cassant).
- A (ChangeAgentProfile) : kill polymorphe — session structurée ⇒ shutdown(),
  PTY ⇒ kill ; détection sur les deux registres.
- B : resume_supported vrai pour profil structuré ; resolve_session_plan ⇒
  Resume{conversation_id} (Claude --resume / Codex exec resume).
- Codex : build_spawn_line porte --sandbox workspace-write --ask-for-approval
  never (autonomie d'écriture ; à terme piloté par les permissions).

Tests : structured_launch 8 + codex flags 2 ; application/infrastructure 0 échec.

Reste D4 : ChatBridge (Channel) + commandes agent_send/reattach + StructuredSessions
dans AppState + DTO cellKind/ReplyChunk.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-09 18:48:25 +02:00