Download seb/human_touch/src/main.rs from Snapkitty/sov-kernel-monster: direct link, hf CLI and curl.
- Browser
- Download file 7.57 kB
-
https://huggingface.co/Snapkitty/sov-kernel-monster/resolve/main/seb/human_touch/src/main.rs
- Command line
-
hf download hf://Snapkitty/sov-kernel-monster/seb/human_touch/src/main.rs
-
curl -L -o main.rs https://huggingface.co/Snapkitty/sov-kernel-monster/resolve/main/seb/human_touch/src/main.rs
7.57 kB
| mod review_queue; | |
| mod commit_gateway; | |
| mod audit_log; | |
| use anyhow::Result; | |
| use clap::Parser; | |
| use std::io::{self, BufRead, Write}; | |
| use std::path::PathBuf; | |
| use std::sync::Arc; | |
| use tokio::sync::mpsc; | |
| use tracing::info; | |
| use tracing_subscriber; | |
| struct Args { | |
| /// Path to git repository | |
| repo_path: PathBuf, | |
| /// Path to audit log file | |
| audit_log: PathBuf, | |
| /// Maximum pending changes before blocking | |
| max_pending: usize, | |
| /// Approval timeout in seconds | |
| approval_timeout_secs: u64, | |
| /// Enable verbose logging | |
| verbose: bool, | |
| /// Human reviewer name (for commits) | |
| reviewer: Option<String>, | |
| /// Run in daemon mode (background service) | |
| daemon: bool, | |
| /// Port for webhook listener (if daemon mode) | |
| webhook_port: u16, | |
| } | |
| async fn main() -> Result<()> { | |
| let args = Args::parse(); | |
| // Initialize tracing | |
| if args.verbose { | |
| tracing_subscriber::fmt() | |
| .with_max_level(tracing::Level::DEBUG) | |
| .pretty() | |
| .init(); | |
| } else { | |
| tracing_subscriber::fmt() | |
| .with_max_level(tracing::Level::INFO) | |
| .init(); | |
| } | |
| info!( | |
| "π Human-Touch Gateway starting (repo: {:?}, audit: {:?})", | |
| args.repo_path, args.audit_log | |
| ); | |
| // Initialize components | |
| let (tx, rx) = mpsc::channel::<review_queue::PendingChange>(args.max_pending); | |
| let review_queue = review_queue::ReviewQueue::new( | |
| rx, | |
| args.repo_path.clone(), | |
| args.audit_log.clone(), | |
| args.max_pending, | |
| )?; | |
| let commit_gateway = commit_gateway::CommitGateway::new( | |
| args.repo_path.clone(), | |
| args.approval_timeout_secs, | |
| )?; | |
| let audit_log = audit_log::AuditLog::new(args.audit_log)?; | |
| // Arc the queue for sharing between tasks | |
| let review_queue = Arc::new(tokio::sync::Mutex::new(review_queue)); | |
| let audit_log_clone = audit_log.clone(); | |
| // Spawn the review queue processor | |
| let queue_handle = { | |
| let gateway = commit_gateway.clone(); | |
| let queue = Arc::clone(&review_queue); | |
| tokio::spawn(async move { | |
| let mut queue_mut = queue.lock().await; | |
| if let Err(e) = queue_mut.process_queue(gateway, audit_log_clone).await { | |
| tracing::error!("Review queue processor failed: {}", e); | |
| } | |
| }) | |
| }; | |
| if args.daemon { | |
| // Run as daemon with webhook listener | |
| info!("π Running in daemon mode (webhook: 0.0.0.0:{})", args.webhook_port); | |
| let _tx_clone = tx.clone(); | |
| // Placeholder: would start webhook server here | |
| // For now just keep running | |
| tokio::signal::ctrl_c().await?; | |
| info!("Received shutdown signal"); | |
| } else { | |
| // Interactive mode: read from stdin | |
| info!("π Running in interactive mode"); | |
| // Run interactive loop | |
| if let Err(e) = interactive_loop_blocking( | |
| tx.clone(), | |
| review_queue.clone(), | |
| audit_log.clone(), | |
| &args.reviewer.clone().unwrap_or_else(|| "human".to_string()), | |
| ) | |
| .await | |
| { | |
| tracing::error!("Interactive loop error: {}", e); | |
| } | |
| // Wait for queue processor | |
| let _ = queue_handle.await; | |
| } | |
| info!("β Human-Touch Gateway shutting down gracefully"); | |
| Ok(()) | |
| } | |
| /// Interactive loop for human approval/rejection of changes | |
| async fn interactive_loop_blocking( | |
| _tx: mpsc::Sender<review_queue::PendingChange>, | |
| review_queue: Arc<tokio::sync::Mutex<review_queue::ReviewQueue>>, | |
| audit_log: audit_log::AuditLog, | |
| reviewer_name: &str, | |
| ) -> Result<()> { | |
| let stdin = io::stdin(); | |
| let mut reader = stdin.lock(); | |
| println!("\nβ¨ Human-Touch Gateway Interactive Mode β¨"); | |
| println!(" Commands: 'approve <id>', 'reject <id> <reason>', 'status', 'help', 'exit'"); | |
| println!(); | |
| loop { | |
| print!("π€ > "); | |
| io::stdout().flush()?; | |
| let mut line = String::new(); | |
| reader.read_line(&mut line)?; | |
| let cmd = line.trim(); | |
| if cmd.is_empty() { | |
| continue; | |
| } | |
| let parts: Vec<&str> = cmd.split_whitespace().collect(); | |
| match parts.get(0).copied() { | |
| Some("approve") => { | |
| if let Some(change_id) = parts.get(1) { | |
| match review_queue | |
| .lock().await | |
| .approve_change(change_id, reviewer_name, &audit_log) | |
| .await | |
| { | |
| Ok(_) => println!("β Change {} approved and ready for commit", change_id), | |
| Err(e) => println!("β Failed to approve: {}", e), | |
| } | |
| } else { | |
| println!("β Usage: approve <change-id>"); | |
| } | |
| } | |
| Some("reject") => { | |
| if let (Some(change_id), Some(reason)) = (parts.get(1), parts.get(2..)) { | |
| let reason_str = reason.join(" "); | |
| match review_queue | |
| .lock().await | |
| .reject_change(change_id, reviewer_name, &reason_str, &audit_log) | |
| .await | |
| { | |
| Ok(_) => println!("β Change {} rejected", change_id), | |
| Err(e) => println!("β Failed to reject: {}", e), | |
| } | |
| } else { | |
| println!("β Usage: reject <change-id> <reason>"); | |
| } | |
| } | |
| Some("status") => { | |
| let status = review_queue.lock().await.status(); | |
| println!( | |
| "\nπ Queue Status:\n Total: {}\n Pending: {}\n Approved: {}\n Rejected: {}\n Committed: {}\n Capacity: {}\n", | |
| status.total, status.pending, status.approved, status.rejected, status.committed, status.capacity | |
| ); | |
| } | |
| Some("help") => { | |
| println!("\nπ Available Commands:"); | |
| println!(" approve <id> - Approve a change for commit"); | |
| println!(" reject <id> <reason> - Reject a change with reason"); | |
| println!(" status - Show queue status"); | |
| println!(" help - Show this message"); | |
| println!(" exit - Exit gateway\n"); | |
| } | |
| Some("exit") => { | |
| println!("π Exiting Human-Touch Gateway..."); | |
| break; | |
| } | |
| _ => println!("β Unknown command. Type 'help' for available commands."), | |
| } | |
| } | |
| Ok(()) | |
| } | |