@@ -304,6 +304,18 @@ struct SessionsCommand {
304304 /// Show all sessions including from other directories
305305 #[ arg( long) ]
306306 all : bool ,
307+
308+ /// Filter sessions from the last N days
309+ #[ arg( long, short = 'd' ) ]
310+ days : Option < u32 > ,
311+
312+ /// Filter sessions since a specific date (YYYY-MM-DD format)
313+ #[ arg( long) ]
314+ since : Option < String > ,
315+
316+ /// Filter sessions until a specific date (YYYY-MM-DD format)
317+ #[ arg( long) ]
318+ until : Option < String > ,
307319}
308320
309321/// Config command.
@@ -478,7 +490,15 @@ async fn main() -> Result<()> {
478490 }
479491 } ,
480492 Some ( Commands :: Resume ( resume_cli) ) => run_resume ( resume_cli) . await ,
481- Some ( Commands :: Sessions ( sessions_cli) ) => list_sessions ( sessions_cli. all ) . await ,
493+ Some ( Commands :: Sessions ( sessions_cli) ) => {
494+ list_sessions (
495+ sessions_cli. all ,
496+ sessions_cli. days ,
497+ sessions_cli. since ,
498+ sessions_cli. until ,
499+ )
500+ . await
501+ }
482502 Some ( Commands :: Export ( export_cli) ) => export_cli. run ( ) . await ,
483503 Some ( Commands :: Import ( import_cli) ) => import_cli. run ( ) . await ,
484504 Some ( Commands :: Config ( config_cli) ) => show_config ( config_cli) . await ,
@@ -676,7 +696,14 @@ async fn run_resume(resume_cli: ResumeCommand) -> Result<()> {
676696 Ok ( ( ) )
677697}
678698
679- async fn list_sessions ( show_all : bool ) -> Result < ( ) > {
699+ async fn list_sessions (
700+ show_all : bool ,
701+ days : Option < u32 > ,
702+ since : Option < String > ,
703+ until : Option < String > ,
704+ ) -> Result < ( ) > {
705+ use chrono:: { DateTime , NaiveDate , Utc } ;
706+
680707 let config = cortex_engine:: Config :: default ( ) ;
681708 let sessions = cortex_engine:: list_sessions ( & config. cortex_home ) ?;
682709
@@ -689,58 +716,146 @@ async fn list_sessions(show_all: bool) -> Result<()> {
689716 return Ok ( ( ) ) ;
690717 }
691718
692- let current_dir = std:: env:: current_dir ( ) . ok ( ) ;
693- let filtered: Vec < _ > = if show_all {
694- sessions. iter ( ) . collect ( )
719+ // Parse date filters
720+ let now = Utc :: now ( ) ;
721+ let since_date: Option < DateTime < Utc > > = if let Some ( days_val) = days {
722+ Some ( now - chrono:: Duration :: days ( days_val as i64 ) )
723+ } else if let Some ( ref since_str) = since {
724+ match NaiveDate :: parse_from_str ( since_str, "%Y-%m-%d" ) {
725+ Ok ( date) => Some (
726+ date. and_hms_opt ( 0 , 0 , 0 )
727+ . unwrap ( )
728+ . and_local_timezone ( Utc )
729+ . unwrap ( ) ,
730+ ) ,
731+ Err ( _) => {
732+ eprintln ! (
733+ "Warning: Invalid --since date format '{}'. Expected YYYY-MM-DD." ,
734+ since_str
735+ ) ;
736+ None
737+ }
738+ }
695739 } else {
696- sessions
697- . iter ( )
698- . filter ( |s| current_dir. as_ref ( ) . is_none_or ( |cwd| s. cwd == * cwd) )
699- . collect ( )
740+ None
741+ } ;
742+
743+ let until_date: Option < DateTime < Utc > > = if let Some ( ref until_str) = until {
744+ match NaiveDate :: parse_from_str ( until_str, "%Y-%m-%d" ) {
745+ Ok ( date) => Some (
746+ date. and_hms_opt ( 23 , 59 , 59 )
747+ . unwrap ( )
748+ . and_local_timezone ( Utc )
749+ . unwrap ( ) ,
750+ ) ,
751+ Err ( _) => {
752+ eprintln ! (
753+ "Warning: Invalid --until date format '{}'. Expected YYYY-MM-DD." ,
754+ until_str
755+ ) ;
756+ None
757+ }
758+ }
759+ } else {
760+ None
700761 } ;
701762
702- let display_sessions = if filtered. is_empty ( ) {
763+ let current_dir = std:: env:: current_dir ( ) . ok ( ) ;
764+
765+ // Apply all filters: directory, since, and until
766+ let filtered: Vec < _ > = sessions
767+ . iter ( )
768+ . filter ( |s| {
769+ // Directory filter
770+ if !show_all && current_dir. as_ref ( ) . is_some_and ( |cwd| s. cwd != * cwd) {
771+ return false ;
772+ }
773+
774+ // Parse session timestamp for date filtering
775+ if since_date. is_some ( ) || until_date. is_some ( ) {
776+ if let Ok ( session_time) = DateTime :: parse_from_rfc3339 ( & s. timestamp ) {
777+ let session_utc = session_time. with_timezone ( & Utc ) ;
778+ if let Some ( ref since) = since_date {
779+ if session_utc < * since {
780+ return false ;
781+ }
782+ }
783+ if let Some ( ref until) = until_date {
784+ if session_utc > * until {
785+ return false ;
786+ }
787+ }
788+ }
789+ }
790+
791+ true
792+ } )
793+ . collect ( ) ;
794+
795+ let display_sessions = if filtered. is_empty ( ) && since_date. is_none ( ) && until_date. is_none ( ) {
703796 & sessions
704797 } else {
705798 & filtered. iter ( ) . map ( |s| ( * s) . clone ( ) ) . collect ( )
706799 } ;
707800
708- println ! ( "Recent Sessions{}:" , if show_all { " (all)" } else { "" } ) ;
709- println ! ( "{:-<80}" , "" ) ;
801+ // Build header with active filters
802+ let mut filter_info = String :: new ( ) ;
803+ if show_all {
804+ filter_info. push_str ( " (all)" ) ;
805+ }
806+ if let Some ( days_val) = days {
807+ filter_info. push_str ( & format ! ( " (last {} days)" , days_val) ) ;
808+ } else {
809+ if since_date. is_some ( ) {
810+ filter_info. push_str ( & format ! ( " (since {})" , since. as_deref( ) . unwrap_or( "" ) ) ) ;
811+ }
812+ if until_date. is_some ( ) {
813+ filter_info. push_str ( & format ! ( " (until {})" , until. as_deref( ) . unwrap_or( "" ) ) ) ;
814+ }
815+ }
710816
711- for session in display_sessions. iter ( ) . take ( 15 ) {
712- let model = session. model . as_deref ( ) . unwrap_or ( "unknown" ) ;
713- let date = if session. timestamp . len ( ) >= 19 {
714- session. timestamp [ ..19 ] . replace ( 'T' , " " )
715- } else {
716- session. timestamp . clone ( )
717- } ;
817+ println ! ( "Recent Sessions{}:" , filter_info) ;
818+ println ! ( "{:-<80}" , "" ) ;
718819
719- let branch_info = session
720- . git_branch
721- . as_ref ( )
722- . map ( |b| format ! ( " [{b}]" ) )
723- . unwrap_or_default ( ) ;
820+ if display_sessions. is_empty ( ) {
821+ println ! ( "No sessions match the specified filters." ) ;
822+ } else {
823+ for session in display_sessions. iter ( ) . take ( 15 ) {
824+ let model = session. model . as_deref ( ) . unwrap_or ( "unknown" ) ;
825+ let date = if session. timestamp . len ( ) >= 19 {
826+ session. timestamp [ ..19 ] . replace ( 'T' , " " )
827+ } else {
828+ session. timestamp . clone ( )
829+ } ;
724830
725- println ! (
726- "{} | {} | {} msgs | {}{branch_info}" ,
727- & session. id[ ..8 . min( session. id. len( ) ) ] ,
728- date,
729- session. message_count,
730- model,
731- ) ;
732- println ! ( " {}" , session. cwd. display( ) ) ;
733- }
831+ let branch_info = session
832+ . git_branch
833+ . as_ref ( )
834+ . map ( |b| format ! ( " [{b}]" ) )
835+ . unwrap_or_default ( ) ;
836+
837+ println ! (
838+ "{} | {} | {} msgs | {}{branch_info}" ,
839+ & session. id[ ..8 . min( session. id. len( ) ) ] ,
840+ date,
841+ session. message_count,
842+ model,
843+ ) ;
844+ println ! ( " {}" , session. cwd. display( ) ) ;
845+ }
734846
735- if display_sessions. len ( ) > 15 {
736- println ! ( "\n ... and {} more sessions" , display_sessions. len( ) - 15 ) ;
847+ if display_sessions. len ( ) > 15 {
848+ println ! ( "\n ... and {} more sessions" , display_sessions. len( ) - 15 ) ;
849+ }
737850 }
738851
739852 println ! ( "\n To resume: Cortex resume <session-id>" ) ;
740853 println ! ( " Cortex resume --last" ) ;
741854 if !show_all {
742855 println ! ( " Cortex sessions --all (show all directories)" ) ;
743856 }
857+ println ! ( " Cortex sessions --days 7 (last 7 days)" ) ;
858+ println ! ( " Cortex sessions --since 2024-01-01 --until 2024-12-31 (date range)" ) ;
744859 Ok ( ( ) )
745860}
746861
0 commit comments