liminal-cli 0.3.23

The liminal command: serve the network, maintain its stores, or serve its discovery MCP over stdio
Documentation
//! The exchange fixture's agent records: alpha and beta placed by an approved draft, and a
//! sender's rights on the inbox of a station nobody placed (gamma, ACCESS-013 R4).

use lys_pass::{Mode, Right};

/// A sender's rights on gamma's inbox: publish on the subject and message on the station. Gamma
/// itself holds none, so its own listen is admitted on its identity alone.
pub(super) fn gamma_sender(holder: &str) -> Vec<Right> {
    if holder == "gamma" {
        return Vec::new();
    }
    let right = |kind: &str, id: &str, action: &str| Right {
        resource: lys_pass::rights::Resource {
            kind: kind.to_owned(),
            id: id.to_owned(),
        },
        actions: vec![action.to_owned()],
        mode: Mode::Outright,
        grant: "agt-fixture".to_owned(),
    };
    vec![
        right("liminal.subject", "agents.gamma.inbox", "publish"),
        right("liminal.agent", "gamma", "message"),
    ]
}

#[derive(Debug)]
pub(super) struct AgentPlacement;
impl liminal_server::services::lifecycle::Placer for AgentPlacement {
    fn place(
        &self,
        _operation: &str,
        child: (&str, &str),
        parent: (&str, &str),
    ) -> Result<(), String> {
        if child.1.is_empty()
            || parent.1.is_empty()
            || !matches!(child.0, "liminal.agent" | "liminal.subject")
        {
            return Err("fixture placement refused".into());
        }
        Ok(())
    }
}
pub(super) fn provision_agents(
    services: &liminal_server::server::connection::LiminalConnectionServices,
) -> super::channel_test_support::TestResult {
    use liminal_server::agents::records::{AgentAct, AgentEvent, AgentHarness, AgentSpec};
    use liminal_server::server::connection::ConnectionServices;
    let agents = services.agents().ok_or("fixture agents missing")?;
    for name in ["alpha", "beta"] {
        let words = serde_json::to_string(&AgentAct {
            name: name.into(),
            holder: "fixture-person".into(),
            owner: "fixture-person".into(),
            at_ms: 1,
            change: AgentEvent::Create(AgentSpec {
                harness: AgentHarness::Cdx,
                purpose: "Exchange contract fixture.".into(),
                service: None,
            }),
        })?;
        let draft = lys_pass::drafts::ApprovedDraft {
            id: format!("create-{name}"),
            app: "liminal".into(),
            grant: "fixture-approved".into(),
            target: lys_pass::Target::new("liminal.agent", name, "create_agent")?,
            request_digest: lys_pass::drafts::request_digest(&words),
            approved_by: vec!["fixture-owner".into()],
            mode: lys_pass::Mode::ByDraft,
            words,
        };
        agents.execute_approved(&draft)?;
        services.agent_created(name)?;
    }
    Ok(())
}