zenith_cli/commands/plugin/
detect.rs1use std::path::{Path, PathBuf};
5
6use super::agent::{ALL_AGENTS, Agent, Scope};
7use super::paths::{home_dir, skill_target};
8
9pub fn is_installed(agent: Agent, scope: Scope, project_root: &Path) -> bool {
11 skill_target(agent, scope, project_root)
12 .map(|t| t.root().exists())
13 .unwrap_or(false)
14}
15
16pub fn marker_dir(agent: Agent, scope: Scope, project_root: &Path) -> Option<PathBuf> {
20 let (proj, user): (&str, fn(&Path) -> PathBuf) = match agent {
21 Agent::ClaudeCode => (".claude", |h| h.join(".claude")),
22 Agent::Codex => (".codex", |h| h.join(".codex")),
23 Agent::OpenCode => (".opencode", |h| h.join(".config").join("opencode")),
24 Agent::Cursor => (".cursor", |h| h.join(".cursor")),
25 Agent::Windsurf => (".windsurf", |h| h.join(".windsurf")),
26 Agent::Aider => (".aider", |h| h.join(".aider")),
27 Agent::Zed => (".zed", |h| h.join(".zed")),
28 Agent::Gemini => (".gemini", |h| h.join(".gemini")),
29 Agent::Copilot => (".copilot", |h| h.join(".copilot")),
30 Agent::Continue => (".continue", |h| h.join(".continue")),
31 Agent::Kiro => (".kiro", |h| h.join(".kiro")),
32 Agent::Antigravity => (".antigravity", |h| h.join(".antigravity")),
33 };
34 match scope {
35 Scope::Project => Some(project_root.join(proj)),
36 Scope::User => home_dir().map(|h| user(&h)),
37 }
38}
39
40pub fn is_present(agent: Agent, project_root: &Path) -> bool {
42 [Scope::Project, Scope::User].into_iter().any(|scope| {
43 marker_dir(agent, scope, project_root)
44 .map(|d| d.exists())
45 .unwrap_or(false)
46 })
47}
48
49pub fn detect_present(project_root: &Path) -> Vec<Agent> {
51 ALL_AGENTS
52 .iter()
53 .copied()
54 .filter(|a| is_present(*a, project_root))
55 .collect()
56}