agent-manager v0.2.0 : gestionnaire d'agents IA locaux
- CLI Rust (am) : list/install/uninstall/update/start/stop/restart/run/status/search/info/config/doctor/completion/export/import/self-update + shell interactif (Tab, historique) - 9 methodes d'installation (npm, pip, uv, cargo, go, bun, curl, binary, git) - catalogue de 72 agents, dependances, processus, securite (dry-run, checksums) - sondes de version paralleles + cache (am list ~25 ms a chaud) - installateurs one-liner : install.sh, install.ps1
This commit is contained in:
@@ -0,0 +1,151 @@
|
||||
//! list: installed agents by default (managed, running and external), or
|
||||
//! the whole catalog with --all.
|
||||
|
||||
use super::*;
|
||||
use crate::output::{print_json, status_style, Table};
|
||||
use crate::probe::ExternalInfo;
|
||||
use crate::state::InstalledEntry;
|
||||
use serde::Serialize;
|
||||
|
||||
#[derive(Serialize)]
|
||||
struct AgentRow {
|
||||
name: String,
|
||||
display_name: String,
|
||||
category: Option<String>,
|
||||
description: Option<String>,
|
||||
status: String,
|
||||
version: Option<String>,
|
||||
source: String,
|
||||
method: Option<String>,
|
||||
path: Option<String>,
|
||||
running: bool,
|
||||
pid: Option<u32>,
|
||||
installable: bool,
|
||||
note: Option<String>,
|
||||
}
|
||||
|
||||
/// run: installed agents only, unless all is set (whole catalog).
|
||||
pub fn run(app: &App, all: bool, category: Option<&str>) -> Result<i32> {
|
||||
let entries = app.state.all().unwrap_or_default();
|
||||
let probe = crate::probe::detect_externals(app);
|
||||
let mut rows: Vec<AgentRow> = Vec::new();
|
||||
for agent in app.catalog.agents() {
|
||||
if agent.hidden {
|
||||
continue;
|
||||
}
|
||||
if let Some(cat) = category {
|
||||
if agent.category.as_deref() != Some(cat) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
rows.push(row_for(agent, entries.get(&agent.name), &probe));
|
||||
}
|
||||
if !all {
|
||||
rows.retain(|r| r.status == "running" || r.status == "installed" || r.status == "external");
|
||||
}
|
||||
rows.sort_by(|a, b| a.name.cmp(&b.name));
|
||||
|
||||
if app.json() {
|
||||
print_json(&rows);
|
||||
return Ok(0);
|
||||
}
|
||||
let color = app.color();
|
||||
let mut table = Table::new(vec!["NAME", "VERSION", "STATUS", "SOURCE", "PATH"]);
|
||||
for r in &rows {
|
||||
table.row(vec![
|
||||
r.display_name.clone(),
|
||||
r.version.clone().unwrap_or_else(|| "—".to_string()),
|
||||
status_style(&r.status, color),
|
||||
r.source.clone(),
|
||||
r.path.clone().unwrap_or_else(|| "—".to_string()),
|
||||
]);
|
||||
}
|
||||
print!("{}", table.render());
|
||||
if rows.is_empty() {
|
||||
app.log.info(if all {
|
||||
"no agents found"
|
||||
} else {
|
||||
"no installed agents found — run 'am list --all' for the full catalog"
|
||||
});
|
||||
}
|
||||
Ok(0)
|
||||
}
|
||||
|
||||
fn row_for(agent: &AgentDef, entry: Option<&InstalledEntry>, probe: &ExternalInfo) -> AgentRow {
|
||||
let (status, source, path, version, running, pid, method) = if let Some(e) = entry {
|
||||
let running = e.pid.map(crate::process::is_running).unwrap_or(false);
|
||||
let status = if running { "running" } else { "installed" };
|
||||
let path = if e
|
||||
.bins
|
||||
.first()
|
||||
.map(|b| std::path::Path::new(b).exists())
|
||||
.unwrap_or(false)
|
||||
{
|
||||
Some(e.bins[0].clone())
|
||||
} else {
|
||||
Some(e.install_dir.clone())
|
||||
};
|
||||
(
|
||||
status.to_string(),
|
||||
"managed".to_string(),
|
||||
path,
|
||||
e.version.clone(),
|
||||
running,
|
||||
e.pid,
|
||||
Some(e.method.clone()),
|
||||
)
|
||||
} else if !agent.installable {
|
||||
(
|
||||
"not-installable".to_string(),
|
||||
"-".to_string(),
|
||||
None,
|
||||
None,
|
||||
false,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
} else {
|
||||
match probe.path_of(&agent.name) {
|
||||
Some(p) => {
|
||||
let version = probe
|
||||
.version_of(&agent.name)
|
||||
.cloned()
|
||||
.flatten()
|
||||
.or_else(|| agent.version.clone());
|
||||
(
|
||||
"external".to_string(),
|
||||
"external".to_string(),
|
||||
Some(p.display().to_string()),
|
||||
version,
|
||||
false,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
}
|
||||
None => (
|
||||
"not-installed".to_string(),
|
||||
"-".to_string(),
|
||||
None,
|
||||
None,
|
||||
false,
|
||||
None,
|
||||
None,
|
||||
),
|
||||
}
|
||||
};
|
||||
AgentRow {
|
||||
name: agent.name.clone(),
|
||||
display_name: agent.title().to_string(),
|
||||
category: agent.category.clone(),
|
||||
description: agent.description.clone(),
|
||||
status,
|
||||
version,
|
||||
source,
|
||||
method,
|
||||
path,
|
||||
running,
|
||||
pid,
|
||||
installable: agent.installable,
|
||||
note: agent.note.clone(),
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user