huskies: merge 1153 story huskies projects chat command — list every registered project with port and status
This commit is contained in:
@@ -19,6 +19,7 @@ const GATEWAY_TOOLS: &[&str] = &[
|
||||
"switch_project",
|
||||
"gateway_status",
|
||||
"gateway_health",
|
||||
"list_projects",
|
||||
"init_project",
|
||||
"adopt_project",
|
||||
"aggregate_pipeline_status",
|
||||
@@ -65,6 +66,14 @@ pub(crate) fn gateway_tool_definitions() -> Vec<Value> {
|
||||
"properties": {}
|
||||
}
|
||||
}),
|
||||
json!({
|
||||
"name": "list_projects",
|
||||
"description": "List every registered gateway project with its name, url, ssh_port (if set), host_path (if set), and an adopted/built-in marker. The active project is prefixed with *. No liveness checks are performed.",
|
||||
"inputSchema": {
|
||||
"type": "object",
|
||||
"properties": {}
|
||||
}
|
||||
}),
|
||||
json!({
|
||||
"name": "init_project",
|
||||
"description": "Initialize a new huskies project at the given path by scaffolding .huskies/ and related files — the same as running `huskies init <path>`. Prefer this tool over asking the user to run the CLI. If `name` and `url` are supplied the project is also registered in projects.toml so switch_project can reach it immediately.",
|
||||
@@ -423,6 +432,7 @@ async fn handle_gateway_tool(
|
||||
"switch_project" => handle_switch_project_tool(params, state, id).await,
|
||||
"gateway_status" => handle_gateway_status_tool(state, id).await,
|
||||
"gateway_health" => handle_gateway_health_tool(state, id).await,
|
||||
"list_projects" => handle_list_projects_tool(state, id).await,
|
||||
"init_project" => handle_init_project_tool(params, state, id).await,
|
||||
"adopt_project" => handle_adopt_project_tool(params, state, id).await,
|
||||
"aggregate_pipeline_status" => handle_aggregate_pipeline_status_tool(state, id).await,
|
||||
@@ -539,6 +549,50 @@ async fn handle_gateway_health_tool(state: &GatewayState, id: Option<Value>) ->
|
||||
)
|
||||
}
|
||||
|
||||
/// Handle the `list_projects` gateway tool.
|
||||
///
|
||||
/// Returns one row per registered project: name, url, ssh_port (if set),
|
||||
/// host_path (if set), and an `[adopted]`/`[built-in]` marker. Output is
|
||||
/// alphabetised by project name (BTreeMap order). The active project is
|
||||
/// prefixed with `*`. No liveness checks are performed.
|
||||
async fn handle_list_projects_tool(state: &GatewayState, id: Option<Value>) -> JsonRpcResponse {
|
||||
let active = state.active_project.read().await.clone();
|
||||
let projects = state.projects.read().await;
|
||||
|
||||
if projects.is_empty() {
|
||||
return JsonRpcResponse::success(
|
||||
id,
|
||||
json!({ "content": [{ "type": "text", "text": "No projects registered." }] }),
|
||||
);
|
||||
}
|
||||
|
||||
let mut lines = Vec::with_capacity(projects.len() + 1);
|
||||
lines.push(format!("Projects ({} registered):", projects.len()));
|
||||
for (name, entry) in projects.iter() {
|
||||
let marker = if *name == active { "*" } else { " " };
|
||||
let mut parts = vec![name.clone()];
|
||||
if let Some(ref url) = entry.url {
|
||||
parts.push(url.clone());
|
||||
}
|
||||
if let Some(port) = entry.ssh_port {
|
||||
parts.push(format!("ssh:{port}"));
|
||||
}
|
||||
if let Some(ref path) = entry.host_path {
|
||||
parts.push(path.clone());
|
||||
}
|
||||
let adopted = if entry.host_path.is_some() {
|
||||
"[adopted]"
|
||||
} else {
|
||||
"[built-in]"
|
||||
};
|
||||
parts.push(adopted.to_string());
|
||||
lines.push(format!("{marker} {}", parts.join(" ")));
|
||||
}
|
||||
let text = lines.join("\n");
|
||||
|
||||
JsonRpcResponse::success(id, json!({ "content": [{ "type": "text", "text": text }] }))
|
||||
}
|
||||
|
||||
async fn handle_init_project_tool(
|
||||
params: &Value,
|
||||
state: &GatewayState,
|
||||
|
||||
Reference in New Issue
Block a user