From f3739d2b8e96da70a868dd2af4be3eb15138e3ba Mon Sep 17 00:00:00 2001 From: damocles Date: Sat, 16 May 2026 18:49:11 +0200 Subject: [PATCH] update plugin marketplaces before install at harness boot --- hive-ag3nt/src/plugins.rs | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/hive-ag3nt/src/plugins.rs b/hive-ag3nt/src/plugins.rs index f1302d0..00254f9 100644 --- a/hive-ag3nt/src/plugins.rs +++ b/hive-ag3nt/src/plugins.rs @@ -6,6 +6,10 @@ //! is expected to be idempotent so reinstalling on each container //! recreate is fine. Failures log a warning but do not abort boot — //! 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; @@ -15,6 +19,30 @@ use crate::client; 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 /// `notify_recipient` is `Some(name)`, install failures also get sent /// 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; } }; + if specs.is_empty() { + return; + } + update_marketplaces().await; for spec in specs { match Command::new("claude") .args(["plugin", "install", &spec])