Skip to main content

scc_engine/
rpc.rs

1//! stdio JSON-RPC: newline-delimited requests, same registry.
2//!
3//! Request:  {"id": 1, "operation": "context.task", "input": {...}}
4//! Response: {"id": 1, "output": {...}} | {"id": 1, "error": "..."}
5//! Plus `operations.list` / `operations.describe` meta-operations.
6//! SDK subprocess mode speaks this — never CLI text.
7
8// trace:exempt reason=internal-detail
9pub 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}