1pub fn serve_stdio(root: &std::path::Path) -> crate::Result<()> {
10 use std::io::BufRead;
11 let stdin = std::io::stdin();
12 let mut line = String::new();
13 let mut lock = stdin.lock();
14 loop {
15 line.clear();
16 let n = lock.read_line(&mut line)?;
17 if n == 0 {
18 break;
19 }
20 let line = line.trim();
21 if line.is_empty() {
22 continue;
23 }
24 let msg: serde_json::Value = match serde_json::from_str(line) {
25 Ok(v) => v,
26 Err(e) => {
27 println!("{}", serde_json::json!({"id": null, "error": format!("invalid JSON: {e}")}));
28 continue;
29 }
30 };
31 let id = msg.get("id").cloned().unwrap_or(serde_json::Value::Null);
32 let op = msg.get("operation").and_then(|o| o.as_str()).unwrap_or("");
33 let input = msg.get("input").cloned().unwrap_or(serde_json::json!({}));
34 if op == "operations.list" {
35 let ids: Vec<&str> = crate::ops::ids();
36 println!("{}", serde_json::json!({"id": id, "output": {"operations": ids, "api_version": scc_api::API_VERSION}}));
37 continue;
38 }
39 if op == "operations.describe" {
40 let target = input.get("id").and_then(|v| v.as_str()).unwrap_or(op);
41 match crate::ops::describe(target) {
42 Some(d) => println!("{}", serde_json::json!({"id": id, "output": d})),
43 None => println!("{}", serde_json::json!({"id": id, "error": format!("unknown operation '{target}'")})),
44 }
45 continue;
46 }
47 match crate::invoke(root, op, input) {
48 Ok(output) => println!("{}", serde_json::json!({"id": id, "output": output})),
49 Err(e) => println!("{}", serde_json::json!({"id": id, "error": e.to_string()})),
50 }
51 }
52 Ok(())
53}