kiromi-ai-cli 0.2.2

Operator and developer CLI for the kiromi-ai-memory store: append, search, snapshot, regenerate, migrate-scheme, gc, audit-tail.
// SPDX-License-Identifier: Apache-2.0 OR MIT
#![allow(clippy::unwrap_used, clippy::expect_used, clippy::panic, missing_docs)]

mod common;

use common::CliWorkspace;

fn append_one(ws: &CliWorkspace) -> String {
    let out = ws
        .cmd()
        .args([
            "append",
            "--partition",
            "user=alex,year=2026,month=05,topic=meetings",
            "--message",
            "hello",
        ])
        .output()
        .unwrap();
    assert!(out.status.success(), "append failed: {out:?}");
    String::from_utf8(out.stdout).unwrap().trim().to_string()
}

#[test]
fn attribute_set_and_get_round_trips() {
    let ws = CliWorkspace::new();
    assert!(ws.init().status.success());
    let id = append_one(&ws);

    let out = ws
        .cmd()
        .args([
            "attribute",
            "set",
            "--memory",
            &id,
            "--key",
            "speaker",
            "--value",
            "alex",
        ])
        .output()
        .unwrap();
    assert!(out.status.success(), "set failed: {out:?}");

    let out = ws
        .cmd()
        .args(["attribute", "get", "--memory", &id, "--key", "speaker"])
        .output()
        .unwrap();
    assert!(out.status.success(), "get failed: {out:?}");
    let body = String::from_utf8(out.stdout).unwrap();
    assert!(body.contains("alex"), "got {body:?}");
}

#[test]
fn attribute_list_emits_json() {
    let ws = CliWorkspace::new();
    assert!(ws.init().status.success());
    let id = append_one(&ws);
    ws.cmd()
        .args([
            "attribute",
            "set",
            "--memory",
            &id,
            "--key",
            "seq",
            "--kind",
            "int",
            "--value",
            "7",
        ])
        .output()
        .unwrap();
    let out = ws
        .cmd()
        .args(["--json", "attribute", "list", "--memory", &id])
        .output()
        .unwrap();
    assert!(out.status.success(), "list failed: {out:?}");
    let parsed: serde_json::Value = serde_json::from_slice(&out.stdout).unwrap();
    assert!(parsed.get("seq").is_some(), "{parsed:?}");
}

#[test]
fn attribute_find_by_string_key() {
    let ws = CliWorkspace::new();
    assert!(ws.init().status.success());
    let id = append_one(&ws);
    ws.cmd()
        .args([
            "attribute",
            "set",
            "--memory",
            &id,
            "--key",
            "speaker",
            "--value",
            "alex",
        ])
        .output()
        .unwrap();
    let out = ws
        .cmd()
        .args(["attribute", "find", "--key", "speaker", "--value", "alex"])
        .output()
        .unwrap();
    assert!(out.status.success(), "find failed: {out:?}");
    let body = String::from_utf8(out.stdout).unwrap();
    assert!(body.contains(&id), "expected {id} in {body:?}");
}

#[test]
fn attribute_find_range_by_int() {
    let ws = CliWorkspace::new();
    assert!(ws.init().status.success());
    let id = append_one(&ws);
    ws.cmd()
        .args([
            "attribute",
            "set",
            "--memory",
            &id,
            "--key",
            "seq",
            "--kind",
            "int",
            "--value",
            "50",
        ])
        .output()
        .unwrap();
    let out = ws
        .cmd()
        .args([
            "attribute",
            "find-range",
            "--key",
            "seq",
            "--kind",
            "int",
            "--min",
            "0",
            "--max",
            "100",
        ])
        .output()
        .unwrap();
    assert!(out.status.success(), "find-range failed: {out:?}");
    let body = String::from_utf8(out.stdout).unwrap();
    assert!(body.contains(&id), "expected {id} in {body:?}");
}