Peeks at the first stdin line to read the MCP `initialize` request's `roots` array, returning the local workspace root paths. The raw line is stored in `out` so the caller can replay it into the MCP transport (the server still needs to see it).
(out: &mut Option<String>)
| 257 | /// stored in `out` so the caller can replay it into the MCP transport (the |
| 258 | /// server still needs to see it). |
| 259 | async fn read_initialize_roots(out: &mut Option<String>) -> Vec<std::path::PathBuf> { |
| 260 | let Some(line) = read_first_non_empty_stdin_line().await else { |
| 261 | return Vec::new(); |
| 262 | }; |
| 263 | *out = Some(line.trim().to_string()); |
| 264 | |
| 265 | let Ok(parsed) = serde_json::from_str::<serde_json::Value>(line.trim()) else { |
| 266 | return Vec::new(); |
| 267 | }; |
| 268 | let Some(roots) = parsed.pointer("/params/roots").and_then(|v| v.as_array()) else { |
| 269 | return Vec::new(); |
| 270 | }; |
| 271 | roots |
| 272 | .iter() |
| 273 | .filter_map(|root| { |
| 274 | let uri = root.get("uri").and_then(|v| v.as_str())?; |
| 275 | local_path_from_mcp_root_uri(uri) |
| 276 | }) |
| 277 | .collect() |
| 278 | } |
| 279 | |
| 280 | /// Resolves a project from MCP `initialize` workspace roots: a root that IS a |
| 281 | /// registered project wins, otherwise the nearest enclosing project of any |
no test coverage detected