22//!
33//! Reads from SQLite as the sole source of truth.
44
5- use std:: env;
65use std:: fs;
76use std:: path:: PathBuf ;
87
@@ -28,12 +27,6 @@ fn ensure_flow_exists() -> PathBuf {
2827 flow_dir
2928}
3029
31- /// Try to open a DB connection. Returns None if DB doesn't exist or can't be opened.
32- fn try_open_db ( ) -> Option < crate :: commands:: db_shim:: Connection > {
33- let cwd = env:: current_dir ( ) . ok ( ) ?;
34- crate :: commands:: db_shim:: open ( & cwd) . ok ( )
35- }
36-
3730/// Serialize an Epic to the JSON format matching Python output.
3831fn epic_to_json ( epic : & Epic ) -> serde_json:: Value {
3932 let spec_path = format ! ( ".flow/specs/{}.md" , epic. id) ;
@@ -65,15 +58,14 @@ fn task_to_json(task: &Task) -> serde_json::Value {
6558 let mut claimed_at: serde_json:: Value = json ! ( null) ;
6659 let claim_note: serde_json:: Value = json ! ( "" ) ;
6760
68- if let Some ( conn) = try_open_db ( ) {
69- let runtime_repo = crate :: commands:: db_shim:: RuntimeRepo :: new ( & conn) ;
70- if let Ok ( Some ( state) ) = runtime_repo. get ( & task. id ) {
71- if let Some ( a) = & state. assignee {
72- assignee = json ! ( a) ;
73- }
74- if let Some ( ca) = & state. claimed_at {
75- claimed_at = json ! ( ca. to_rfc3339( ) ) ;
76- }
61+ let conn = require_db ( ) ;
62+ let runtime_repo = crate :: commands:: db_shim:: RuntimeRepo :: new ( & conn) ;
63+ if let Ok ( Some ( state) ) = runtime_repo. get ( & task. id ) {
64+ if let Some ( a) = & state. assignee {
65+ assignee = json ! ( a) ;
66+ }
67+ if let Some ( ca) = & state. claimed_at {
68+ claimed_at = json ! ( ca. to_rfc3339( ) ) ;
7769 }
7870 }
7971
@@ -132,38 +124,30 @@ fn require_db() -> crate::commands::db_shim::Connection {
132124
133125/// Get a single epic by ID from DB.
134126fn get_epic ( _flow_dir : & PathBuf , id : & str ) -> Option < Epic > {
135- let conn = try_open_db ( ) ? ;
127+ let conn = require_db ( ) ;
136128 let repo = crate :: commands:: db_shim:: EpicRepo :: new ( & conn) ;
137129 repo. get ( id) . ok ( )
138130}
139131
140132/// Get a single task by ID from DB.
141133fn get_task ( _flow_dir : & PathBuf , id : & str ) -> Option < Task > {
142- let conn = try_open_db ( ) ? ;
134+ let conn = require_db ( ) ;
143135 let repo = crate :: commands:: db_shim:: TaskRepo :: new ( & conn) ;
144136 repo. get ( id) . ok ( )
145137}
146138
147139/// Get all tasks for an epic from DB.
148140fn get_epic_tasks ( _flow_dir : & PathBuf , epic_id : & str ) -> Vec < Task > {
149- if let Some ( conn) = try_open_db ( ) {
150- let repo = crate :: commands:: db_shim:: TaskRepo :: new ( & conn) ;
151- if let Ok ( tasks) = repo. list_by_epic ( epic_id) {
152- return tasks;
153- }
154- }
155- Vec :: new ( )
141+ let conn = require_db ( ) ;
142+ let repo = crate :: commands:: db_shim:: TaskRepo :: new ( & conn) ;
143+ repo. list_by_epic ( epic_id) . unwrap_or_default ( )
156144}
157145
158146/// Get all epics from DB.
159147fn get_all_epics ( _flow_dir : & PathBuf ) -> Vec < Epic > {
160- if let Some ( conn) = try_open_db ( ) {
161- let repo = crate :: commands:: db_shim:: EpicRepo :: new ( & conn) ;
162- if let Ok ( epics) = repo. list ( None ) {
163- return epics;
164- }
165- }
166- Vec :: new ( )
148+ let conn = require_db ( ) ;
149+ let repo = crate :: commands:: db_shim:: EpicRepo :: new ( & conn) ;
150+ repo. list ( None ) . unwrap_or_default ( )
167151}
168152
169153/// Get all tasks, optionally filtered, from DB.
@@ -173,28 +157,21 @@ fn get_all_tasks(
173157 status_filter : Option < & str > ,
174158 domain_filter : Option < & str > ,
175159) -> Vec < Task > {
176- if let Some ( conn) = try_open_db ( ) {
177- let repo = crate :: commands:: db_shim:: TaskRepo :: new ( & conn) ;
178- match epic_filter {
179- Some ( epic_id) => {
180- if let Ok ( mut tasks) = repo. list_by_epic ( epic_id) {
181- if let Some ( status) = status_filter {
182- tasks. retain ( |t| t. status . to_string ( ) == status) ;
183- }
184- if let Some ( domain) = domain_filter {
185- tasks. retain ( |t| t. domain . to_string ( ) == domain) ;
186- }
187- return tasks;
188- }
160+ let conn = require_db ( ) ;
161+ let repo = crate :: commands:: db_shim:: TaskRepo :: new ( & conn) ;
162+ match epic_filter {
163+ Some ( epic_id) => {
164+ let mut tasks = repo. list_by_epic ( epic_id) . unwrap_or_default ( ) ;
165+ if let Some ( status) = status_filter {
166+ tasks. retain ( |t| t. status . to_string ( ) == status) ;
189167 }
190- None => {
191- if let Ok ( tasks) = repo. list_all ( status_filter, domain_filter) {
192- return tasks;
193- }
168+ if let Some ( domain) = domain_filter {
169+ tasks. retain ( |t| t. domain . to_string ( ) == domain) ;
194170 }
171+ tasks
195172 }
173+ None => repo. list_all ( status_filter, domain_filter) . unwrap_or_default ( ) ,
196174 }
197- Vec :: new ( )
198175}
199176
200177// ── Show command ────────────────────────────────────────────────────
@@ -550,24 +527,22 @@ pub fn cmd_files(json_mode: bool, epic: String) {
550527 let mut ownership: std:: collections:: BTreeMap < String , Vec < String > > =
551528 std:: collections:: BTreeMap :: new ( ) ;
552529
553- let conn_opt = try_open_db ( ) ;
530+ let conn = require_db ( ) ;
554531 for task in & tasks {
555532 let mut task_files: Vec < String > = task. files . clone ( ) ;
556533
557534 // Fallback: parse **Files:** from task body in DB if no structured files
558535 if task_files. is_empty ( ) {
559- if let Some ( ref conn) = conn_opt {
560- let repo = crate :: commands:: db_shim:: TaskRepo :: new ( conn) ;
561- if let Ok ( ( _t, body) ) = repo. get_with_body ( & task. id ) {
562- for line in body. lines ( ) {
563- if let Some ( rest) = line. strip_prefix ( "**Files:**" ) {
564- task_files = rest
565- . split ( ',' )
566- . map ( |f| f. trim ( ) . trim_matches ( '`' ) . to_string ( ) )
567- . filter ( |f| !f. is_empty ( ) )
568- . collect ( ) ;
569- break ;
570- }
536+ let repo = crate :: commands:: db_shim:: TaskRepo :: new ( & conn) ;
537+ if let Ok ( ( _t, body) ) = repo. get_with_body ( & task. id ) {
538+ for line in body. lines ( ) {
539+ if let Some ( rest) = line. strip_prefix ( "**Files:**" ) {
540+ task_files = rest
541+ . split ( ',' )
542+ . map ( |f| f. trim ( ) . trim_matches ( '`' ) . to_string ( ) )
543+ . filter ( |f| !f. is_empty ( ) )
544+ . collect ( ) ;
545+ break ;
571546 }
572547 }
573548 }
0 commit comments