haematite-cli 0.21.3

The haematite command: serve a store, its door and Studio, answer MCP, query with jq, and host the store's assistant seat
Documentation
use super::{
    config::Seat,
    door_link::Link,
    handshake::{Session, Version},
    tools::Identity,
};
use serde_json::json;
use tokio::io::{AsyncBufReadExt as _, AsyncWriteExt as _, BufReader};

#[tokio::test]
async fn r1_door_open_combines_the_bound_hello_and_welcome() -> anyhow::Result<()> {
    use std::os::unix::fs::PermissionsExt as _;
    let directory = tempfile::tempdir()?;
    let socket = directory.path().join("door.sock");
    let listener = tokio::net::UnixListener::bind(&socket)?;
    std::fs::set_permissions(&socket, std::fs::Permissions::from_mode(0o600))?;
    let server = tokio::spawn(async move {
        let mut peer = BufReader::new(listener.accept().await?.0);
        let mut line = String::new();
        peer.read_line(&mut line).await?;
        let hello: serde_json::Value = serde_json::from_str(&line)?;
        assert_eq!(hello["hello"]["agent"], "fixture-agent");
        peer.get_mut()
            .write_all(b"{\"welcome\":{\"person\":\"fixture-person\"}}\n")
            .await?;
        peer.get_mut().shutdown().await?;
        Ok::<_, anyhow::Error>(())
    });
    let seat: Seat = serde_json::from_value(
        json!({"harness":{"id":"codex","program":"/bin/true","args":[]},"door_socket":socket,"serve_config":"/tmp/serve.json","key_file":"/tmp/agent.key","issuer":"http://127.0.0.1:1","store":"fixture"}),
    )?;
    let identity = Identity {
        agent: "fixture-agent".to_owned(),
        launch: "fixture-launch".to_owned(),
        pass: "fixture-pass".to_owned(),
    };
    let session = Session {
        id: String::new(),
        version: Version::One,
        resumable: false,
        capability: "agentCapabilities.loadSession",
        updates: Vec::new(),
        config: json!([]),
        info: json!({}),
    };
    let mut link = Link::open(&seat, &identity, &session).await?;
    assert_eq!(link.person, "fixture-person");
    server.await??;
    super::closing::stop(&mut link.reader, "door_reader").await?;
    super::closing::stop(&mut link.writer, "door_writer")
        .await?
        .unwrap_or(Ok(()))?;
    Ok(())
}