huskies: merge 921

This commit is contained in:
dave
2026-05-12 21:04:33 +00:00
parent 69d91d7707
commit 93443e2ff1
3 changed files with 101 additions and 6 deletions
+76
View File
@@ -215,6 +215,82 @@ pub async fn fetch_all_project_pipeline_statuses(
join_all(futures).await.into_iter().collect()
}
/// Fetch pipeline items for a single project URL.
///
/// Returns `{ "active": [...], "backlog_count": N }` preserving individual
/// story items so the gateway UI can render them. On error returns
/// `{ "error": "..." }`. This is distinct from
/// `fetch_one_project_pipeline_status` which discards items and returns
/// aggregated counts.
pub async fn fetch_one_project_pipeline_items(url: &str, client: &Client) -> Value {
let mcp_url = format!("{}/mcp", url.trim_end_matches('/'));
let rpc_body = json!({
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "get_pipeline_status",
"arguments": {}
}
});
match client.post(&mcp_url).json(&rpc_body).send().await {
Ok(resp) => match resp.json::<Value>().await {
Ok(upstream) => {
if let Some(text) = upstream
.get("result")
.and_then(|r| r.get("content"))
.and_then(|c| c.get(0))
.and_then(|c| c.get("text"))
.and_then(|t| t.as_str())
{
match serde_json::from_str::<Value>(text) {
Ok(pipeline) => {
let active = pipeline.get("active").cloned().unwrap_or(json!([]));
let backlog_count = pipeline
.get("backlog_count")
.and_then(|n| n.as_u64())
.unwrap_or(0);
json!({ "active": active, "backlog_count": backlog_count })
}
Err(_) => json!({ "error": "invalid pipeline JSON" }),
}
} else {
json!({ "error": "unexpected response shape" })
}
}
Err(e) => json!({ "error": format!("invalid response: {e}") }),
},
Err(e) => json!({ "error": format!("unreachable: {e}") }),
}
}
/// Fetch pipeline items from every registered project URL in parallel.
///
/// Returns per-project `{ "active": [...], "backlog_count": N }` objects
/// suitable for the gateway web UI.
pub async fn fetch_all_project_pipeline_items(
project_urls: &BTreeMap<String, String>,
client: &Client,
) -> BTreeMap<String, Value> {
use futures::future::join_all;
let futures: Vec<_> = project_urls
.iter()
.map(|(name, url)| {
let name = name.clone();
let url = url.clone();
let client = client.clone();
async move {
let result = fetch_one_project_pipeline_items(&url, &client).await;
(name, result)
}
})
.collect();
join_all(futures).await.into_iter().collect()
}
/// Fetch the pipeline status from a single project for the `gateway_status` tool.
pub async fn fetch_pipeline_status_for_project(
client: &Client,