swactor/crates/runtime-dashboard/src/investigate.rs

72 lines
2.1 KiB
Rust
Raw Normal View History

//! Line-oriented diagnostic protocol for LLM-driven runtime investigation.
//!
2026-02-13 07:42:44 +00:00
//! Delegates all command logic to the `swactor-command` crate.
//!
//! Send text commands on stdin, receive JSON responses on stdout (one per line).
//! All human-readable diagnostics go to stderr.
//!
//! # Protocol
//!
//! ```text
//! → overview
//! ← {"ok":true,"command":"overview","data":{"workers":4,"actors":120,...}}
//!
//! → hot 5
//! ← {"ok":true,"command":"hot","data":[{"address":"a1b2...","worker_id":2,"mailbox_depth":47},..]}
//!
//! → diff 2
//! ← {"ok":true,"command":"diff","data":{"elapsed_s":2.0,"delta_messages":8432,"msg_per_sec":4216.0,...}}
//! ```
use std::collections::HashMap;
use std::io::{self, BufRead, Write};
use std::sync::Arc;
use swactor::runtime::Runtime;
2026-02-13 07:42:44 +00:00
use swactor_command::{CommandContext, CommandRouter};
use crate::collector::StatsCollector;
/// Run the investigate REPL. Blocks until stdin is closed or `quit` is received.
pub fn run_investigate(runtime: Arc<Runtime>, collector: Arc<StatsCollector>) -> io::Result<()> {
2026-02-13 07:42:44 +00:00
let router = CommandRouter::with_builtins();
let ctx = CommandContext::with_enricher(runtime, collector);
let stdin = io::stdin();
let mut stdout = io::stdout();
eprintln!("swactor investigate protocol ready — send `help` for commands");
for line in stdin.lock().lines() {
let line = line?;
let line = line.trim();
if line.is_empty() {
continue;
}
2026-02-13 07:42:44 +00:00
if line == "quit" || line == "exit" {
break;
}
2026-02-13 07:42:44 +00:00
let req = swactor_command::parse_line(line);
let resp = router.dispatch(&req, &ctx);
2026-02-13 07:42:44 +00:00
stdout.write_all(resp.to_json_line().as_bytes())?;
stdout.write_all(b"\n")?;
stdout.flush()?;
}
Ok(())
}
/// Dispatch an investigate command from HTTP query parameters.
///
2026-02-13 07:42:44 +00:00
/// Maps `?cmd=overview`, `?cmd=hot&n=10`, etc. to the appropriate command.
pub fn dispatch_command(
params: &HashMap<String, String>,
2026-02-13 07:42:44 +00:00
router: &CommandRouter,
ctx: &CommandContext,
) -> String {
2026-02-13 07:42:44 +00:00
let req = swactor_command::from_query_params(params);
router.dispatch(&req, ctx).to_json_line()
}