@@ -53,14 +53,13 @@ fn epic_to_json(epic: &Epic) -> serde_json::Value {
5353fn task_to_json ( task : & Task ) -> serde_json:: Value {
5454 let spec_path = format ! ( ".flow/tasks/{}.md" , task. id) ;
5555
56- // Try to get runtime state from DB
56+ // Try to get runtime state from JSON files
5757 let mut assignee: serde_json:: Value = json ! ( null) ;
5858 let mut claimed_at: serde_json:: Value = json ! ( null) ;
5959 let claim_note: serde_json:: Value = json ! ( "" ) ;
6060
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 ) {
61+ let flow_dir = crate :: commands:: helpers:: get_flow_dir ( ) ;
62+ if let Ok ( state) = flowctl_core:: json_store:: state_read ( & flow_dir, & task. id ) {
6463 if let Some ( a) = & state. assignee {
6564 assignee = json ! ( a) ;
6665 }
@@ -114,54 +113,55 @@ fn task_list_json(task: &Task) -> serde_json::Value {
114113 } )
115114}
116115
117- // ── DB-only data access ─────────────────── ─────────────────────────
116+ // ── DB bridge for file locks (stays in DB) ─────────────────────────
118117
119- /// Open DB or exit with error (DB is sole source of truth).
120118fn require_db ( ) -> crate :: commands:: db_shim:: Connection {
121119 crate :: commands:: db_shim:: require_db ( )
122120 . unwrap_or_else ( |e| error_exit ( & format ! ( "Cannot open database: {}" , e) ) )
123121}
124122
125- /// Get a single epic by ID from DB.
126- fn get_epic ( _flow_dir : & PathBuf , id : & str ) -> Option < Epic > {
127- let conn = require_db ( ) ;
128- let repo = crate :: commands :: db_shim :: EpicRepo :: new ( & conn ) ;
129- repo . get ( id) . ok ( )
123+ // ── JSON file data access ──────────────────────────────────────────
124+
125+ /// Get a single epic by ID from JSON files.
126+ fn get_epic ( flow_dir : & PathBuf , id : & str ) -> Option < Epic > {
127+ flowctl_core :: json_store :: epic_read ( flow_dir , id) . ok ( )
130128}
131129
132- /// Get a single task by ID from DB.
133- fn get_task ( _flow_dir : & PathBuf , id : & str ) -> Option < Task > {
134- let conn = require_db ( ) ;
135- let repo = crate :: commands:: db_shim:: TaskRepo :: new ( & conn) ;
136- repo. get ( id) . ok ( )
130+ /// Get a single task by ID from JSON files.
131+ fn get_task ( flow_dir : & PathBuf , id : & str ) -> Option < Task > {
132+ flowctl_core:: json_store:: task_read ( flow_dir, id) . ok ( )
137133}
138134
139- /// Get all tasks for an epic from DB.
140- fn get_epic_tasks ( _flow_dir : & PathBuf , epic_id : & str ) -> Vec < Task > {
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 ( )
135+ /// Get all tasks for an epic from JSON files.
136+ fn get_epic_tasks ( flow_dir : & PathBuf , epic_id : & str ) -> Vec < Task > {
137+ flowctl_core:: json_store:: task_list_by_epic ( flow_dir, epic_id) . unwrap_or_default ( )
144138}
145139
146- /// Get all epics from DB.
147- fn get_all_epics ( _flow_dir : & PathBuf ) -> Vec < Epic > {
148- let conn = require_db ( ) ;
149- let repo = crate :: commands:: db_shim:: EpicRepo :: new ( & conn) ;
150- repo. list ( None ) . unwrap_or_default ( )
140+ /// Get all epics from JSON files.
141+ fn get_all_epics ( flow_dir : & PathBuf ) -> Vec < Epic > {
142+ flowctl_core:: json_store:: epic_list ( flow_dir) . unwrap_or_default ( )
151143}
152144
153- /// Get all tasks, optionally filtered, from DB .
145+ /// Get all tasks, optionally filtered, from JSON files .
154146fn get_all_tasks (
155- _flow_dir : & PathBuf ,
147+ flow_dir : & PathBuf ,
156148 epic_filter : Option < & str > ,
157149 status_filter : Option < & str > ,
158150 domain_filter : Option < & str > ,
159151) -> Vec < Task > {
160- let conn = require_db ( ) ;
161- let repo = crate :: commands:: db_shim:: TaskRepo :: new ( & conn) ;
162152 match epic_filter {
163153 Some ( epic_id) => {
164- let mut tasks = repo. list_by_epic ( epic_id) . unwrap_or_default ( ) ;
154+ let mut tasks = flowctl_core:: json_store:: task_list_by_epic ( flow_dir, epic_id) . unwrap_or_default ( ) ;
155+ if let Some ( status) = status_filter {
156+ tasks. retain ( |t| t. status . to_string ( ) == status) ;
157+ }
158+ if let Some ( domain) = domain_filter {
159+ tasks. retain ( |t| t. domain . to_string ( ) == domain) ;
160+ }
161+ tasks
162+ }
163+ None => {
164+ let mut tasks = flowctl_core:: json_store:: task_list_all ( flow_dir) . unwrap_or_default ( ) ;
165165 if let Some ( status) = status_filter {
166166 tasks. retain ( |t| t. status . to_string ( ) == status) ;
167167 }
@@ -170,7 +170,6 @@ fn get_all_tasks(
170170 }
171171 tasks
172172 }
173- None => repo. list_all ( status_filter, domain_filter) . unwrap_or_default ( ) ,
174173 }
175174}
176175
@@ -490,13 +489,11 @@ pub fn cmd_cat(id: String) {
490489 }
491490 }
492491 } else if is_task_id ( & id) {
493- // Task body: read from DB (sole source of truth)
494- let conn = require_db ( ) ;
495- let repo = crate :: commands:: db_shim:: TaskRepo :: new ( & conn) ;
496- match repo. get_with_body ( & id) {
497- Ok ( ( _task, body) ) => {
492+ // Task body: read from JSON spec file
493+ match flowctl_core:: json_store:: task_spec_read ( & flow_dir, & id) {
494+ Ok ( body) => {
498495 if body. is_empty ( ) {
499- error_exit ( & format ! ( "Task body not found in DB : {}" , id) ) ;
496+ error_exit ( & format ! ( "Task spec not found: {}" , id) ) ;
500497 }
501498 print ! ( "{}" , body) ;
502499 }
@@ -527,14 +524,12 @@ pub fn cmd_files(json_mode: bool, epic: String) {
527524 let mut ownership: std:: collections:: BTreeMap < String , Vec < String > > =
528525 std:: collections:: BTreeMap :: new ( ) ;
529526
530- let conn = require_db ( ) ;
531527 for task in & tasks {
532528 let mut task_files: Vec < String > = task. files . clone ( ) ;
533529
534- // Fallback: parse **Files:** from task body in DB if no structured files
530+ // Fallback: parse **Files:** from task spec if no structured files
535531 if task_files. is_empty ( ) {
536- let repo = crate :: commands:: db_shim:: TaskRepo :: new ( & conn) ;
537- if let Ok ( ( _t, body) ) = repo. get_with_body ( & task. id ) {
532+ if let Ok ( body) = flowctl_core:: json_store:: task_spec_read ( & flow_dir, & task. id ) {
538533 for line in body. lines ( ) {
539534 if let Some ( rest) = line. strip_prefix ( "**Files:**" ) {
540535 task_files = rest
0 commit comments