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,103 @@
|
||||
//! Binary installer: download a precompiled binary (direct URL or GitHub
|
||||
//! Releases asset), verify its checksum, extract it if needed, and install
|
||||
//! it into the global bin directory.
|
||||
|
||||
use super::*;
|
||||
|
||||
pub fn install(
|
||||
app: &App,
|
||||
agent: &AgentDef,
|
||||
method: &MethodSpec,
|
||||
runner: &dyn Runner,
|
||||
) -> Result<InstallOutcome> {
|
||||
let root = install_root(app, &agent.name);
|
||||
let dist = root.join("dist");
|
||||
let bindir = bin_dir(app);
|
||||
ensure_dir(app, &root)?;
|
||||
ensure_dir(app, &dist)?;
|
||||
ensure_dir(app, &bindir)?;
|
||||
|
||||
// Resolve the download URL (direct or GitHub release asset).
|
||||
let (url, tag): (String, Option<String>) = if let Some(u) = &method.url {
|
||||
(u.clone(), None)
|
||||
} else if let Some(repo) = &method.repo {
|
||||
let release = crate::download::latest_release(repo)?;
|
||||
let picked = crate::download::pick_asset(
|
||||
&release,
|
||||
&method.asset_match,
|
||||
&method.asset_exclude,
|
||||
method.binary.as_deref(),
|
||||
)
|
||||
.ok_or_else(|| {
|
||||
anyhow!(
|
||||
"no release asset of '{repo}' matches this platform ({}/{})",
|
||||
crate::config::current_platform(),
|
||||
std::env::consts::ARCH
|
||||
)
|
||||
})?;
|
||||
app.log
|
||||
.info(&format!("selected asset: {} ({})", picked.name, picked.tag));
|
||||
(
|
||||
picked.url,
|
||||
Some(picked.tag.trim_start_matches('v').to_string()),
|
||||
)
|
||||
} else {
|
||||
bail!("binary install requires 'url' or 'repo' (GitHub owner/repo)");
|
||||
};
|
||||
|
||||
let names = expected_bin_names(agent, method);
|
||||
let bin_name = names
|
||||
.first()
|
||||
.cloned()
|
||||
.unwrap_or_else(|| agent.name.clone());
|
||||
let dest_bin = bindir.join(exe_name(&bin_name));
|
||||
|
||||
if app.dry_run() {
|
||||
app.log
|
||||
.dry(format!("would download {url} and install {}", dest_bin.display()));
|
||||
return Ok(InstallOutcome {
|
||||
bins: vec![dest_bin],
|
||||
version: tag,
|
||||
});
|
||||
}
|
||||
|
||||
let tmpdir = tempfile::tempdir()?;
|
||||
let tmpfile = tmpdir.path().join("download");
|
||||
crate::download::download(&url, &tmpfile, method.checksum.as_deref(), true)?;
|
||||
if crate::download::extract_archive(&tmpfile, &dist)? {
|
||||
let found = crate::download::find_executable(&dist, Some(&bin_name))?;
|
||||
std::fs::copy(&found, &dest_bin).with_context(|| {
|
||||
format!("cannot copy {} to {}", found.display(), dest_bin.display())
|
||||
})?;
|
||||
app.log
|
||||
.info(&format!("extracted {} -> {}", found.display(), dest_bin.display()));
|
||||
} else {
|
||||
std::fs::copy(&tmpfile, &dest_bin).with_context(|| {
|
||||
format!("cannot copy {} to {}", tmpfile.display(), dest_bin.display())
|
||||
})?;
|
||||
}
|
||||
#[cfg(unix)]
|
||||
{
|
||||
use std::os::unix::fs::PermissionsExt;
|
||||
let _ = std::fs::set_permissions(&dest_bin, std::fs::Permissions::from_mode(0o755));
|
||||
}
|
||||
let version = detect_version(runner, &dest_bin).or(tag);
|
||||
Ok(InstallOutcome {
|
||||
bins: vec![dest_bin],
|
||||
version,
|
||||
})
|
||||
}
|
||||
|
||||
/// Latest release tag (without the leading "v").
|
||||
pub fn latest(
|
||||
_app: &App,
|
||||
_agent: &AgentDef,
|
||||
method: &MethodSpec,
|
||||
_runner: &dyn Runner,
|
||||
) -> Result<Option<String>> {
|
||||
let Some(repo) = method.repo.as_deref() else {
|
||||
return Ok(None);
|
||||
};
|
||||
let release = crate::download::latest_release(repo)?;
|
||||
Ok(Some(release.tag_name.trim_start_matches('v').to_string()))
|
||||
}
|
||||
Reference in New Issue
Block a user