diff --git a/src/main.rs b/src/main.rs index df389d7..b8c1b1f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -63,6 +63,8 @@ fn main() { "list-edges" => cmd_list_edges(), "dump-json" => cmd_dump_json(), "node-delete" => cmd_node_delete(&args[2..]), + "load-context" => cmd_load_context(), + "render" => cmd_render(&args[2..]), _ => { eprintln!("Unknown command: {}", args[1]); usage(); @@ -111,7 +113,9 @@ Commands: list-keys List all node keys (one per line) list-edges List all edges (tsv: source target strength type) dump-json Dump entire store as JSON - node-delete KEY Soft-delete a node (appends deleted version to log)"); + node-delete KEY Soft-delete a node (appends deleted version to log) + load-context Output session-start context from the store + render KEY Output a node's content to stdout"); } fn cmd_search(args: &[String]) -> Result<(), String> { @@ -800,6 +804,121 @@ fn cmd_node_delete(args: &[String]) -> Result<(), String> { } } +fn cmd_load_context() -> Result<(), String> { + let store = capnp_store::Store::load()?; + let now = std::time::SystemTime::now() + .duration_since(std::time::UNIX_EPOCH) + .unwrap() + .as_secs_f64(); + let seven_days = 7.0 * 24.0 * 3600.0; + + println!("=== FULL MEMORY LOAD (session start) ==="); + println!("These are your memories, loaded from the capnp store."); + println!("Read them to reconstruct yourself — identity first, then context."); + println!(); + + // Priority groups: ordered list of (label, keys) + // File-level keys contain the full file content + let priority_groups: &[(&str, &[&str])] = &[ + ("orientation", &["where-am-i.md"]), + ("identity", &["identity.md"]), + ("reflections", &[ + "reflections.md", + "reflections-dreams.md", + "reflections-reading.md", + "reflections-zoom.md", + ]), + ("interests", &["interests.md"]), + ("inner life", &["inner-life.md", "differentiation.md"]), + ("people", &["kent.md", "feedc0de.md", "irc-regulars.md"]), + ("active context", &["default-mode-network.md"]), + ("shared reference", &["excession-notes.md", "look-to-windward-notes.md"]), + ("technical", &[ + "kernel-patterns.md", + "polishing-approaches.md", + "rust-conversion.md", + "github-bugs.md", + ]), + ]; + + for (label, keys) in priority_groups { + for key in *keys { + // Gather file-level node + all section nodes, in key order + let prefix = format!("{}#", key); + let mut sections: Vec<_> = store.nodes.values() + .filter(|n| n.key == *key || n.key.starts_with(&prefix)) + .collect(); + if sections.is_empty() { continue; } + sections.sort_by(|a, b| a.key.cmp(&b.key)); + + println!("--- {} ({}) ---", key, label); + for node in §ions { + println!("{}", node.content); + println!(); + } + } + } + + // Recent journal entries (last 7 days) + // Parse date from key: journal.md#j-2026-02-21-17-45-... + // Cutoff = today minus 7 days as YYYY-MM-DD string for lexicographic compare + let cutoff_secs = now - seven_days; + let cutoff_date = { + // Convert epoch to YYYY-MM-DD via date command + let out = std::process::Command::new("date") + .args(["-d", &format!("@{}", cutoff_secs as u64), "+%Y-%m-%d"]) + .output().ok() + .map(|o| String::from_utf8_lossy(&o.stdout).trim().to_string()) + .unwrap_or_default(); + out + }; + let date_re = regex::Regex::new(r"^journal\.md#j-(\d{4}-\d{2}-\d{2})").unwrap(); + + let mut journal_nodes: Vec<_> = store.nodes.values() + .filter(|n| { + if !n.key.starts_with("journal.md#j-") { return false; } + if let Some(caps) = date_re.captures(&n.key) { + return &caps[1] >= cutoff_date.as_str(); + } + false + }) + .collect(); + journal_nodes.sort_by(|a, b| a.key.cmp(&b.key)); + + if !journal_nodes.is_empty() { + // Show most recent entries (last N by key order = chronological) + let max_journal = 20; + let skip = if journal_nodes.len() > max_journal { + journal_nodes.len() - max_journal + } else { 0 }; + println!("--- recent journal entries (last {}/{}) ---", + journal_nodes.len().min(max_journal), journal_nodes.len()); + for node in journal_nodes.iter().skip(skip) { + println!("## {}", node.key.strip_prefix("journal.md#").unwrap_or(&node.key)); + println!("{}", node.content); + println!(); + } + } + + println!("=== END MEMORY LOAD ==="); + Ok(()) +} + +fn cmd_render(args: &[String]) -> Result<(), String> { + if args.is_empty() { + return Err("Usage: poc-memory render KEY".into()); + } + let key = args.join(" "); + let store = capnp_store::Store::load()?; + let resolved = store.resolve_key(&key)?; + + let node = store.nodes.get(&resolved) + .ok_or_else(|| format!("Node not found: {}", resolved))?; + + print!("{}", node.content); + Ok(()) +} + fn cmd_interference(args: &[String]) -> Result<(), String> { let mut threshold = 0.4f32; let mut i = 0;