返回 CodeWhale
compat.rs
根目录 / crates / tui / src / work_graph / compat.rs
1 //! Pure compatibility projections for the pre-Work-Graph Plan and To-do wire
2 //! formats.
3 //!
4 //! The graph owns the ordering, metadata, titles, and states. These functions
5 //! only derive owned snapshots; they never receive mutable graph access (V10).
6
7 use crate::tools::plan::{PlanItemArg, PlanSnapshot, StepStatus};
8 use crate::tools::todo::{TodoItem, TodoListSnapshot, TodoStatus};
9
10 use super::model::{CompatPlanMetadata, NodeState, WorkGraphSnapshot, WorkNode};
11
12 pub type PlanProjection = PlanSnapshot;
13 pub type TodoProjection = TodoListSnapshot;
14
15 impl CompatPlanMetadata {
16 #[must_use]
17 pub fn from_plan_snapshot(snapshot: &PlanSnapshot) -> Self {
18 Self {
19 title: snapshot.title.clone(),
20 objective: snapshot.objective.clone(),
21 context_summary: snapshot.context_summary.clone(),
22 explanation: snapshot.explanation.clone(),
23 sources_used: snapshot.sources_used.clone(),
24 critical_files: snapshot.critical_files.clone(),
25 constraints: snapshot.constraints.clone(),
26 recommended_approach: snapshot.recommended_approach.clone(),
27 verification_plan: snapshot.verification_plan.clone(),
28 risks_and_unknowns: snapshot.risks_and_unknowns.clone(),
29 handoff_packet: snapshot.handoff_packet.clone(),
30 }
31 }
32
33 #[must_use]
34 fn to_plan_snapshot(&self) -> PlanSnapshot {
35 PlanSnapshot {
36 title: self.title.clone(),
37 objective: self.objective.clone(),
38 context_summary: self.context_summary.clone(),
39 explanation: self.explanation.clone(),
40 sources_used: self.sources_used.clone(),
41 critical_files: self.critical_files.clone(),
42 constraints: self.constraints.clone(),
43 recommended_approach: self.recommended_approach.clone(),
44 verification_plan: self.verification_plan.clone(),
45 risks_and_unknowns: self.risks_and_unknowns.clone(),
46 handoff_packet: self.handoff_packet.clone(),
47 items: Vec::new(),
48 }
49 }
50 }
51
52 /// Derive the complete legacy Strategy/Plan snapshot.
53 #[must_use]
54 pub fn project_plan(snapshot: &WorkGraphSnapshot) -> PlanProjection {
55 let mut plan = snapshot.compat.plan.to_plan_snapshot();
56 plan.items = snapshot
57 .compat
58 .plan_order
59 .iter()
60 .filter_map(|id| snapshot.node(id))
61 .map(|node| PlanItemArg {
62 step: node.title.clone(),
63 status: plan_status(node),
64 })
65 .collect();
66 plan
67 }
68
69 /// Derive the complete legacy To-do snapshot. Migration provenance stays in
70 /// the graph; old readers receive clean, user-visible content.
71 #[must_use]
72 pub fn project_todos(snapshot: &WorkGraphSnapshot) -> TodoProjection {
73 let items = snapshot
74 .compat
75 .todos
76 .iter()
77 .filter_map(|binding| {
78 let node = snapshot.node(&binding.node)?;
79 Some(TodoItem {
80 id: binding.legacy_id,
81 content: node.title.clone(),
82 status: todo_status(node),
83 })
84 })
85 .collect::<Vec<_>>();
86 let settled = items.iter().filter(|item| item.status.is_settled()).count();
87 let completion_pct = if items.is_empty() {
88 0
89 } else {
90 let rounded = (settled.saturating_mul(100) + items.len() / 2) / items.len();
91 u8::try_from(rounded).unwrap_or(u8::MAX)
92 };
93 let in_progress_id = items
94 .iter()
95 .find(|item| item.status == TodoStatus::InProgress)
96 .map(|item| item.id);
97 TodoListSnapshot {
98 items,
99 completion_pct,
100 in_progress_id,
101 }
102 }
103
104 fn plan_status(node: &WorkNode) -> StepStatus {
105 match node.state {
106 NodeState::Initializing | NodeState::Active => StepStatus::InProgress,
107 NodeState::Completed | NodeState::Verified => StepStatus::Completed,
108 _ => StepStatus::Pending,
109 }
110 }
111
112 fn todo_status(node: &WorkNode) -> TodoStatus {
113 match node.state {
114 NodeState::Initializing | NodeState::Active => TodoStatus::InProgress,
115 NodeState::Completed | NodeState::Verified => TodoStatus::Completed,
116 NodeState::Cancelled | NodeState::Superseded => TodoStatus::Cancelled,
117 _ => TodoStatus::Pending,
118 }
119 }
120
120 lines RUST