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
+31 -22
View File
@@ -1,23 +1,39 @@
use anyhow::{anyhow, Result};
use std::collections::{HashMap, HashSet};
use std::collections::HashMap;
use std::fs;
use std::path::{Path, PathBuf};
use sha2::{Digest, Sha256};
use serde::{Deserialize, Serialize};
use crate::{
MemoryNode, MemoryRecord, MemoryParent, Level, VectorKind, PgRepo, ObsidianProjector,
ProjectorOpts,
};
use crate::{MemoryNode, Level, PgRepo};
/// Memory record from log (local copy for rebuild purposes)
#[derive(Debug, Clone, Serialize, Deserialize)]
struct MemoryRecord {
pub level: String,
pub project: String,
pub query_id: Option<String>,
pub text: String,
pub run_id: String,
pub t: i32,
pub source: Option<String>,
pub parents: Vec<MemoryParent>,
}
/// Parent reference for provenance
#[derive(Debug, Clone, Serialize, Deserialize)]
struct MemoryParent {
pub source: String,
pub t: i32,
pub description: Option<String>,
}
/// Rebuild options
#[derive(Debug, Clone)]
pub struct RebuildOpts {
pub project: String,
pub vault_only: bool, // Only rebuild vault, not database
pub db_only: bool, // Only rebuild database, not vault
pub allow_partial: bool, // Allow rebuilding from incomplete logs
pub embedding_cache_dir: Option<PathBuf>,
pub vault_dir: Option<PathBuf>,
pub log_dir: Option<PathBuf>,
}
@@ -32,7 +48,7 @@ pub struct RebuildStats {
pub embeddings_cached: i64,
}
/// Rebuild orchestrator: drop projections, rebuild from log
/// Rebuild orchestrator: rebuild database from log (vault projection delegated to Obsidian service)
pub struct RebuildEngine {
repo: PgRepo,
}
@@ -44,12 +60,12 @@ impl RebuildEngine {
Ok(Self { repo })
}
/// Execute full rebuild: clear → insert nodes → insert edges → project vault
/// Execute database rebuild: clear → insert nodes → insert edges
///
/// Order matters: nodes first (foreign key constraint), then edges, then vault projection
/// Order matters: nodes first (foreign key constraint), then edges.
/// Vault projection delegated to Obsidian service.
pub async fn rebuild(&self, opts: RebuildOpts) -> Result<RebuildStats> {
let log_dir = opts.log_dir.unwrap_or_else(|| PathBuf::from("log"));
let vault_dir = opts.vault_dir.unwrap_or_else(|| PathBuf::from("vault"));
let cache_dir = opts
.embedding_cache_dir
.clone()
@@ -63,13 +79,11 @@ impl RebuildEngine {
let mut stats = RebuildStats::default();
// PASS 1: Clear project (if not vault-only)
if !opts.vault_only {
self.repo.clear_project(&opts.project).await?;
}
// PASS 1: Clear project
self.repo.clear_project(&opts.project).await?;
// PASS 2: Insert all nodes (convert memories to nodes, batch embeddings)
if !opts.vault_only {
{
let mut nodes_by_sha: HashMap<String, MemoryNode> = HashMap::new();
let mut sha_to_level: HashMap<String, Level> = HashMap::new();
let mut sha_to_parents: HashMap<String, Vec<String>> = HashMap::new();
@@ -130,11 +144,6 @@ impl RebuildEngine {
stats.embeddings_computed = 0;
}
// PASS 4: Project vault (if not db-only)
if !opts.db_only {
ObsidianProjector::project(&log_dir, &vault_dir, ProjectorOpts::default()).await?;
}
Ok(stats)
}