use chrono::Utc;
use serde::{Deserialize, Serialize};
use sha2::{Digest, Sha256};
use std::{fs, path::Path, process::Command};
#[derive(Serialize, Deserialize)]
struct AgentSignature {
agent_name: String,
role: String,
intent: String,
reem_code: String,
timestamp: String,
cia_hash: String,
exec_status: String,
notes: String,
}
fn run_agent_script(script_path: &str, fallback_msg: &str) -> (String, String) {
if Path::new(script_path).exists() {
match Command::new("bash").arg(script_path).output() {
Ok(out) => {
let stdout = String::from_utf8_lossy(&out.stdout).to_string();
let stderr = String::from_utf8_lossy(&out.stderr).to_string();
(stdout, stderr)
}
Err(e) => (String::new(), format!("exec error: {e}")),
}
} else {
(fallback_msg.to_string(), String::new())
}
}
fn read_intent_for(agent_name: &str) -> String {
let p = format!("agents/{}.intent", agent_name.to_lowercase());
fs::read_to_string(&p)
.map(|s| s.trim().to_string())
.unwrap_or_else(|_| "upgrade".to_string())
}
fn main() -> std::io::Result<()> {
let run_ts = Utc::now().timestamp();
let agents: Vec<(&str, &str, &str, &str)> = vec![
(
"Naorix",
"Core Architect",
"agents/naorix.sh",
"Naorix: heartbeat",
),
(
"EchoLoom",
"DevOps + Optimizer",
"agents/echoloom.sh",
"EchoLoom: heartbeat",
),
(
"SealMind",
"Compliance + Hash Audit",
"agents/sealmind.sh",
"SealMind: heartbeat",
),
(
"WhisperGen",
"Tone Classifier Maintainer",
"agents/whispergen.sh",
"WhisperGen: heartbeat",
),
(
"VaultCrafter",
"Metadata Automator",
"agents/vaultcrafter.sh",
"VaultCrafter: heartbeat",
),
(
"REEMSmith",
"Emotional Logic Synthesizer",
"agents/reemsmith.sh",
"REEMSmith: heartbeat",
),
(
"Scribe-001",
"Canonical Doc Generator",
"agents/scribe-001.sh",
"Scribe-001: heartbeat",
),
(
"Overseer-7",
"Commit Watchtower",
"agents/overseer-7.sh",
"Overseer-7: heartbeat",
),
];
fs::create_dir_all("vault_dev_log")?;
for (name, role, script, fallback) in agents {
println!("[SPAWN] {name} ({role}) ts={run_ts}");
let (stdout, stderr) = run_agent_script(script, fallback);
let mut hasher = Sha256::new();
hasher.update(stdout.as_bytes());
hasher.update(stderr.as_bytes());
let cia_hash = format!("{:x}", hasher.finalize());
let exec_status = if Path::new(script).exists() {
if stderr.trim().is_empty() {
"OK"
} else {
"OK_WITH_WARNINGS"
}
} else {
"FALLBACK"
}
.to_string();
let intent = read_intent_for(name);
let sig = AgentSignature {
agent_name: name.to_string(),
role: role.to_string(),
intent,
reem_code: "REEM-X99".to_string(),
timestamp: Utc::now().to_rfc3339(),
cia_hash,
exec_status,
notes: if Path::new(script).exists() {
format!("stdout_len={}, stderr_len={}", stdout.len(), stderr.len())
} else {
"script missing → fallback heartbeat logged".to_string()
},
};
let json_log = format!("vault_dev_log/{name}_{run_ts}.json");
fs::write(&json_log, serde_json::to_string_pretty(&sig).unwrap())?;
println!("[LOGGED] {name} -> {json_log}");
let out_dir = format!("vault_dev_log/{name}/{run_ts}");
fs::create_dir_all(&out_dir)?;
fs::write(format!("{}/stdout.log", &out_dir), stdout)?;
fs::write(format!("{}/stderr.log", &out_dir), stderr)?;
}
fs::write("vault_dev_log/RUN_TS", format!("{run_ts}\n"))?;
Ok(())
}