lean_ctx/core/context_package/
bundle.rs1use chrono::{DateTime, Utc};
4use serde::{Deserialize, Serialize};
5
6use crate::core::session::{Decision, FileTouched, Finding, TaskInfo, TestSnapshot};
7use crate::core::session_summary::SummaryRecord;
8
9pub(crate) const FORMAT_VERSION: u32 = 1;
10
11#[derive(Debug, Clone, Serialize, Deserialize)]
13pub struct ContextPackage {
14 pub format_version: u32,
15 pub created_at: DateTime<Utc>,
16 pub project_root: String,
17 pub session_id: String,
18 pub metadata: PackageMetadata,
19 pub session: SessionSlice,
20 #[serde(default, skip_serializing_if = "Vec::is_empty")]
21 pub summaries: Vec<SummaryRecord>,
22 #[serde(default, skip_serializing_if = "Vec::is_empty")]
23 pub knowledge: Vec<KnowledgeFact>,
24}
25
26#[derive(Debug, Clone, Serialize, Deserialize)]
28pub struct PackageMetadata {
29 pub agent_id: Option<String>,
30 pub description: Option<String>,
31 pub tool_calls: u32,
32 pub tokens_saved: u64,
33}
34
35#[derive(Debug, Clone, Serialize, Deserialize)]
37pub struct SessionSlice {
38 pub task: Option<TaskInfo>,
39 pub findings: Vec<Finding>,
40 pub decisions: Vec<Decision>,
41 pub files: Vec<FileTouched>,
42 pub next_steps: Vec<String>,
43 pub test_results: Option<TestSnapshot>,
44}
45
46#[derive(Debug, Clone, Serialize, Deserialize)]
48pub struct KnowledgeFact {
49 #[serde(default)]
50 pub origin: crate::core::knowledge::FactOrigin,
51 pub category: String,
52 pub key: String,
53 pub value: String,
54 pub confidence: f32,
55 pub created_at: DateTime<Utc>,
56}
57
58impl ContextPackage {
59 pub(crate) fn is_compatible(&self) -> bool {
60 self.format_version <= FORMAT_VERSION
61 }
62
63 pub fn summary_line(&self) -> String {
64 let desc = self
65 .metadata
66 .description
67 .as_deref()
68 .or(self.session.task.as_ref().map(|t| t.description.as_str()))
69 .unwrap_or("(no description)");
70 format!(
71 "[{}] {} — {} files, {} decisions, {} summaries, {} facts",
72 self.session_id
73 .split('-')
74 .next()
75 .unwrap_or(&self.session_id),
76 desc,
77 self.session.files.len(),
78 self.session.decisions.len(),
79 self.summaries.len(),
80 self.knowledge.len()
81 )
82 }
83}