@@ -33,6 +33,11 @@ CLAUDE_USE_CONTINUE=true # Enable session continuity
3333CLAUDE_SESSION_FILE=" .claude_session_id" # Session ID persistence file
3434CLAUDE_MIN_VERSION=" 2.0.76" # Minimum required Claude CLI version
3535
36+ # Session management configuration (Phase 1.2)
37+ RALPH_SESSION_FILE=" .ralph_session" # Ralph-specific session tracking
38+ RALPH_SESSION_HISTORY_FILE=" .ralph_session_history" # Session transition history
39+ SESSION_EXPIRATION_SECONDS=86400 # 24 hours in seconds
40+
3641# Valid tool patterns for --allowed-tools validation
3742# Tools can be exact matches or pattern matches with wildcards in parentheses
3843VALID_TOOL_PATTERNS=(
@@ -477,6 +482,125 @@ save_claude_session() {
477482 fi
478483}
479484
485+ # =============================================================================
486+ # SESSION LIFECYCLE MANAGEMENT FUNCTIONS (Phase 1.2)
487+ # =============================================================================
488+
489+ # Get current session ID from Ralph session file
490+ # Returns: session ID string or empty if not found
491+ get_session_id () {
492+ if [[ ! -f " $RALPH_SESSION_FILE " ]]; then
493+ echo " "
494+ return 0
495+ fi
496+
497+ # Extract session_id from JSON file
498+ local session_id=$( jq -r ' .session_id // ""' " $RALPH_SESSION_FILE " 2> /dev/null)
499+ if [[ " $session_id " == " null" ]]; then
500+ session_id=" "
501+ fi
502+ echo " $session_id "
503+ return 0
504+ }
505+
506+ # Reset session with reason logging
507+ # Usage: reset_session "reason_for_reset"
508+ reset_session () {
509+ local reason=${1:- " manual_reset" }
510+
511+ # Log the transition before clearing
512+ local old_session_id=$( get_session_id)
513+
514+ # Clear the session file
515+ if [[ -f " $RALPH_SESSION_FILE " ]]; then
516+ cat > " $RALPH_SESSION_FILE " << EOF
517+ {
518+ "session_id": "",
519+ "created_at": "",
520+ "last_used": "",
521+ "reset_at": "$( get_iso_timestamp) ",
522+ "reset_reason": "$reason "
523+ }
524+ EOF
525+ fi
526+
527+ # Also clear the Claude session file for consistency
528+ if [[ -f " $CLAUDE_SESSION_FILE " ]]; then
529+ rm -f " $CLAUDE_SESSION_FILE "
530+ fi
531+
532+ # Log the session transition
533+ log_session_transition " active" " reset" " $reason " " ${loop_count:- 0} "
534+
535+ log_status " INFO" " Session reset: $reason "
536+ }
537+
538+ # Log session state transitions to history file
539+ # Usage: log_session_transition from_state to_state reason loop_number
540+ log_session_transition () {
541+ local from_state=$1
542+ local to_state=$2
543+ local reason=$3
544+ local loop_number=${4:- 0}
545+
546+ # Initialize history file if needed
547+ if [[ ! -f " $RALPH_SESSION_HISTORY_FILE " ]]; then
548+ echo ' []' > " $RALPH_SESSION_HISTORY_FILE "
549+ fi
550+
551+ # Create transition entry
552+ local transition
553+ transition=$( jq -n \
554+ --arg timestamp " $( get_iso_timestamp) " \
555+ --arg from_state " $from_state " \
556+ --arg to_state " $to_state " \
557+ --arg reason " $reason " \
558+ --argjson loop_number " $loop_number " \
559+ ' {
560+ timestamp: $timestamp,
561+ from_state: $from_state,
562+ to_state: $to_state,
563+ reason: $reason,
564+ loop_number: $loop_number
565+ }' )
566+
567+ # Append to history and keep only last 50 entries
568+ local history=$( cat " $RALPH_SESSION_HISTORY_FILE " 2> /dev/null || echo ' []' )
569+ history=$( echo " $history " | jq " . += [$transition ] | .[-50:]" )
570+ echo " $history " > " $RALPH_SESSION_HISTORY_FILE "
571+ }
572+
573+ # Initialize session tracking (called at loop start)
574+ init_session_tracking () {
575+ # Create session file if it doesn't exist
576+ if [[ ! -f " $RALPH_SESSION_FILE " ]]; then
577+ cat > " $RALPH_SESSION_FILE " << EOF
578+ {
579+ "session_id": "",
580+ "created_at": "$( get_iso_timestamp) ",
581+ "last_used": "",
582+ "reset_at": "",
583+ "reset_reason": ""
584+ }
585+ EOF
586+ log_status " INFO" " Initialized session tracking"
587+ fi
588+
589+ # Validate existing session file
590+ if ! jq empty " $RALPH_SESSION_FILE " 2> /dev/null; then
591+ log_status " WARN" " Corrupted session file detected, recreating..."
592+ cat > " $RALPH_SESSION_FILE " << EOF
593+ {
594+ "session_id": "",
595+ "created_at": "$( get_iso_timestamp) ",
596+ "last_used": "",
597+ "reset_at": "",
598+ "reset_reason": "corrupted_file_recovery"
599+ }
600+ EOF
601+ fi
602+ }
603+
480604# Global array for Claude command arguments (avoids shell injection)
481605declare -a CLAUDE_CMD_ARGS=()
482606
731855# Cleanup function
732856cleanup () {
733857 log_status " INFO" " Ralph loop interrupted. Cleaning up..."
858+ reset_session " manual_interrupt"
734859 update_status " $loop_count " " $( cat " $CALL_COUNT_FILE " 2> /dev/null || echo " 0" ) " " interrupted" " stopped"
735860 exit 0
736861}
@@ -785,6 +910,7 @@ main() {
785910
786911 # Check circuit breaker before attempting execution
787912 if should_halt_execution; then
913+ reset_session " circuit_breaker_open"
788914 update_status " $loop_count " " $( cat " $CALL_COUNT_FILE " ) " " circuit_breaker_open" " halted" " stagnation_detected"
789915 log_status " ERROR" " 🛑 Circuit breaker has opened - execution halted"
790916 break
@@ -800,13 +926,14 @@ main() {
800926 local exit_reason=$( should_exit_gracefully)
801927 if [[ " $exit_reason " != " " ]]; then
802928 log_status " SUCCESS" " 🏁 Graceful exit triggered: $exit_reason "
929+ reset_session " project_complete"
803930 update_status " $loop_count " " $( cat " $CALL_COUNT_FILE " ) " " graceful_exit" " completed" " $exit_reason "
804-
931+
805932 log_status " SUCCESS" " 🎉 Ralph has completed the project! Final stats:"
806933 log_status " INFO" " - Total loops: $loop_count "
807934 log_status " INFO" " - API calls used: $( cat " $CALL_COUNT_FILE " ) "
808935 log_status " INFO" " - Exit reason: $exit_reason "
809-
936+
810937 break
811938 fi
812939
@@ -825,6 +952,7 @@ main() {
825952 sleep 5
826953 elif [ $exec_result -eq 3 ]; then
827954 # Circuit breaker opened
955+ reset_session " circuit_breaker_trip"
828956 update_status " $loop_count " " $( cat " $CALL_COUNT_FILE " ) " " circuit_breaker_open" " halted" " stagnation_detected"
829957 log_status " ERROR" " 🛑 Circuit breaker has opened - halting loop"
830958 log_status " INFO" " Run 'ralph --reset-circuit' to reset the circuit breaker after addressing issues"
@@ -896,6 +1024,7 @@ Options:
8961024 -t, --timeout MIN Set Claude Code execution timeout in minutes (default: $CLAUDE_TIMEOUT_MINUTES )
8971025 --reset-circuit Reset circuit breaker to CLOSED state
8981026 --circuit-status Show circuit breaker status and exit
1027+ --reset-session Reset session state and exit (clears session continuity)
8991028
9001029Modern CLI Options (Phase 1.1):
9011030 --output-format FORMAT Set Claude output format: json or text (default: $CLAUDE_OUTPUT_FORMAT )
@@ -968,7 +1097,17 @@ while [[ $# -gt 0 ]]; do
9681097 # Source the circuit breaker library
9691098 SCRIPT_DIR=" $( dirname " ${BASH_SOURCE[0]} " ) "
9701099 source " $SCRIPT_DIR /lib/circuit_breaker.sh"
1100+ source " $SCRIPT_DIR /lib/date_utils.sh"
9711101 reset_circuit_breaker " Manual reset via command line"
1102+ reset_session " manual_circuit_reset"
1103+ exit 0
1104+ ;;
1105+ --reset-session)
1106+ # Reset session state only
1107+ SCRIPT_DIR=" $( dirname " ${BASH_SOURCE[0]} " ) "
1108+ source " $SCRIPT_DIR /lib/date_utils.sh"
1109+ reset_session " manual_reset_flag"
1110+ echo -e " ${GREEN} ✅ Session state reset successfully${NC} "
9721111 exit 0
9731112 ;;
9741113 --circuit-status)
0 commit comments