refactor: replace Obsidian projector with standalone service (ppatlabs/obsidian)
This commit is contained in:
@@ -6,6 +6,7 @@ mod query_worker;
|
||||
mod rate_limiter;
|
||||
mod idempotency;
|
||||
mod jwt_validator;
|
||||
mod verify;
|
||||
|
||||
use clap::{Parser, Subcommand};
|
||||
use mem_chunk::token_counter::CharsOverFourCounter;
|
||||
@@ -113,6 +114,28 @@ enum Commands {
|
||||
#[arg(long)]
|
||||
database_url: Option<String>,
|
||||
},
|
||||
|
||||
/// Verify edge closure and graph integrity
|
||||
Verify {
|
||||
/// Project name
|
||||
#[arg(long, value_name = "PROJECT")]
|
||||
project: String,
|
||||
/// Check database (default: true)
|
||||
#[arg(long, default_value_t = true)]
|
||||
db: bool,
|
||||
/// Check log (default: true)
|
||||
#[arg(long, default_value_t = true)]
|
||||
log: bool,
|
||||
/// Log directory
|
||||
#[arg(long)]
|
||||
log_dir: Option<PathBuf>,
|
||||
/// Output format (text, json)
|
||||
#[arg(long, default_value = "text")]
|
||||
format: String,
|
||||
/// Database URL
|
||||
#[arg(long)]
|
||||
database_url: Option<String>,
|
||||
},
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
@@ -160,6 +183,14 @@ async fn main() -> anyhow::Result<()> {
|
||||
let database_url = database_url.unwrap_or_else(|| std::env::var("DATABASE_URL").unwrap_or_else(|_| "postgresql://app:poimen@localhost:5432/memory".to_string()));
|
||||
http_server::start_server(port, api_key, &database_url).await?
|
||||
}
|
||||
Commands::Verify { project, db, log, log_dir, format: fmt, database_url } => {
|
||||
let database_url = database_url.unwrap_or_else(|| std::env::var("DATABASE_URL").unwrap_or_else(|_| "postgresql://app:poimen@localhost:5432/memory".to_string()));
|
||||
let output_format = match fmt.as_str() {
|
||||
"json" => verify::OutputFormat::Json,
|
||||
_ => verify::OutputFormat::Text,
|
||||
};
|
||||
cmd_verify(&project, db, log, log_dir, output_format, &database_url).await?
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@@ -274,3 +305,54 @@ async fn cmd_ingest(
|
||||
println!("Done.");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn cmd_verify(
|
||||
project: &str,
|
||||
check_db: bool,
|
||||
check_log: bool,
|
||||
log_dir: Option<PathBuf>,
|
||||
format: verify::OutputFormat,
|
||||
database_url: &str,
|
||||
) -> anyhow::Result<()> {
|
||||
let opts = verify::VerifyOpts {
|
||||
project: project.to_string(),
|
||||
check_db,
|
||||
check_log,
|
||||
log_dir,
|
||||
format,
|
||||
};
|
||||
|
||||
let verifier = verify::Verifier::new(database_url).await?;
|
||||
let result = verifier.verify(opts).await?;
|
||||
|
||||
match format {
|
||||
verify::OutputFormat::Json => {
|
||||
println!("{}", serde_json::to_string_pretty(&result)?);
|
||||
}
|
||||
verify::OutputFormat::Text => {
|
||||
println!("Project: {}", result.project);
|
||||
println!("Status: {}", if result.clean { "✓ CLEAN" } else { "✗ VIOLATIONS" });
|
||||
println!("Total violations: {}", result.total_violations);
|
||||
|
||||
if !result.violations.is_empty() {
|
||||
println!("\nViolations:");
|
||||
for v in &result.violations {
|
||||
println!(
|
||||
" Invariant {}: {} (sha: {}, level: {})",
|
||||
v.invariant,
|
||||
v.description,
|
||||
v.sha.as_deref().unwrap_or("N/A"),
|
||||
v.level.as_deref().unwrap_or("N/A")
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Exit with non-zero if there are violations
|
||||
if !result.clean {
|
||||
std::process::exit(1);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user