neural/rs/cli/src/main.rs

//! neu — the neural CLI (slice-1).
//!
//! Speak one sentence, land it as a typed relation on the local cell, read it
//! back. neu is a *client of the cell*: it parses (sigil) → expands (dialect) →
//! writes through [`cyb_core::Cell`], and reads via inf. It holds no runtime of
//! its own.
//!
//! ```text
//! neu "cat is-a animal"   # speak: parse → expand → land on the cell
//! neu focus               # read: the graph's nodes by energy
//! ```

use std::path::PathBuf;

use cyb_core::Cell;
use cybergraph::Particle;

/// One directed cyberlink: `from → to`.
type Edge = (Particle, Particle);

/// The authoring neuron. Slice-1 uses a fixed local identity; a real key +
/// `H(secret)=address` proof (mudra) lands later.
fn neuron() -> Particle {
    sigil::word_particle("@you")
}

/// Where the durable cell logs its signals. Override with `NEU_LOG`.
fn graph_path() -> PathBuf {
    std::env::var("NEU_LOG")
        .map(PathBuf::from)
        .unwrap_or_else(|_| std::env::temp_dir().join("neu").join("graph.log"))
}

/// Parse → expand → land the sentence as **one atomic signal** on the cell.
/// Returns the edges staked. A sentence lands whole or not at all — the dialect
/// builds the base link and its axon-type link, and both ride one signal.
fn speak(cell: &mut Cell, input: &str) -> Result<Vec<Edge>, String> {
    let sentence = sigil::parse(input).map_err(|e| e.to_string())?;
    let edges = dialect::expand(&sentence);
    cell.cast(neuron(), edges.iter().copied()).map_err(|e| format!("{e:?}"))?;
    Ok(edges)
}

/// First 4 bytes of a particle, hex — enough to eyeball identity in the demo.
fn short(p: &Particle) -> String {
    p[..4].iter().map(|b| format!("{b:02x}")).collect()
}

fn main() {
    let args: Vec<String> = std::env::args().skip(1).collect();
    let mut cell = Cell::open(graph_path()).expect("open cell");

    match args.first().map(String::as_str) {
        None | Some("focus") => {
            let mut nodes = cell.nodes();
            nodes.sort_by(|a, b| b.1.cmp(&a.1));
            println!("● focus — {} particles, {} axons", cell.particles(), cell.axons().len());
            for (p, energy) in nodes.iter().take(20) {
                println!("  {}  energy {energy}", short(p));
            }
        }
        _ => {
            let input = args.join(" ");
            match speak(&mut cell, &input) {
                Ok(edges) => {
                    println!("● spoke: {input}");
                    println!("  base  {}{}", short(&edges[0].0), short(&edges[0].1));
                    println!(
                        "  type  {}{}   (on the axon of the pair)",
                        short(&edges[1].0),
                        short(&edges[1].1)
                    );
                }
                Err(e) => {
                    eprintln!("✗ {e}");
                    std::process::exit(1);
                }
            }
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn speak_lands_a_typed_relation() {
        let mut cell = Cell::ephemeral();
        let edges = speak(&mut cell, "cat is-a animal").expect("speak");
        assert_eq!(edges.len(), 2, "base link + axon-type link");

        let cat = sigil::word_particle("cat");
        let animal = sigil::word_particle("animal");
        let is_a = sigil::word_particle("is-a");

        // the base pair: the object particle materialized
        assert!(cell.has_particle(&animal), "object particle exists");

        // the relation is a link ON the axon of (cat, animal) — the settled model
        let axon = bbg::state::axon_id(&cat, &animal);
        assert!(
            cell.axons().iter().any(|(from, to, _)| *from == axon && *to == is_a),
            "typed relation staked: axon(cat,animal) → is_a"
        );

        // the read path runs
        cell.query("?[particle, energy] := particles{particle, energy}").expect("query runs");
    }

    #[test]
    fn ill_formed_sentence_is_rejected() {
        let mut cell = Cell::ephemeral();
        assert!(speak(&mut cell, "cat animal").is_err(), "a non-triple is not a sentence");
    }

    #[test]
    fn sentence_is_one_atomic_signal() {
        let mut cell = Cell::ephemeral();
        let before = cell.len();
        let edges = speak(&mut cell, "cat is-a animal").expect("speak");
        assert_eq!(edges.len(), 2, "two links");
        // ...but ONE signal — the whole sentence is atomic, not two commits
        assert_eq!(cell.len() - before, 1, "the sentence lands as one signal, not two");

        // and that one signal still carries both the base link and its axon-type
        let cat = sigil::word_particle("cat");
        let animal = sigil::word_particle("animal");
        let is_a = sigil::word_particle("is-a");
        let axon = bbg::state::axon_id(&cat, &animal);
        assert!(cell.has_particle(&animal), "base link landed");
        assert!(
            cell.axons().iter().any(|(from, to, _)| *from == axon && *to == is_a),
            "axon-type link landed in the same signal"
        );
    }
}

Homonyms

cyberia/src/main.rs
soft3/glia/import/main.rs
soft3/tru/cli/main.rs
warriors/trisha/cli/main.rs
soft3/nox/cli/main.rs
cyb/optica/src/main.rs
neural/trident/src/main.rs
cyb/src-tauri/src/main.rs
neural/rune/cli/main.rs
cyb/cyb-boot/src/main.rs
cyb/cyb/cyb-portal/src/main.rs
soft3/zheng/cli/src/main.rs
soft3/radio/radio-cli/src/main.rs
neural/rs/rsc/src/main.rs
cyb/cyb/cyb-ui/src/main.rs
soft3/bbg/cli/src/main.rs
neural/eidos/cli/src/main.rs
soft3/cybergraph/cli/src/main.rs
soft3/radio/particle/src/main.rs
soft3/lens/cli/src/main.rs
cyb/cyb/cyb-shell/src/main.rs
neural/rs/link/src/main.rs
soft3/radio/iroh-relay/src/main.rs
soft3/hemera/cli/src/main.rs
soft3/foculus/src/bin/main.rs
neural/rs/macho-linker/src/main.rs
neural/rs/pure-rust-check/src/main.rs
soft3/radio/iroh-dns-server/src/main.rs
soft3/glia/run/cli/main.rs
soft3/strata/jali/cli/src/main.rs
bootloader/go-cyber/mcp/rust/src/main.rs
soft3/strata/nebu/cli/src/main.rs
cyb/wysm/crates/cli/src/main.rs
soft3/strata/trop/cli/src/main.rs
neural/inf/rs/cli/src/main.rs
cyb/honeycrisp/rane/src/probe/main.rs
soft3/strata/kuro/cli/src/main.rs
soft3/strata/genies/cli/src/main.rs
cyb/honeycrisp/acpu/src/probe/main.rs
cyb/honeycrisp/unimem/experiments/iosurface_probe/src/main.rs
cyb/honeycrisp/unimem/experiments/hyp_probe/src/main.rs
cyb/honeycrisp/unimem/experiments/dext_contiguous_alloc/client/src/main.rs
cyb/honeycrisp/unimem/experiments/dext_iosurface_pa/client/src/main.rs

Graph