refactor: replace Obsidian projector with standalone service (ppatlabs/obsidian)

This commit is contained in:
Story Crater Bot
2026-08-27 21:35:07 -07:00
parent 83b9dcf5f9
commit 0eecca815b
11 changed files with 1050 additions and 804 deletions
+82
View File
@@ -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(())
}