Implement chrs-slurp: Context Intelligence layer with DR curation and Dolt integration
This commit is contained in:
@@ -44,20 +44,23 @@ 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(())
|
||||
}
|
||||
|
||||
pub fn commit(&self, message: &str) -> Result<(), GraphError> {
|
||||
self.run_cmd(&["add", "."])?;
|
||||
self.run_cmd(&["add", "-A"])?;
|
||||
self.run_cmd(&["commit", "-m", message])?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
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])?;
|
||||
self.commit(&format!("Create table {}", table_name))?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -90,6 +93,7 @@ impl DoltGraph {
|
||||
columns.join(", "),
|
||||
values.join(", ")
|
||||
);
|
||||
println!("Executing: dolt sql -q \"{}\"", query);
|
||||
self.run_cmd(&["sql", "-q", &query])?;
|
||||
Ok(())
|
||||
}
|
||||
@@ -105,6 +109,5 @@ mod tests {
|
||||
let dir = TempDir::new().unwrap();
|
||||
let graph = DoltGraph::init(dir.path()).expect("init failed");
|
||||
graph.create_table("nodes", "id INT PRIMARY KEY, name TEXT").expect("create table failed");
|
||||
graph.commit("initial commit with table").expect("commit failed");
|
||||
}
|
||||
}
|
||||
|
||||
17
chrs-slurp/Cargo.toml
Normal file
17
chrs-slurp/Cargo.toml
Normal file
@@ -0,0 +1,17 @@
|
||||
[package]
|
||||
name = "chrs-slurp"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
chrs-graph = { path = "../chrs-graph" }
|
||||
ucxl = { path = "../UCXL" }
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = "1.0"
|
||||
thiserror = "1.0"
|
||||
chrono = { version = "0.4", features = ["serde"] }
|
||||
uuid = { version = "1.0", features = ["v4", "serde"] }
|
||||
|
||||
[dev-dependencies]
|
||||
tempfile = "3"
|
||||
|
||||
85
chrs-slurp/src/lib.rs
Normal file
85
chrs-slurp/src/lib.rs
Normal file
@@ -0,0 +1,85 @@
|
||||
use chrs_graph::{DoltGraph, GraphError};
|
||||
use ucxl::UCXLAddress;
|
||||
use chrono::{DateTime, Utc};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use thiserror::Error;
|
||||
use uuid::Uuid;
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||
pub struct DecisionRecord {
|
||||
pub id: Uuid,
|
||||
pub author: String,
|
||||
pub reasoning: String,
|
||||
pub citations: Vec<String>, // Serialized UCXL addresses
|
||||
pub timestamp: DateTime<Utc>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum SlurpError {
|
||||
#[error("Graph error: {0}")]
|
||||
Graph(#[from] GraphError),
|
||||
#[error("Serialization error: {0}")]
|
||||
Serde(#[from] serde_json::Error),
|
||||
#[error("Validation error: {0}")]
|
||||
ValidationError(String),
|
||||
}
|
||||
|
||||
pub struct CurationEngine {
|
||||
graph: DoltGraph,
|
||||
}
|
||||
|
||||
impl CurationEngine {
|
||||
pub fn new(graph: DoltGraph) -> Self {
|
||||
Self { graph }
|
||||
}
|
||||
|
||||
pub fn curate_decision(&self, dr: DecisionRecord) -> Result<(), SlurpError> {
|
||||
// 1. Validate Citations
|
||||
for citation in &dr.citations {
|
||||
use std::str::FromStr;
|
||||
UCXLAddress::from_str(citation)
|
||||
.map_err(|e| SlurpError::ValidationError(format!("Invalid citation {}: {}", citation, e)))?;
|
||||
}
|
||||
|
||||
// 2. Log DR into Graph (create table if needed handled by insert_node in future,
|
||||
// but for now let's ensure it's there).
|
||||
// If it fails because it exists, that's fine.
|
||||
let _ = self.graph.create_table("curated_decisions", "id VARCHAR(255) PRIMARY KEY, author TEXT, reasoning TEXT, citations TEXT, curated_at TEXT");
|
||||
|
||||
let data = serde_json::json!({
|
||||
"id": dr.id.to_string(),
|
||||
"author": dr.author,
|
||||
"reasoning": dr.reasoning,
|
||||
"citations": serde_json::to_string(&dr.citations)?,
|
||||
"curated_at": dr.timestamp.to_rfc3339()
|
||||
});
|
||||
|
||||
self.graph.insert_node("curated_decisions", data)?;
|
||||
self.graph.commit(&format!("Curation complete for DR: {}", dr.id))?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use tempfile::TempDir;
|
||||
|
||||
#[test]
|
||||
fn test_curation_flow() {
|
||||
let dir = TempDir::new().unwrap();
|
||||
let graph = DoltGraph::init(dir.path()).expect("graph init failed");
|
||||
let engine = CurationEngine::new(graph);
|
||||
|
||||
let dr = DecisionRecord {
|
||||
id: Uuid::new_v4(),
|
||||
author: "agent-001".into(),
|
||||
reasoning: "Tested the implementation of SLURP.".into(),
|
||||
citations: vec!["ucxl://system:watcher@local:filesystem/#/UCXL/src/lib.rs".into()],
|
||||
timestamp: Utc::now(),
|
||||
};
|
||||
|
||||
engine.curate_decision(dr).expect("curation failed");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user