lean_ctx/core/gotcha_tracker/
persist.rs1use super::model::{Gotcha, GotchaStore};
2use std::path::PathBuf;
3
4impl GotchaStore {
5 pub fn load(project_root: &str) -> Self {
6 let hash = crate::core::project_hash::hash_project_root(project_root);
7 let path = gotcha_path(&hash);
8 if let Ok(content) = std::fs::read_to_string(&path) {
9 if let Ok(mut store) = serde_json::from_str::<GotchaStore>(&content) {
10 store.apply_decay();
11 store.pending_errors = Vec::new();
12 return store;
13 }
14 }
15 Self::new(&hash)
16 }
17
18 pub fn save(&self, project_root: &str) -> Result<(), String> {
19 let hash = crate::core::project_hash::hash_project_root(project_root);
20 let path = gotcha_path(&hash);
21 if let Some(parent) = path.parent() {
22 std::fs::create_dir_all(parent).map_err(|e| e.to_string())?;
23 }
24 let tmp = path.with_extension("tmp");
25 let json = serde_json::to_string_pretty(self).map_err(|e| e.to_string())?;
26 std::fs::write(&tmp, &json).map_err(|e| e.to_string())?;
27 std::fs::rename(&tmp, &path).map_err(|e| e.to_string())?;
28 Ok(())
29 }
30}
31
32fn gotcha_path(project_hash: &str) -> PathBuf {
33 crate::core::data_dir::lean_ctx_data_dir()
34 .unwrap_or_else(|_| PathBuf::from("."))
35 .join("knowledge")
36 .join(project_hash)
37 .join("gotchas.json")
38}
39
40pub fn load_universal_gotchas() -> Vec<Gotcha> {
45 let policy = crate::core::memory_boundary::BoundaryPolicy::default();
46 if !policy.universal_gotchas_enabled {
47 return Vec::new();
48 }
49 let Ok(dir) = crate::core::data_dir::lean_ctx_data_dir() else {
50 return Vec::new();
51 };
52 let path = dir.join("universal-gotchas.json");
53 if let Ok(content) = std::fs::read_to_string(&path) {
54 serde_json::from_str(&content).unwrap_or_default()
55 } else {
56 Vec::new()
57 }
58}
59
60pub fn save_universal_gotchas(gotchas: &[Gotcha]) -> Result<(), String> {
61 let dir = crate::core::data_dir::lean_ctx_data_dir()?;
62 let path = dir.join("universal-gotchas.json");
63 let tmp = path.with_extension("tmp");
64 let json = serde_json::to_string_pretty(gotchas).map_err(|e| e.to_string())?;
65 std::fs::write(&tmp, &json).map_err(|e| e.to_string())?;
66 std::fs::rename(&tmp, &path).map_err(|e| e.to_string())?;
67 Ok(())
68}