tail-fin-daemon 0.5.0

Long-running browser-session daemon for tail-fin (tfd binary). Keeps Chrome tabs warm across invocations via a Unix-socket protocol; registers Site implementations through a runtime Arc<dyn Site> registry.
Documentation
use night_fury_core::BrowserSession;
use night_fury_daemon_core::protocol::Response;
use serde_json::{json, Value};
use tail_fin_grok::GrokClient;

pub async fn handle(session: &BrowserSession, id: &str, cmd: &str, params: &Value) -> Response {
    let client = GrokClient::new(session.clone());

    match cmd {
        "grok.ask" => {
            let prompt = match params.get("prompt").and_then(|v| v.as_str()) {
                Some(p) => p.to_string(),
                None => return Response::err(id, "missing required param 'prompt'"),
            };
            let timeout = params.get("timeout").and_then(|v| v.as_u64()).unwrap_or(30);
            match client.ask(&prompt, timeout).await {
                Ok(resp) => match serde_json::to_value(&resp) {
                    Ok(v) => Response::ok(id, v),
                    Err(e) => Response::err(id, format!("serialize: {e}")),
                },
                Err(e) => Response::err(id, e.to_string()),
            }
        }
        "grok.conversations" => match client.list_conversations().await {
            Ok(convs) => match serde_json::to_value(&convs) {
                Ok(v) => Response::ok(id, json!({"conversations": v})),
                Err(e) => Response::err(id, format!("serialize: {e}")),
            },
            Err(e) => Response::err(id, e.to_string()),
        },
        other => Response::err(id, format!("unknown grok cmd: {other}")),
    }
}