use std::ffi::OsStr;
use std::path::{Path, PathBuf};
use super::{AgentBackend, BackendState};
use crate::doctor::{CheckStatus, DoctorCheck, DoctorReport};
use crate::error::Result;
use crate::host::{Capabilities, Desired, Outcome, Plugin, Scope, Source};
pub(crate) struct PiBackend;
impl AgentBackend for PiBackend {
fn id(&self) -> &'static str {
"pi"
}
fn detect(&self) -> bool {
which::which("pi").is_ok() || pi_dir().is_some_and(|d| d.is_dir())
}
fn capabilities(&self) -> Capabilities {
Capabilities {
plugins: false,
mcp: false,
hooks: false,
commands: false,
agents: false,
skills: false,
instructions: false,
statusline: false,
scopes: &["user"],
}
}
fn probe(&self, _plugin: &Plugin, _scope: &Scope, _source: &Source) -> Result<BackendState> {
Ok(BackendState::Healthy)
}
fn reconcile(&self, _plugin: &Plugin, _desired: &Desired, _scope: &Scope) -> Result<Outcome> {
Ok(Outcome::NoOp)
}
fn remove(&self, _plugin: &Plugin, _scope: &Scope, _source: &Source) -> Result<Outcome> {
Ok(Outcome::NoOp)
}
fn report(&self, _plugin: &Plugin, _source: &Source) -> DoctorReport {
let detected = if self.detect() {
DoctorCheck { name: "pi detected", status: CheckStatus::Ok("`pi` on PATH or ~/.pi present".into()) }
} else {
DoctorCheck {
name: "pi detected",
status: CheckStatus::Fail {
problem: "pi CLI not detected".into(),
fix: "install it with `npm install -g --ignore-scripts @earendil-works/pi-coding-agent`".into(),
},
}
};
let surface = DoctorCheck {
name: "pi surface",
status: CheckStatus::Ok(
"detect-only: no mcp or config-file hooks to translate; pi's file-writable commands/skills surfaces are out of scope"
.into(),
),
};
DoctorReport::from_checks(vec![detected, surface])
}
}
fn pi_dir() -> Option<PathBuf> {
resolve_pi_dir(std::env::var_os("PI_CODING_AGENT_DIR").as_deref(), dirs::home_dir().as_deref())
}
fn resolve_pi_dir(env_override: Option<&OsStr>, home: Option<&Path>) -> Option<PathBuf> {
if let Some(dir) = env_override.filter(|v| !v.is_empty()) {
return Some(PathBuf::from(dir));
}
home.map(|h| h.join(".pi"))
}
#[cfg(test)]
#[path = "../../tests/unit/pi.rs"]
mod pi_tests;