@@ -598,32 +598,31 @@ pub fn cmd_files(json_mode: bool, epic: String) {
598598// ── Lock commands (Teams mode) ─────────────────────────────────────
599599
600600
601- pub fn cmd_lock ( json : bool , task : String , files : String ) {
601+ pub fn cmd_lock ( json : bool , task : String , files : String , mode : String ) {
602602 let _flow_dir = ensure_flow_exists ( ) ;
603603
604604 let file_list: Vec < & str > = files. split ( ',' ) . map ( str:: trim) . filter ( |s| !s. is_empty ( ) ) . collect ( ) ;
605605 if file_list. is_empty ( ) {
606606 error_exit ( "No files specified for locking." ) ;
607607 }
608608
609+ let lock_mode = crate :: commands:: db_shim:: LockMode :: from_str ( & mode)
610+ . unwrap_or_else ( |e| error_exit ( & format ! ( "Invalid lock mode: {}" , e) ) ) ;
611+
609612 let conn = require_db ( ) ;
610613 let repo = crate :: commands:: db_shim:: FileLockRepo :: new ( & conn) ;
611614
612615 let mut locked = Vec :: new ( ) ;
613616 let mut already_locked = Vec :: new ( ) ;
614617
615618 for file in & file_list {
616- match repo. acquire ( file, & task) {
619+ match repo. acquire ( file, & task, & lock_mode ) {
617620 Ok ( ( ) ) => locked. push ( file. to_string ( ) ) ,
618- Err ( crate :: commands:: db_shim:: DbError :: Constraint ( _ ) ) => {
621+ Err ( crate :: commands:: db_shim:: DbError :: Constraint ( msg ) ) => {
619622 // Already locked — find out by whom
620- let owner = repo. check ( file) . ok ( ) . flatten ( ) . unwrap_or_else ( || "unknown" . to_string ( ) ) ;
621- if owner == task {
622- // Re-locking own file is fine, treat as locked
623- locked. push ( file. to_string ( ) ) ;
624- } else {
625- already_locked. push ( json ! ( { "file" : file, "owner" : owner} ) ) ;
626- }
623+ let entries = repo. check_locks ( file) . ok ( ) . unwrap_or_default ( ) ;
624+ let owners: Vec < String > = entries. iter ( ) . map ( |e| format ! ( "{}({})" , e. task_id, e. lock_mode. as_str( ) ) ) . collect ( ) ;
625+ already_locked. push ( json ! ( { "file" : file, "owners" : owners, "detail" : msg} ) ) ;
627626 }
628627 Err ( e) => {
629628 error_exit ( & format ! ( "Failed to lock {}: {}" , file, e) ) ;
@@ -636,16 +635,17 @@ pub fn cmd_lock(json: bool, task: String, files: String) {
636635 "locked" : locked,
637636 "already_locked" : already_locked,
638637 "task" : task,
638+ "mode" : mode,
639639 } ) ) ;
640640 } else {
641641 if !locked. is_empty ( ) {
642- println ! ( "Locked {} file(s) for task {}" , locked. len( ) , task) ;
642+ println ! ( "Locked {} file(s) for task {} (mode: {}) " , locked. len( ) , task, mode ) ;
643643 }
644644 for al in & already_locked {
645645 println ! (
646- "Already locked: {} (owner : {})" ,
646+ "Already locked: {} (owners : {})" ,
647647 al[ "file" ] . as_str( ) . unwrap_or( "" ) ,
648- al[ "owner" ] . as_str ( ) . unwrap_or ( "" )
648+ al[ "owners" ] ,
649649 ) ;
650650 }
651651 }
@@ -703,19 +703,24 @@ pub fn cmd_lock_check(json: bool, file: Option<String>) {
703703
704704 match file {
705705 Some ( f) => {
706- match repo. check ( & f) {
707- Ok ( Some ( owner) ) => {
706+ match repo. check_locks ( & f) {
707+ Ok ( entries) if !entries. is_empty ( ) => {
708+ let lock_info: Vec < serde_json:: Value > = entries. iter ( ) . map ( |e| json ! ( {
709+ "task_id" : e. task_id,
710+ "mode" : e. lock_mode. as_str( ) ,
711+ } ) ) . collect ( ) ;
708712 if json {
709713 json_output ( json ! ( {
710714 "file" : f,
711715 "locked" : true ,
712- "owner " : owner ,
716+ "locks " : lock_info ,
713717 } ) ) ;
714718 } else {
715- println ! ( "{}: locked by {}" , f, owner) ;
719+ let owners: Vec < String > = entries. iter ( ) . map ( |e| format ! ( "{}({})" , e. task_id, e. lock_mode. as_str( ) ) ) . collect ( ) ;
720+ println ! ( "{}: locked by {}" , f, owners. join( ", " ) ) ;
716721 }
717722 }
718- Ok ( None ) => {
723+ Ok ( _ ) => {
719724 if json {
720725 json_output ( json ! ( {
721726 "file" : f,
@@ -736,10 +741,11 @@ pub fn cmd_lock_check(json: bool, file: Option<String>) {
736741 . unwrap_or_else ( |e| { error_exit ( & format ! ( "Query failed: {}" , e) ) ; } ) ;
737742 let locks: Vec < serde_json:: Value > = rows
738743 . into_iter ( )
739- . map ( |( file, task_id, locked_at) | json ! ( {
744+ . map ( |( file, task_id, locked_at, lock_mode ) | json ! ( {
740745 "file" : file,
741746 "task_id" : task_id,
742747 "locked_at" : locked_at,
748+ "mode" : lock_mode,
743749 } ) )
744750 . collect ( ) ;
745751
@@ -754,9 +760,10 @@ pub fn cmd_lock_check(json: bool, file: Option<String>) {
754760 println ! ( "Active file locks ({}):\n " , locks. len( ) ) ;
755761 for l in & locks {
756762 println ! (
757- " {} → {} (since {})" ,
763+ " {} → {} [{}] (since {})" ,
758764 l[ "file" ] . as_str( ) . unwrap_or( "" ) ,
759765 l[ "task_id" ] . as_str( ) . unwrap_or( "" ) ,
766+ l[ "mode" ] . as_str( ) . unwrap_or( "write" ) ,
760767 l[ "locked_at" ] . as_str( ) . unwrap_or( "" )
761768 ) ;
762769 }
0 commit comments