diff --git a/chrs-graph/src/lib.rs b/chrs-graph/src/lib.rs index 4c60b300..72747bb6 100644 --- a/chrs-graph/src/lib.rs +++ b/chrs-graph/src/lib.rs @@ -17,20 +17,22 @@ pub enum GraphError { } pub struct DoltGraph { - repo_path: std::path::PathBuf, + pub repo_path: std::path::PathBuf, } impl DoltGraph { pub fn init(path: &Path) -> Result { - let status = Command::new("dolt") - .arg("init") - .current_dir(path) - .status()?; - if !status.success() { - return Err(GraphError::CommandFailed(format!( - "dolt init failed with status {:?}", - status - ))); + if !path.join(".dolt").exists() { + let status = Command::new("dolt") + .arg("init") + .current_dir(path) + .status()?; + if !status.success() { + return Err(GraphError::CommandFailed(format!( + "dolt init failed with status {:?}", + status + ))); + } } Ok(Self { repo_path: path.to_path_buf(), @@ -44,7 +46,6 @@ impl DoltGraph { .output()?; if !output.status.success() { let stderr = String::from_utf8_lossy(&output.stderr); - eprintln!("Dolt Command Failed: {:?} -> {}", args, stderr); return Err(GraphError::CommandFailed(stderr.to_string())); } Ok(()) @@ -58,8 +59,12 @@ impl DoltGraph { pub fn create_table(&self, table_name: &str, schema: &str) -> Result<(), GraphError> { let query = format!("CREATE TABLE {} ({})", table_name, schema); - println!("Executing: dolt sql -q \"{}\"", query); - self.run_cmd(&["sql", "-q", &query])?; + if let Err(e) = self.run_cmd(&["sql", "-q", &query]) { + if e.to_string().contains("already exists") { + return Ok(()); + } + return Err(e); + } self.commit(&format!("Create table {}", table_name))?; Ok(()) } @@ -93,7 +98,6 @@ impl DoltGraph { columns.join(", "), values.join(", ") ); - println!("Executing: dolt sql -q \"{}\"", query); self.run_cmd(&["sql", "-q", &query])?; Ok(()) } diff --git a/chrs-poc/Cargo.toml b/chrs-poc/Cargo.toml new file mode 100644 index 00000000..a4e17a86 --- /dev/null +++ b/chrs-poc/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "chrs-poc" +version = "0.1.0" +edition = "2021" + +[dependencies] +ucxl = { path = "../UCXL" } +chrs-mail = { path = "../chrs-mail" } +chrs-graph = { path = "../chrs-graph" } +chrs-slurp = { path = "../chrs-slurp" } +chrs-shhh = { path = "../chrs-shhh" } +chrs-bubble = { path = "../chrs-bubble" } +tokio = { version = "1", features = ["full"] } +serde = { version = "1.0", features = ["derive"] } +serde_json = "1.0" +uuid = { version = "1.0", features = ["v4"] } +chrono = "0.4" diff --git a/chrs-poc/src/main.rs b/chrs-poc/src/main.rs new file mode 100644 index 00000000..7b49a40f --- /dev/null +++ b/chrs-poc/src/main.rs @@ -0,0 +1,90 @@ +use chrs_bubble::{ProvenanceGraph, ProvenanceEdge}; +use chrs_graph::DoltGraph; +use chrs_mail::{Mailbox, Message}; +use chrs_shhh::SecretSentinel; +use chrs_slurp::{CurationEngine, DecisionRecord}; +use chrono::Utc; +use std::fs; +use std::path::Path; +use uuid::Uuid; + +#[tokio::main] +async fn main() -> Result<(), Box> { + println!("=== CHORUS End-to-End Proof of Concept ==="); + + // 1. Setup paths + let base_path = Path::new("/tmp/chrs_poc"); + if base_path.exists() { + fs::remove_dir_all(base_path)?; + } + fs::create_dir_all(base_path)?; + + let mail_path = base_path.join("mail.sqlite"); + let graph_path = base_path.join("state_graph"); + fs::create_dir_all(&graph_path)?; + + // 2. Initialize Components + let mailbox = Mailbox::open(&mail_path)?; + let persistence = DoltGraph::init(&graph_path)?; + let mut provenance = ProvenanceGraph::new(persistence); + + // We need a fresh DoltGraph handle for SLURP because ProvenanceGraph moved 'persistence' + // In a real app, we'd use Arc> or similar. + let slurp_persistence = DoltGraph::init(&graph_path)?; + let curator = CurationEngine::new(slurp_persistence); + let sentinel = SecretSentinel::new_default(); + + println!("[POC] Components initialized."); + + // 3. Dispatch Task (simulate client sending message to Agent-A) + let task_id = Uuid::new_v4(); + let task_msg = Message { + id: task_id, + from_peer: "client".into(), + to_peer: "agent-a".into(), + topic: "audit_system".into(), + payload: serde_json::json!({"action": "audit", "target": "UCXL"}), + sent_at: Utc::now(), + read_at: None, + }; + mailbox.send(&task_msg)?; + println!("[POC] Task dispatched to Agent-A: {}", task_id); + + // 4. Process Task (Agent-A logic) + let pending = mailbox.receive_pending("agent-a")?; + for msg in pending { + println!("[POC] Agent-A received task: {}", msg.topic); + + // Generate reasoning with an accidental secret + let raw_reasoning = "Audit complete. Verified UCXL address parsing. My secret key is sk-1234567890abcdef1234567890abcdef1234567890abcdef"; + + // 5. SHHH: Scrub secrets + let clean_reasoning = sentinel.scrub_text(raw_reasoning); + println!("[POC] SHHH scrubbed reasoning: {}", clean_reasoning); + + // 6. SLURP: Create and Curate Decision Record + let dr = DecisionRecord { + id: Uuid::new_v4(), + author: "agent-a".into(), + reasoning: clean_reasoning, + citations: vec!["ucxl://system:watcher@local:filesystem/#/UCXL/src/lib.rs".into()], + timestamp: Utc::now(), + }; + curator.curate_decision(dr.clone())?; + + // 7. BUBBLE: Record Provenance + provenance.record_node(task_id, "ucxl://client:user@poc:task/#/audit_request")?; + provenance.record_node(dr.id, "ucxl://agent-a:worker@poc:task/#/audit_result")?; + provenance.record_link(dr.id, task_id, ProvenanceEdge::DerivedFrom)?; + + println!("[POC] Provenance recorded: DR {} -> Task {}", dr.id, task_id); + + mailbox.mark_read(msg.id)?; + } + + println!(" +=== POC SUCCESSFUL ==="); + println!("Final State is persisted in Dolt at: {:?}", graph_path); + + Ok(()) +}