diff --git a/crates/studio-cp/src/lib.rs b/crates/studio-cp/src/lib.rs index 27be58a..559b674 100644 --- a/crates/studio-cp/src/lib.rs +++ b/crates/studio-cp/src/lib.rs @@ -1783,6 +1783,74 @@ fn write_local_agent_config(folder: &str, name: &str, config_toml: &[u8]) -> any .map_err(|e| anyhow::anyhow!("failed to write {}: {e}", path.display())) } +/// Minimum openab release version (`X.Y.Z[-beta.N]`) that ships `/acp` +/// gateway support (`crates/openab-gateway/src/adapters/acp_server.rs` — +/// confirmed absent through `0.10.0-beta.1`, present from `0.10.0-beta.2` +/// onward, openab#1418). +const MIN_ACP_VERSION: (u32, u32, u32, u32) = (0, 10, 0, 2); + +/// Parses the `X.Y.Z` or `X.Y.Z-beta.N` version prefix of an openab release +/// tag into a tuple ordered so a final release outranks every beta of the +/// same `X.Y.Z` (`beta` defaults to `u32::MAX` when absent — `0.10.0` sorts +/// after `0.10.0-beta.4`). Returns `None` for anything that doesn't match +/// this shape — a custom/non-openab image the caller supplied directly, +/// which [`check_acp_image_compat`] deliberately lets through rather than +/// guessing, same "can't verify, don't block" stance `resolve_vendor_image_tags` +/// already takes on a failed GHCR/GitHub lookup. +fn parse_openab_version(v: &str) -> Option<(u32, u32, u32, u32)> { + let (base, beta) = match v.split_once("-beta.") { + Some((b, n)) => (b, n.parse().ok()?), + None => (v, u32::MAX), + }; + let mut parts = base.split('.'); + let major = parts.next()?.parse().ok()?; + let minor = parts.next()?.parse().ok()?; + let patch = parts.next()?.parse().ok()?; + if parts.next().is_some() { + return None; // trailing junk after the third component + } + Some((major, minor, patch, beta)) +} + +/// Refuses an ACP-only deploy (`acp_enabled` true, no `chat_platform` — ACP +/// is this agent's *only* connection path) onto an image that predates +/// `/acp` gateway support: it would boot with zero adapters configured and +/// crash (`Error: no adapter configured...`). studio#153 already guards the +/// New Fleet wizard's Image-tag `