bmalph 2.7.3 → 2.7.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/README.md +68 -30
  2. package/dist/commands/doctor-checks.js +5 -4
  3. package/dist/commands/doctor-checks.js.map +1 -1
  4. package/dist/commands/run.js +4 -0
  5. package/dist/commands/run.js.map +1 -1
  6. package/dist/commands/status.js +12 -3
  7. package/dist/commands/status.js.map +1 -1
  8. package/dist/installer.js +101 -48
  9. package/dist/installer.js.map +1 -1
  10. package/dist/platform/cursor-runtime-checks.js +81 -0
  11. package/dist/platform/cursor-runtime-checks.js.map +1 -0
  12. package/dist/platform/cursor.js +4 -3
  13. package/dist/platform/cursor.js.map +1 -1
  14. package/dist/platform/detect.js +28 -5
  15. package/dist/platform/detect.js.map +1 -1
  16. package/dist/platform/instructions-snippet.js +18 -0
  17. package/dist/platform/instructions-snippet.js.map +1 -1
  18. package/dist/platform/resolve.js +23 -5
  19. package/dist/platform/resolve.js.map +1 -1
  20. package/dist/run/ralph-process.js +84 -15
  21. package/dist/run/ralph-process.js.map +1 -1
  22. package/dist/transition/artifact-scan.js +15 -3
  23. package/dist/transition/artifact-scan.js.map +1 -1
  24. package/dist/transition/fix-plan.js +4 -4
  25. package/dist/transition/fix-plan.js.map +1 -1
  26. package/dist/transition/orchestration.js +45 -13
  27. package/dist/transition/orchestration.js.map +1 -1
  28. package/dist/transition/preflight.js +9 -1
  29. package/dist/transition/preflight.js.map +1 -1
  30. package/dist/transition/story-id.js +46 -0
  31. package/dist/transition/story-id.js.map +1 -0
  32. package/dist/transition/story-parsing.js +3 -4
  33. package/dist/transition/story-parsing.js.map +1 -1
  34. package/package.json +1 -1
  35. package/ralph/RALPH-REFERENCE.md +27 -3
  36. package/ralph/drivers/claude-code.sh +44 -2
  37. package/ralph/drivers/codex.sh +10 -1
  38. package/ralph/drivers/copilot.sh +5 -0
  39. package/ralph/drivers/cursor.sh +50 -29
  40. package/ralph/lib/response_analyzer.sh +440 -111
  41. package/ralph/ralph_loop.sh +73 -61
@@ -744,7 +744,7 @@ get_session_file_age_seconds() {
744
744
  echo "$age_seconds"
745
745
  }
746
746
 
747
- # Initialize or resume Claude session (with expiration check)
747
+ # Initialize or resume persisted driver session (with expiration check)
748
748
  #
749
749
  # Session Expiration Strategy:
750
750
  # - Default expiration: 24 hours (configurable via CLAUDE_SESSION_EXPIRY_HOURS)
@@ -786,16 +786,17 @@ init_claude_session() {
786
786
  fi
787
787
 
788
788
  # Session is valid, try to read it
789
- local session_id=$(cat "$CLAUDE_SESSION_FILE" 2>/dev/null)
789
+ local session_id
790
+ session_id=$(get_last_session_id)
790
791
  if [[ -n "$session_id" ]]; then
791
792
  local age_hours=$((age_seconds / 3600))
792
- log_status "INFO" "Resuming Claude session: ${session_id:0:20}... (${age_hours}h old)"
793
+ log_status "INFO" "Resuming session: ${session_id:0:20}... (${age_hours}h old)"
793
794
  echo "$session_id"
794
795
  return 0
795
796
  fi
796
797
  fi
797
798
 
798
- log_status "INFO" "Starting new Claude session"
799
+ log_status "INFO" "Starting new session"
799
800
  echo ""
800
801
  }
801
802
 
@@ -803,12 +804,13 @@ init_claude_session() {
803
804
  save_claude_session() {
804
805
  local output_file=$1
805
806
 
806
- # Try to extract session ID from JSON output
807
+ # Try to extract session ID from structured output
807
808
  if [[ -f "$output_file" ]]; then
808
- local session_id=$(jq -r '.metadata.session_id // .session_id // empty' "$output_file" 2>/dev/null)
809
+ local session_id
810
+ session_id=$(extract_session_id_from_output "$output_file" 2>/dev/null || echo "")
809
811
  if [[ -n "$session_id" && "$session_id" != "null" ]]; then
810
812
  echo "$session_id" > "$CLAUDE_SESSION_FILE"
811
- log_status "INFO" "Saved Claude session: ${session_id:0:20}..."
813
+ log_status "INFO" "Saved session: ${session_id:0:20}..."
812
814
  fi
813
815
  fi
814
816
  }
@@ -1015,6 +1017,7 @@ update_session_last_used() {
1015
1017
 
1016
1018
  # Global array for Claude command arguments (avoids shell injection)
1017
1019
  declare -a CLAUDE_CMD_ARGS=()
1020
+ declare -a LIVE_CMD_ARGS=()
1018
1021
 
1019
1022
  # Build CLI command with platform driver (shell-injection safe)
1020
1023
  # Delegates to the active platform driver's driver_build_command()
@@ -1023,6 +1026,45 @@ build_claude_command() {
1023
1026
  driver_build_command "$@"
1024
1027
  }
1025
1028
 
1029
+ supports_driver_sessions() {
1030
+ if declare -F driver_supports_sessions >/dev/null; then
1031
+ driver_supports_sessions
1032
+ return $?
1033
+ fi
1034
+
1035
+ return 0
1036
+ }
1037
+
1038
+ supports_live_output() {
1039
+ if declare -F driver_supports_live_output >/dev/null; then
1040
+ driver_supports_live_output
1041
+ return $?
1042
+ fi
1043
+
1044
+ return 0
1045
+ }
1046
+
1047
+ prepare_live_command_args() {
1048
+ LIVE_CMD_ARGS=("${CLAUDE_CMD_ARGS[@]}")
1049
+
1050
+ if declare -F driver_prepare_live_command >/dev/null; then
1051
+ driver_prepare_live_command
1052
+ return $?
1053
+ fi
1054
+
1055
+ return 0
1056
+ }
1057
+
1058
+ get_live_stream_filter() {
1059
+ if declare -F driver_stream_filter >/dev/null; then
1060
+ driver_stream_filter
1061
+ return 0
1062
+ fi
1063
+
1064
+ echo "empty"
1065
+ return 1
1066
+ }
1067
+
1026
1068
  # Main execution function
1027
1069
  execute_claude_code() {
1028
1070
  local timestamp=$(date '+%Y-%m-%d_%H-%M-%S')
@@ -1054,7 +1096,7 @@ execute_claude_code() {
1054
1096
 
1055
1097
  # Initialize or resume session
1056
1098
  local session_id=""
1057
- if [[ "$CLAUDE_USE_CONTINUE" == "true" ]]; then
1099
+ if [[ "$CLAUDE_USE_CONTINUE" == "true" ]] && supports_driver_sessions; then
1058
1100
  session_id=$(init_claude_session)
1059
1101
  fi
1060
1102
 
@@ -1094,11 +1136,16 @@ execute_claude_code() {
1094
1136
  # - --continue (session continuity)
1095
1137
  # - -p (prompt content)
1096
1138
 
1139
+ if ! supports_live_output; then
1140
+ log_status "WARN" "$DRIVER_DISPLAY_NAME does not support structured live streaming. Falling back to background mode."
1141
+ LIVE_OUTPUT=false
1142
+ fi
1143
+
1097
1144
  # Check dependencies for live mode
1098
- if ! command -v jq &> /dev/null; then
1145
+ if [[ "$LIVE_OUTPUT" == "true" ]] && ! command -v jq &> /dev/null; then
1099
1146
  log_status "ERROR" "Live mode requires 'jq' but it's not installed. Falling back to background mode."
1100
1147
  LIVE_OUTPUT=false
1101
- elif ! command -v stdbuf &> /dev/null; then
1148
+ elif [[ "$LIVE_OUTPUT" == "true" ]] && ! command -v stdbuf &> /dev/null; then
1102
1149
  log_status "ERROR" "Live mode requires 'stdbuf' (from coreutils) but it's not installed. Falling back to background mode."
1103
1150
  LIVE_OUTPUT=false
1104
1151
  fi
@@ -1116,42 +1163,15 @@ execute_claude_code() {
1116
1163
  log_status "INFO" "šŸ“ŗ Live output mode enabled - showing $DRIVER_DISPLAY_NAME streaming..."
1117
1164
  echo -e "${PURPLE}━━━━━━━━━━━━━━━━ ${DRIVER_DISPLAY_NAME} Output ━━━━━━━━━━━━━━━━${NC}"
1118
1165
 
1119
- # Modify CLAUDE_CMD_ARGS: replace --output-format value with stream-json
1120
- # and add streaming-specific flags
1121
- local -a LIVE_CMD_ARGS=()
1122
- local skip_next=false
1123
- for arg in "${CLAUDE_CMD_ARGS[@]}"; do
1124
- if [[ "$skip_next" == "true" ]]; then
1125
- # Replace "json" with "stream-json" for output format
1126
- LIVE_CMD_ARGS+=("stream-json")
1127
- skip_next=false
1128
- elif [[ "$arg" == "--output-format" ]]; then
1129
- LIVE_CMD_ARGS+=("$arg")
1130
- skip_next=true
1131
- else
1132
- LIVE_CMD_ARGS+=("$arg")
1133
- fi
1134
- done
1166
+ if ! prepare_live_command_args; then
1167
+ log_status "ERROR" "Failed to prepare live streaming command. Falling back to background mode."
1168
+ LIVE_OUTPUT=false
1169
+ fi
1170
+ fi
1135
1171
 
1136
- # Add streaming-specific flags (--verbose and --include-partial-messages)
1137
- # These are required for stream-json to work properly
1138
- LIVE_CMD_ARGS+=("--verbose" "--include-partial-messages")
1139
-
1140
- # jq filter: show text + tool names + newlines for readability
1141
- local jq_filter='
1142
- if .type == "stream_event" then
1143
- if .event.type == "content_block_delta" and .event.delta.type == "text_delta" then
1144
- .event.delta.text
1145
- elif .event.type == "content_block_start" and .event.content_block.type == "tool_use" then
1146
- "\n\n⚔ [" + .event.content_block.name + "]\n"
1147
- elif .event.type == "content_block_stop" then
1148
- "\n"
1149
- else
1150
- empty
1151
- end
1152
- else
1153
- empty
1154
- end'
1172
+ if [[ "$LIVE_OUTPUT" == "true" ]]; then
1173
+ local jq_filter
1174
+ jq_filter=$(get_live_stream_filter)
1155
1175
 
1156
1176
  # Execute with streaming, preserving all flags from build_claude_command()
1157
1177
  # Use stdbuf to disable buffering for real-time output
@@ -1183,34 +1203,26 @@ execute_claude_code() {
1183
1203
  echo ""
1184
1204
  echo -e "${PURPLE}━━━━━━━━━━━━━━━━ End of Output ━━━━━━━━━━━━━━━━━━━${NC}"
1185
1205
 
1186
- # Extract session ID from stream-json output for session continuity
1187
- # Stream-json format has session_id in the final "result" type message
1188
- # Keep full stream output in _stream.log, extract session data separately
1206
+ # Preserve full stream output for downstream analysis and session extraction.
1207
+ # Claude-style stream_json can be collapsed to the final result record,
1208
+ # while Codex JSONL should remain as event output for the shared parser.
1189
1209
  if [[ "$CLAUDE_USE_CONTINUE" == "true" && -f "$output_file" ]]; then
1190
- # Preserve full stream output for analysis (don't overwrite output_file)
1191
1210
  local stream_output_file="${output_file%.log}_stream.log"
1192
1211
  cp "$output_file" "$stream_output_file"
1193
1212
 
1194
- # Extract the result message and convert to standard JSON format
1195
- # Use flexible regex to match various JSON formatting styles
1196
- # Matches: "type":"result", "type": "result", "type" : "result"
1213
+ # Collapse Claude-style stream_json to the final result object when present.
1197
1214
  local result_line=$(grep -E '"type"[[:space:]]*:[[:space:]]*"result"' "$output_file" 2>/dev/null | tail -1)
1198
1215
 
1199
1216
  if [[ -n "$result_line" ]]; then
1200
- # Validate that extracted line is valid JSON before using it
1201
1217
  if echo "$result_line" | jq -e . >/dev/null 2>&1; then
1202
- # Write validated result as the output_file for downstream processing
1203
- # (save_claude_session and analyze_response expect JSON format)
1204
1218
  echo "$result_line" > "$output_file"
1205
- log_status "INFO" "Extracted and validated session data from stream output"
1219
+ log_status "INFO" "Collapsed streamed response to the final result record"
1206
1220
  else
1207
- log_status "WARN" "Extracted result line is not valid JSON, keeping stream output"
1208
- # Restore original stream output
1209
1221
  cp "$stream_output_file" "$output_file"
1222
+ log_status "WARN" "Final result record was invalid JSON, keeping full stream output"
1210
1223
  fi
1211
1224
  else
1212
- log_status "WARN" "Could not find result message in stream output"
1213
- # Keep stream output as-is for debugging
1225
+ log_status "INFO" "Keeping full stream output for shared response analysis"
1214
1226
  fi
1215
1227
  fi
1216
1228
  else
@@ -1305,7 +1317,7 @@ EOF
1305
1317
  log_status "SUCCESS" "āœ… $DRIVER_DISPLAY_NAME execution completed successfully"
1306
1318
 
1307
1319
  # Save session ID from JSON output (Phase 1.1)
1308
- if [[ "$CLAUDE_USE_CONTINUE" == "true" ]]; then
1320
+ if [[ "$CLAUDE_USE_CONTINUE" == "true" ]] && supports_driver_sessions; then
1309
1321
  save_claude_session "$output_file"
1310
1322
  fi
1311
1323