navi_core/memory/
schemas.rs1use serde::{Deserialize, Serialize};
2
3#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq, Eq)]
5pub struct SessionCheckpoint {
6 pub intent: String,
7 pub next_action: String,
8 pub constraints: String,
9 pub task_tree: String,
10 pub current_work: String,
11 pub involved_files: String,
12 pub discoveries: String,
13 pub errors_fixes: String,
14 pub runtime_state: String,
15 pub decisions: String,
16 pub misc: String,
17}
18
19impl SessionCheckpoint {
20 pub fn from_markdown(text: &str) -> Self {
22 let mut checkpoint = Self::default();
23 let mut current_section: Option<String> = None;
24 let mut current_content = String::new();
25
26 let commit_section = |checkpoint: &mut Self, section: Option<&str>, content: &str| {
27 let trimmed = content.trim().to_string();
28 if let Some(sec) = section {
29 match sec {
30 "Current Intent" => checkpoint.intent = trimmed,
31 "Next Action" => checkpoint.next_action = trimmed,
32 "Working Constraints" => checkpoint.constraints = trimmed,
33 "Task Tree" => checkpoint.task_tree = trimmed,
34 "Current Work" => checkpoint.current_work = trimmed,
35 "Involved Files" => checkpoint.involved_files = trimmed,
36 "Cross-Task Discoveries" => checkpoint.discoveries = trimmed,
37 "Errors and Fixes" => checkpoint.errors_fixes = trimmed,
38 "Runtime State" => checkpoint.runtime_state = trimmed,
39 "Design Decisions" => checkpoint.decisions = trimmed,
40 "Miscellaneous Notes" => checkpoint.misc = trimmed,
41 _ => {}
42 }
43 }
44 };
45
46 for line in text.lines() {
47 if line.starts_with("## ") {
48 commit_section(
49 &mut checkpoint,
50 current_section.as_deref(),
51 ¤t_content,
52 );
53 current_section = Some(line["## ".len()..].trim().to_string());
54 current_content.clear();
55 } else if line.starts_with("# ") {
56 } else {
58 if current_section.is_some() {
59 current_content.push_str(line);
60 current_content.push('\n');
61 }
62 }
63 }
64 commit_section(
65 &mut checkpoint,
66 current_section.as_deref(),
67 ¤t_content,
68 );
69 checkpoint
70 }
71
72 pub fn to_markdown(&self) -> String {
74 let mut out = String::new();
75 out.push_str("# Session Checkpoint\n\n");
76 out.push_str("## Current Intent\n");
77 out.push_str(if self.intent.is_empty() {
78 ""
79 } else {
80 &self.intent
81 });
82 out.push_str("\n\n## Next Action\n");
83 out.push_str(if self.next_action.is_empty() {
84 ""
85 } else {
86 &self.next_action
87 });
88 out.push_str("\n\n## Working Constraints\n");
89 out.push_str(if self.constraints.is_empty() {
90 ""
91 } else {
92 &self.constraints
93 });
94 out.push_str("\n\n## Task Tree\n");
95 out.push_str(if self.task_tree.is_empty() {
96 ""
97 } else {
98 &self.task_tree
99 });
100 out.push_str("\n\n## Current Work\n");
101 out.push_str(if self.current_work.is_empty() {
102 ""
103 } else {
104 &self.current_work
105 });
106 out.push_str("\n\n## Involved Files\n");
107 out.push_str(if self.involved_files.is_empty() {
108 ""
109 } else {
110 &self.involved_files
111 });
112 out.push_str("\n\n## Cross-Task Discoveries\n");
113 out.push_str(if self.discoveries.is_empty() {
114 ""
115 } else {
116 &self.discoveries
117 });
118 out.push_str("\n\n## Errors and Fixes\n");
119 out.push_str(if self.errors_fixes.is_empty() {
120 ""
121 } else {
122 &self.errors_fixes
123 });
124 out.push_str("\n\n## Runtime State\n");
125 out.push_str(if self.runtime_state.is_empty() {
126 ""
127 } else {
128 &self.runtime_state
129 });
130 out.push_str("\n\n## Design Decisions\n");
131 out.push_str(if self.decisions.is_empty() {
132 ""
133 } else {
134 &self.decisions
135 });
136 out.push_str("\n\n## Miscellaneous Notes\n");
137 out.push_str(if self.misc.is_empty() { "" } else { &self.misc });
138 out.push_str("\n");
139 out
140 }
141}