evolve_adapters/traits.rs
1//! The [`Adapter`] trait: one implementor per supported tool.
2
3use crate::signals::{ParsedSignal, SessionLog};
4use async_trait::async_trait;
5use evolve_core::agent_config::AgentConfig;
6use evolve_core::ids::AdapterId;
7use std::path::Path;
8use thiserror::Error;
9
10/// Errors common to all adapters.
11#[derive(Debug, Error)]
12pub enum AdapterError {
13 /// I/O error reading or writing adapter files.
14 #[error("io: {0}")]
15 Io(#[from] std::io::Error),
16 /// JSON error parsing or writing settings/transcript.
17 #[error("json: {0}")]
18 Json(#[from] serde_json::Error),
19 /// Adapter was asked to operate on a root that it does not recognize.
20 #[error("adapter not applicable at {path}")]
21 NotApplicable {
22 /// Path the caller asked the adapter to operate on.
23 path: String,
24 },
25 /// Adapter-specific parse failure (bad transcript line, etc.).
26 #[error("parse: {0}")]
27 Parse(String),
28}
29
30/// What [`Adapter::detect`] found in a target directory.
31#[derive(Debug, Clone, Copy, PartialEq, Eq)]
32pub enum AdapterDetection {
33 /// Strong signal the tool is in use here (config files, binaries, etc.).
34 Detected,
35 /// Nothing conclusive found.
36 NotDetected,
37}
38
39/// Per-tool integration contract. See design doc section 4.4.
40#[async_trait]
41pub trait Adapter: Send + Sync {
42 /// Stable identifier (e.g., "claude-code", "cursor", "aider").
43 fn id(&self) -> AdapterId;
44
45 /// Detect whether the tool is in use at `root` (or in the user's home).
46 fn detect(&self, root: &Path) -> AdapterDetection;
47
48 /// Install hooks/config so the tool reports sessions back to Evolve. Idempotent.
49 async fn install(&self, root: &Path, config: &AgentConfig) -> Result<(), AdapterError>;
50
51 /// Write the given config into the tool's files (inside managed-section markers).
52 async fn apply_config(&self, root: &Path, config: &AgentConfig) -> Result<(), AdapterError>;
53
54 /// Parse a session log into fitness signals.
55 async fn parse_session(&self, log: SessionLog) -> Result<Vec<ParsedSignal>, AdapterError>;
56
57 /// Remove everything this adapter installed, restoring the pre-evolve state.
58 async fn forget(&self, root: &Path) -> Result<(), AdapterError>;
59}