File size: 11,228 Bytes
4ae5926
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
// cli.rs β€” `magma` command-line interface
//
// A thin client that talks to a running magmad daemon over REST.
// Ships as a separate binary so it can be installed alongside magmad.
//
// Usage:
//   magma health                        # ping the daemon
//   magma verify PUSH_UN PUSH_LIN SEAL  # ERRANT opcode trace
//   magma run program.meta              # stream a .meta file through BOB
//   magma seal "some event text"        # compute WORM hash and seal
//   magma talk "build the auth module"  # SSE orchestrate stream
//   magma chain                         # print current WORM chain head
//
// Daemon is assumed at http://127.0.0.1:3000 unless MAGMA_URL is set.

use std::io::{self, Write as IoWrite};
use std::path::PathBuf;
use anyhow::{Context, Result};
use clap::{Parser, Subcommand};
use reqwest::Client;
use serde_json::Value;

// ── Args ───────────────────────────────────────────────────────────────────────

#[derive(Parser)]
#[command(

    name    = "magma",

    version,

    about   = "Sovereign agentic runtime CLI",

    long_about = r#"

magma β€” SnapKitty Sovereign CLI

Talks to magmad (default http://127.0.0.1:3000).

Set MAGMA_URL to override.



Examples:

  magma health

  magma verify PUSH_UN PUSH_LIN SEAL

  magma run program.meta

  magma talk "deploy the auth module"

  magma seal "key-rotation-event-2026"

  magma chain

"#

)]
struct Cli {
    #[command(subcommand)]
    command: Command,
}

#[derive(Subcommand)]
enum Command {
    /// Health check β€” pings magmad and prints status
    Health,

    /// ERRANT opcode trace verification
    Verify {
        /// Opcodes to verify (e.g. PUSH_UN PUSH_LIN SEAL)
        #[arg(required = true)]
        opcodes: Vec<String>,
    },

    /// Source string verification
    Source {
        /// ERRANT source string
        code: String,
    },

    /// Run a .meta METAMINE file through the BOB pipeline (streams SSE)
    Run {
        /// Path to .meta file
        file: PathBuf,
        /// Action to pass to BOB routing (default: "build")
        #[arg(long, default_value = "build")]
        action: String,
        /// Print raw SSE events
        #[arg(long)]
        raw: bool,
    },

    /// SSE orchestration stream for a natural-language action
    Talk {
        /// Instruction (e.g. "deploy the auth module")
        instruction: String,
        /// Print raw SSE events
        #[arg(long)]
        raw: bool,
    },

    /// Seal an arbitrary string and print the WORM hash
    Seal {
        /// Text to seal
        text: String,
    },

    /// Print the current WORM chain head
    Chain,

    /// Print daemon version info
    Version,
}

// ── Main ───────────────────────────────────────────────────────────────────────

#[tokio::main]
async fn main() -> Result<()> {
    let cli = Cli::parse();
    let base_url = std::env::var("MAGMA_URL")
        .unwrap_or_else(|_| "http://127.0.0.1:3000".into());
    let client = Client::builder()
        .timeout(std::time::Duration::from_secs(30))
        .build()?;

    match cli.command {
        Command::Health  => cmd_health(&client, &base_url).await?,
        Command::Version => cmd_version(&client, &base_url).await?,
        Command::Chain   => cmd_chain(&client, &base_url).await?,

        Command::Verify { opcodes } => {
            cmd_verify(&client, &base_url, opcodes).await?
        }
        Command::Source { code } => {
            cmd_source(&client, &base_url, code).await?
        }
        Command::Run { file, action, raw } => {
            cmd_run(&client, &base_url, file, action, raw).await?
        }
        Command::Talk { instruction, raw } => {
            cmd_talk(&client, &base_url, instruction, raw).await?
        }
        Command::Seal { text } => {
            cmd_seal(&client, &base_url, text).await?
        }
    }

    Ok(())
}

// ── Commands ───────────────────────────────────────────────────────────────────

async fn cmd_health(client: &Client, base: &str) -> Result<()> {
    let resp: Value = client.get(format!("{base}/api/v1/health"))
        .send().await?.json().await?;
    print_health(&resp);
    Ok(())
}

async fn cmd_version(client: &Client, base: &str) -> Result<()> {
    let resp: Value = client.get(format!("{base}/api/v1/version"))
        .send().await?.json().await?;
    println!("magmad  {}", resp["magmad"].as_str().unwrap_or("?"));
    println!("liberrant {}", resp["liberrant"].as_str().unwrap_or("?"));
    println!("protocol  {}", resp["protocol"].as_str().unwrap_or("?"));
    Ok(())
}

async fn cmd_chain(client: &Client, base: &str) -> Result<()> {
    let resp: Value = client.get(format!("{base}/api/v1/chain/head"))
        .send().await?.json().await?;
    println!("head   {}", resp["head"].as_str().unwrap_or("?"));
    println!("source {}", resp["source"].as_str().unwrap_or("?"));
    Ok(())
}

async fn cmd_verify(client: &Client, base: &str, opcodes: Vec<String>) -> Result<()> {
    let body = serde_json::json!({ "opcodes": opcodes });
    let resp: Value = client.post(format!("{base}/api/v1/verify"))
        .json(&body).send().await?.json().await?;
    print_verify(&resp);
    Ok(())
}

async fn cmd_source(client: &Client, base: &str, code: String) -> Result<()> {
    let body = serde_json::json!({ "source": code });
    let resp: Value = client.post(format!("{base}/api/v1/verify"))
        .json(&body).send().await?.json().await?;
    print_verify(&resp);
    Ok(())
}

async fn cmd_run(
    client: &Client,
    base:   &str,
    file:   PathBuf,
    action: String,
    raw:    bool,
) -> Result<()> {
    let code = std::fs::read_to_string(&file)
        .with_context(|| format!("cannot read {}", file.display()))?;

    // Parse .meta β†’ opcode names (words only, ignore comments)
    let ops: Vec<String> = code
        .lines()
        .filter(|l| !l.trim_start().starts_with('#') && !l.trim_start().starts_with(';'))
        .flat_map(|l| l.split_whitespace())
        .filter(|w| !w.is_empty())
        .map(String::from)
        .collect();

    eprintln!("metamine: {} opcodes from {}", ops.len(), file.display());
    cmd_orchestrate(client, base, action, Some(ops), raw).await
}

async fn cmd_talk(
    client: &Client,
    base:   &str,
    instruction: String,
    raw: bool,
) -> Result<()> {
    cmd_orchestrate(client, base, instruction, None, raw).await
}

async fn cmd_seal(client: &Client, base: &str, text: String) -> Result<()> {
    // Use verify endpoint with PUSH_UN + SEAL to get a worm_hash sealing the input
    // We encode the text as the action field so it influences the final seal hash
    let body = serde_json::json!({
        "opcodes": ["PUSH_UN", "SEAL"],
        "source": text,
    });
    let resp: Value = client.post(format!("{base}/api/v1/verify"))
        .json(&body).send().await?.json().await?;
    let hash = resp["worm_hash"].as_str().unwrap_or("?");
    println!("WORM seal: {hash}");
    println!("Ξ© text:    {text}");
    Ok(())
}

async fn cmd_orchestrate(
    client:    &Client,
    base:      &str,
    action:    String,
    trace_ops: Option<Vec<String>>,
    raw:       bool,
) -> Result<()> {
    let body = serde_json::json!({
        "action":    action,
        "trace_ops": trace_ops,
    });

    let resp = client.post(format!("{base}/api/v1/orchestrate"))
        .json(&body)
        .header("Accept", "text/event-stream")
        .send().await?;

    // Stream SSE line-by-line
    use futures::StreamExt;
    let mut stream = resp.bytes_stream();
    let mut buf = String::new();

    while let Some(chunk) = stream.next().await {
        let chunk = chunk?;
        buf.push_str(&String::from_utf8_lossy(&chunk));

        // Process complete lines
        while let Some(nl) = buf.find('\n') {
            let line = buf[..nl].trim().to_string();
            buf.drain(..=nl);

            if line.is_empty() || line == "ping" { continue; }
            if let Some(data) = line.strip_prefix("data: ") {
                if raw {
                    println!("{data}");
                } else {
                    match serde_json::from_str::<Value>(data) {
                        Ok(ev)  => print_stage_event(&ev),
                        Err(_)  => println!("  {data}"),
                    }
                }
                io::stdout().flush().ok();
            }
        }
    }

    Ok(())
}

// ── Pretty printers ────────────────────────────────────────────────────────────

fn print_health(v: &Value) {
    let status  = v["status"].as_str().unwrap_or("?");
    let version = v["version"].as_str().unwrap_or("?");
    let errant  = v["errant_ok"].as_bool().unwrap_or(false);
    let nats    = v["nats_ok"].as_bool().unwrap_or(false);

    let tick    = |b: bool| if b { "βœ“" } else { "βœ—" };
    println!("status    {status}");
    println!("version   {version}");
    println!("liberrant {}", tick(errant));
    println!("nats      {}", tick(nats));
    println!("sovereign {}", v["sovereign"].as_str().unwrap_or("Ξ©"));
}

fn print_verify(v: &Value) {
    let ok      = v["ok"].as_bool().unwrap_or(false);
    let verdict = v["verdict"].as_str().unwrap_or("?");
    let hash    = v["worm_hash"].as_str().unwrap_or("?");
    let steps   = v["steps"].as_i64().unwrap_or(0);
    let lc      = v["lin_consumed"].as_i64().unwrap_or(0);
    let ll      = v["lin_leaked"].as_i64().unwrap_or(0);
    let fb      = v["fallback"].as_bool().unwrap_or(false);

    let mark = if ok { "EVIDENCE" } else { "SILENCE" };
    println!("{mark} Β· {verdict}");
    println!("hash  {hash}");
    println!("steps {} Β· lin_consumed {} Β· lin_leaked {}", steps, lc, ll);
    if fb { println!("mode  structural (Ξ©-path)"); }
    if let Some(err) = v["error"].as_str() {
        println!("error {err}");
    }
}

fn print_stage_event(v: &Value) {
    let stage = v["stage"].as_str().unwrap_or("?");
    let ok    = v["ok"].as_bool().unwrap_or(false);
    let msg   = v["message"].as_str().unwrap_or("");
    let tick  = if ok { "βœ“" } else { "βœ—" };

    print!("  [{tick}] {stage:<20} {msg}");

    if let Some(agent) = v["agent"].as_str() {
        print!("  ← {agent}");
    }
    if let Some(hash) = v["worm_hash"].as_str() {
        print!("  Ξ©:{}", &hash[..12]);
    }
    println!();

    if !ok {
        if let Some(err) = v["error"].as_str() {
            println!("      ERROR: {err}");
        }
    }
}