update plugin marketplaces before install at harness boot

This commit is contained in:
damocles 2026-05-16 18:49:11 +02:00
parent dc53615686
commit f3739d2b8e

View file

@ -6,6 +6,10 @@
//! is expected to be idempotent so reinstalling on each container //! is expected to be idempotent so reinstalling on each container
//! recreate is fine. Failures log a warning but do not abort boot — //! recreate is fine. Failures log a warning but do not abort boot —
//! we'd rather start without a plugin than refuse to serve. //! we'd rather start without a plugin than refuse to serve.
//!
//! Before installing, all configured marketplaces are updated so that
//! plugin specs resolve against current index data. Marketplace update
//! failures are non-fatal — stale index is better than no install attempt.
use std::path::Path; use std::path::Path;
@ -15,6 +19,30 @@ use crate::client;
const PLUGINS_PATH: &str = "/etc/hyperhive/claude-plugins.json"; const PLUGINS_PATH: &str = "/etc/hyperhive/claude-plugins.json";
/// Update all configured plugin marketplaces. Non-fatal — logs a warning
/// on failure but does not abort the install sequence.
async fn update_marketplaces() {
match Command::new("claude")
.args(["plugin", "marketplace", "update"])
.output()
.await
{
Ok(out) if out.status.success() => {
tracing::info!("claude plugin marketplace update ok");
}
Ok(out) => {
tracing::warn!(
status = ?out.status,
stderr = %String::from_utf8_lossy(&out.stderr),
"claude plugin marketplace update failed (non-fatal)",
);
}
Err(e) => {
tracing::warn!(error = ?e, "claude plugin marketplace update spawn failed (non-fatal)");
}
}
}
/// Install every plugin in `/etc/hyperhive/claude-plugins.json`. When /// Install every plugin in `/etc/hyperhive/claude-plugins.json`. When
/// `notify_recipient` is `Some(name)`, install failures also get sent /// `notify_recipient` is `Some(name)`, install failures also get sent
/// as a hyperhive message to that recipient (typically `"manager"` for /// as a hyperhive message to that recipient (typically `"manager"` for
@ -33,6 +61,10 @@ pub async fn install_configured(socket: &Path, notify_recipient: Option<&str>) {
return; return;
} }
}; };
if specs.is_empty() {
return;
}
update_marketplaces().await;
for spec in specs { for spec in specs {
match Command::new("claude") match Command::new("claude")
.args(["plugin", "install", &spec]) .args(["plugin", "install", &spec])