bmalph 2.7.2 โ 2.7.4
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.
- package/README.md +14 -4
- package/dist/commands/doctor-checks.js +17 -10
- package/dist/commands/doctor-checks.js.map +1 -1
- package/dist/run/ralph-process.js +101 -7
- package/dist/run/ralph-process.js.map +1 -1
- package/dist/transition/artifact-collection.js +74 -0
- package/dist/transition/artifact-collection.js.map +1 -0
- package/dist/transition/artifacts.js +12 -1
- package/dist/transition/artifacts.js.map +1 -1
- package/dist/transition/context.js +17 -25
- package/dist/transition/context.js.map +1 -1
- package/dist/transition/fix-plan.js +12 -7
- package/dist/transition/fix-plan.js.map +1 -1
- package/dist/transition/orchestration.js +213 -116
- package/dist/transition/orchestration.js.map +1 -1
- package/dist/transition/preflight.js +30 -17
- package/dist/transition/preflight.js.map +1 -1
- package/dist/transition/section-patterns.js +56 -4
- package/dist/transition/section-patterns.js.map +1 -1
- package/dist/transition/specs-index.js +5 -2
- package/dist/transition/specs-index.js.map +1 -1
- package/dist/transition/specs-sync.js +23 -0
- package/dist/transition/specs-sync.js.map +1 -0
- package/dist/transition/sprint-status.js +91 -0
- package/dist/transition/sprint-status.js.map +1 -0
- package/dist/transition/story-id.js +46 -0
- package/dist/transition/story-id.js.map +1 -0
- package/dist/transition/story-parsing.js +7 -7
- package/dist/transition/story-parsing.js.map +1 -1
- package/dist/transition/tech-stack.js +1 -7
- package/dist/transition/tech-stack.js.map +1 -1
- package/package.json +1 -1
- package/ralph/RALPH-REFERENCE.md +50 -46
- package/ralph/drivers/claude-code.sh +44 -2
- package/ralph/drivers/codex.sh +10 -1
- package/ralph/drivers/copilot.sh +5 -0
- package/ralph/drivers/cursor-agent-wrapper.sh +13 -0
- package/ralph/drivers/cursor.sh +178 -14
- package/ralph/lib/circuit_breaker.sh +5 -5
- package/ralph/lib/enable_core.sh +10 -10
- package/ralph/lib/response_analyzer.sh +357 -111
- package/ralph/ralph_import.sh +14 -10
- package/ralph/ralph_loop.sh +168 -119
- package/ralph/ralph_monitor.sh +4 -4
- package/ralph/templates/AGENT.md +7 -7
- package/ralph/templates/PROMPT.md +13 -13
package/ralph/ralph_import.sh
CHANGED
|
@@ -272,11 +272,14 @@ Supported formats:
|
|
|
272
272
|
- PDFs (.pdf)
|
|
273
273
|
- Any text-based format
|
|
274
274
|
|
|
275
|
+
This legacy helper is kept for standalone Ralph compatibility.
|
|
276
|
+
If you are using bmalph, use `bmalph implement` instead.
|
|
277
|
+
|
|
275
278
|
The command will:
|
|
276
279
|
1. Create a new Ralph project
|
|
277
280
|
2. Use Claude Code to intelligently convert your PRD into:
|
|
278
281
|
- .ralph/PROMPT.md (Ralph instructions)
|
|
279
|
-
- .ralph
|
|
282
|
+
- .ralph/@fix_plan.md (prioritized tasks)
|
|
280
283
|
- .ralph/specs/ (technical specifications)
|
|
281
284
|
|
|
282
285
|
HELPEOF
|
|
@@ -320,7 +323,7 @@ convert_prd() {
|
|
|
320
323
|
cat > "$CONVERSION_PROMPT_FILE" << 'PROMPTEOF'
|
|
321
324
|
# PRD to Ralph Conversion Task
|
|
322
325
|
|
|
323
|
-
You are tasked with converting a Product Requirements Document (PRD) or specification into Ralph
|
|
326
|
+
You are tasked with converting a Product Requirements Document (PRD) or specification into Ralph's autonomous implementation format.
|
|
324
327
|
|
|
325
328
|
## Input Analysis
|
|
326
329
|
Analyze the provided specification file and extract:
|
|
@@ -350,7 +353,7 @@ You are Ralph, an autonomous AI development agent working on a [PROJECT NAME] pr
|
|
|
350
353
|
- Search the codebase before assuming something isn't implemented
|
|
351
354
|
- Use subagents for expensive operations (file searching, analysis)
|
|
352
355
|
- Write comprehensive tests with clear documentation
|
|
353
|
-
- Update fix_plan.md with your learnings
|
|
356
|
+
- Update @fix_plan.md with your learnings
|
|
354
357
|
- Commit working changes with descriptive messages
|
|
355
358
|
|
|
356
359
|
## ๐งช Testing Guidelines (CRITICAL)
|
|
@@ -370,10 +373,10 @@ You are Ralph, an autonomous AI development agent working on a [PROJECT NAME] pr
|
|
|
370
373
|
[Define what "done" looks like based on the PRD]
|
|
371
374
|
|
|
372
375
|
## Current Task
|
|
373
|
-
Follow fix_plan.md and choose the most important item to implement next.
|
|
376
|
+
Follow @fix_plan.md and choose the most important item to implement next.
|
|
374
377
|
```
|
|
375
378
|
|
|
376
|
-
### 2. .ralph
|
|
379
|
+
### 2. .ralph/@fix_plan.md
|
|
377
380
|
Convert requirements into a prioritized task list:
|
|
378
381
|
```markdown
|
|
379
382
|
# Ralph Fix Plan
|
|
@@ -416,7 +419,7 @@ Create detailed technical specifications:
|
|
|
416
419
|
2. Create the three files above with content derived from the PRD
|
|
417
420
|
3. Ensure all requirements are captured and properly prioritized
|
|
418
421
|
4. Make the PROMPT.md actionable for autonomous development
|
|
419
|
-
5. Structure fix_plan.md with clear, implementable tasks
|
|
422
|
+
5. Structure @fix_plan.md with clear, implementable tasks
|
|
420
423
|
|
|
421
424
|
PROMPTEOF
|
|
422
425
|
|
|
@@ -527,7 +530,7 @@ PROMPTEOF
|
|
|
527
530
|
# Use PARSED_FILES_CREATED from JSON if available, otherwise check filesystem
|
|
528
531
|
local missing_files=()
|
|
529
532
|
local created_files=()
|
|
530
|
-
local expected_files=(".ralph/PROMPT.md" ".ralph
|
|
533
|
+
local expected_files=(".ralph/PROMPT.md" ".ralph/@fix_plan.md" ".ralph/specs/requirements.md")
|
|
531
534
|
|
|
532
535
|
# If JSON provided files_created, use that to inform verification
|
|
533
536
|
if [[ "$json_parsed" == "true" && -n "$PARSED_FILES_CREATED" && "$PARSED_FILES_CREATED" != "[]" ]]; then
|
|
@@ -632,10 +635,11 @@ main() {
|
|
|
632
635
|
echo "Next steps:"
|
|
633
636
|
echo " 1. Review and edit the generated files:"
|
|
634
637
|
echo " - .ralph/PROMPT.md (Ralph instructions)"
|
|
635
|
-
echo " - .ralph
|
|
638
|
+
echo " - .ralph/@fix_plan.md (task priorities)"
|
|
636
639
|
echo " - .ralph/specs/requirements.md (technical specs)"
|
|
637
640
|
echo " 2. Start autonomous development:"
|
|
638
|
-
echo " ralph --monitor"
|
|
641
|
+
echo " ralph --monitor # standalone Ralph"
|
|
642
|
+
echo " bmalph run # bmalph-managed projects"
|
|
639
643
|
echo ""
|
|
640
644
|
echo "Project created in: $(pwd)"
|
|
641
645
|
}
|
|
@@ -649,4 +653,4 @@ case "${1:-}" in
|
|
|
649
653
|
*)
|
|
650
654
|
main "$@"
|
|
651
655
|
;;
|
|
652
|
-
esac
|
|
656
|
+
esac
|
package/ralph/ralph_loop.sh
CHANGED
|
@@ -26,6 +26,7 @@ DOCS_DIR="$RALPH_DIR/docs/generated"
|
|
|
26
26
|
STATUS_FILE="$RALPH_DIR/status.json"
|
|
27
27
|
PROGRESS_FILE="$RALPH_DIR/progress.json"
|
|
28
28
|
CLAUDE_CODE_CMD="claude"
|
|
29
|
+
DRIVER_DISPLAY_NAME="Claude Code"
|
|
29
30
|
SLEEP_DURATION=3600 # 1 hour in seconds
|
|
30
31
|
LIVE_OUTPUT=false # Show Claude Code output in real-time (streaming)
|
|
31
32
|
LIVE_LOG_FILE="$RALPH_DIR/live.log" # Fixed file for live output monitoring
|
|
@@ -95,17 +96,36 @@ MAX_CONSECUTIVE_TEST_LOOPS=3
|
|
|
95
96
|
MAX_CONSECUTIVE_DONE_SIGNALS=2
|
|
96
97
|
TEST_PERCENTAGE_THRESHOLD=30 # If more than 30% of recent loops are test-only, flag it
|
|
97
98
|
|
|
98
|
-
#
|
|
99
|
-
|
|
99
|
+
# Ralph configuration file
|
|
100
|
+
# bmalph installs .ralph/.ralphrc. Fall back to a project-root .ralphrc for
|
|
101
|
+
# older standalone Ralph layouts.
|
|
102
|
+
RALPHRC_FILE="${RALPHRC_FILE:-$RALPH_DIR/.ralphrc}"
|
|
100
103
|
RALPHRC_LOADED=false
|
|
101
104
|
|
|
102
105
|
# Platform driver (set from .ralphrc or environment)
|
|
103
106
|
PLATFORM_DRIVER="${PLATFORM_DRIVER:-claude-code}"
|
|
107
|
+
RUNTIME_CONTEXT_LOADED=false
|
|
104
108
|
|
|
105
|
-
#
|
|
109
|
+
# resolve_ralphrc_file - Resolve the Ralph config path
|
|
110
|
+
resolve_ralphrc_file() {
|
|
111
|
+
if [[ -f "$RALPHRC_FILE" ]]; then
|
|
112
|
+
echo "$RALPHRC_FILE"
|
|
113
|
+
return 0
|
|
114
|
+
fi
|
|
115
|
+
|
|
116
|
+
if [[ "$RALPHRC_FILE" != ".ralphrc" && -f ".ralphrc" ]]; then
|
|
117
|
+
echo ".ralphrc"
|
|
118
|
+
return 0
|
|
119
|
+
fi
|
|
120
|
+
|
|
121
|
+
echo "$RALPHRC_FILE"
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
# load_ralphrc - Load project-specific configuration from .ralph/.ralphrc
|
|
106
125
|
#
|
|
107
|
-
# This function sources .ralphrc
|
|
108
|
-
#
|
|
126
|
+
# This function sources the bundled .ralph/.ralphrc file when present, falling
|
|
127
|
+
# back to a project-root .ralphrc for older standalone Ralph layouts.
|
|
128
|
+
# Environment variables take precedence over config values.
|
|
109
129
|
#
|
|
110
130
|
# Configuration values that can be overridden:
|
|
111
131
|
# - MAX_CALLS_PER_HOUR
|
|
@@ -120,15 +140,18 @@ PLATFORM_DRIVER="${PLATFORM_DRIVER:-claude-code}"
|
|
|
120
140
|
# - RALPH_VERBOSE
|
|
121
141
|
#
|
|
122
142
|
load_ralphrc() {
|
|
123
|
-
|
|
143
|
+
local config_file
|
|
144
|
+
config_file="$(resolve_ralphrc_file)"
|
|
145
|
+
|
|
146
|
+
if [[ ! -f "$config_file" ]]; then
|
|
124
147
|
return 0
|
|
125
148
|
fi
|
|
126
149
|
|
|
127
|
-
# Source
|
|
150
|
+
# Source config (this may override default values)
|
|
128
151
|
# shellcheck source=/dev/null
|
|
129
|
-
source "$
|
|
152
|
+
source "$config_file"
|
|
130
153
|
|
|
131
|
-
# Map
|
|
154
|
+
# Map config variable names to internal names
|
|
132
155
|
if [[ -n "${ALLOWED_TOOLS:-}" ]]; then
|
|
133
156
|
CLAUDE_ALLOWED_TOOLS="$ALLOWED_TOOLS"
|
|
134
157
|
fi
|
|
@@ -155,6 +178,7 @@ load_ralphrc() {
|
|
|
155
178
|
[[ -n "$_env_CB_COOLDOWN_MINUTES" ]] && CB_COOLDOWN_MINUTES="$_env_CB_COOLDOWN_MINUTES"
|
|
156
179
|
[[ -n "$_env_CB_AUTO_RESET" ]] && CB_AUTO_RESET="$_env_CB_AUTO_RESET"
|
|
157
180
|
|
|
181
|
+
RALPHRC_FILE="$config_file"
|
|
158
182
|
RALPHRC_LOADED=true
|
|
159
183
|
return 0
|
|
160
184
|
}
|
|
@@ -175,8 +199,25 @@ load_platform_driver() {
|
|
|
175
199
|
|
|
176
200
|
# Set CLI binary from driver
|
|
177
201
|
CLAUDE_CODE_CMD="$(driver_cli_binary)"
|
|
202
|
+
DRIVER_DISPLAY_NAME="$(driver_display_name)"
|
|
178
203
|
|
|
179
|
-
log_status "INFO" "Platform driver: $
|
|
204
|
+
log_status "INFO" "Platform driver: $DRIVER_DISPLAY_NAME ($CLAUDE_CODE_CMD)"
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
initialize_runtime_context() {
|
|
208
|
+
if [[ "$RUNTIME_CONTEXT_LOADED" == "true" ]]; then
|
|
209
|
+
return 0
|
|
210
|
+
fi
|
|
211
|
+
|
|
212
|
+
if load_ralphrc; then
|
|
213
|
+
if [[ "$RALPHRC_LOADED" == "true" ]]; then
|
|
214
|
+
log_status "INFO" "Loaded configuration from $RALPHRC_FILE"
|
|
215
|
+
fi
|
|
216
|
+
fi
|
|
217
|
+
|
|
218
|
+
# Load platform driver after config so PLATFORM_DRIVER can be overridden.
|
|
219
|
+
load_platform_driver
|
|
220
|
+
RUNTIME_CONTEXT_LOADED=true
|
|
180
221
|
}
|
|
181
222
|
|
|
182
223
|
# Colors for terminal output
|
|
@@ -217,6 +258,8 @@ setup_tmux_session() {
|
|
|
217
258
|
local ralph_home="${RALPH_HOME:-$HOME/.ralph}"
|
|
218
259
|
local project_dir="$(pwd)"
|
|
219
260
|
|
|
261
|
+
initialize_runtime_context
|
|
262
|
+
|
|
220
263
|
# Get the tmux base-index to handle custom configurations (e.g., base-index 1)
|
|
221
264
|
local base_win
|
|
222
265
|
base_win=$(get_tmux_base_index)
|
|
@@ -235,7 +278,7 @@ setup_tmux_session() {
|
|
|
235
278
|
# Split right pane horizontally (top: Claude output, bottom: status)
|
|
236
279
|
tmux split-window -v -t "$session_name:${base_win}.1" -c "$project_dir"
|
|
237
280
|
|
|
238
|
-
# Right-top pane (pane 1): Live
|
|
281
|
+
# Right-top pane (pane 1): Live driver output
|
|
239
282
|
tmux send-keys -t "$session_name:${base_win}.1" "tail -f '$project_dir/$LIVE_LOG_FILE'" Enter
|
|
240
283
|
|
|
241
284
|
# Right-bottom pane (pane 2): Ralph status monitor
|
|
@@ -304,7 +347,7 @@ setup_tmux_session() {
|
|
|
304
347
|
|
|
305
348
|
# Set pane titles (requires tmux 2.6+)
|
|
306
349
|
tmux select-pane -t "$session_name:${base_win}.0" -T "Ralph Loop"
|
|
307
|
-
tmux select-pane -t "$session_name:${base_win}.1" -T "
|
|
350
|
+
tmux select-pane -t "$session_name:${base_win}.1" -T "$DRIVER_DISPLAY_NAME Output"
|
|
308
351
|
tmux select-pane -t "$session_name:${base_win}.2" -T "Status"
|
|
309
352
|
|
|
310
353
|
# Set window title
|
|
@@ -312,7 +355,7 @@ setup_tmux_session() {
|
|
|
312
355
|
|
|
313
356
|
log_status "SUCCESS" "Tmux session created with 3 panes:"
|
|
314
357
|
log_status "INFO" " Left: Ralph loop"
|
|
315
|
-
log_status "INFO" " Right-top:
|
|
358
|
+
log_status "INFO" " Right-top: $DRIVER_DISPLAY_NAME live output"
|
|
316
359
|
log_status "INFO" " Right-bottom: Status monitor"
|
|
317
360
|
log_status "INFO" ""
|
|
318
361
|
log_status "INFO" "Use Ctrl+B then D to detach from session"
|
|
@@ -701,7 +744,7 @@ get_session_file_age_seconds() {
|
|
|
701
744
|
echo "$age_seconds"
|
|
702
745
|
}
|
|
703
746
|
|
|
704
|
-
# Initialize or resume
|
|
747
|
+
# Initialize or resume persisted driver session (with expiration check)
|
|
705
748
|
#
|
|
706
749
|
# Session Expiration Strategy:
|
|
707
750
|
# - Default expiration: 24 hours (configurable via CLAUDE_SESSION_EXPIRY_HOURS)
|
|
@@ -743,16 +786,17 @@ init_claude_session() {
|
|
|
743
786
|
fi
|
|
744
787
|
|
|
745
788
|
# Session is valid, try to read it
|
|
746
|
-
local session_id
|
|
789
|
+
local session_id
|
|
790
|
+
session_id=$(get_last_session_id)
|
|
747
791
|
if [[ -n "$session_id" ]]; then
|
|
748
792
|
local age_hours=$((age_seconds / 3600))
|
|
749
|
-
log_status "INFO" "Resuming
|
|
793
|
+
log_status "INFO" "Resuming session: ${session_id:0:20}... (${age_hours}h old)"
|
|
750
794
|
echo "$session_id"
|
|
751
795
|
return 0
|
|
752
796
|
fi
|
|
753
797
|
fi
|
|
754
798
|
|
|
755
|
-
log_status "INFO" "Starting new
|
|
799
|
+
log_status "INFO" "Starting new session"
|
|
756
800
|
echo ""
|
|
757
801
|
}
|
|
758
802
|
|
|
@@ -760,12 +804,13 @@ init_claude_session() {
|
|
|
760
804
|
save_claude_session() {
|
|
761
805
|
local output_file=$1
|
|
762
806
|
|
|
763
|
-
# Try to extract session ID from
|
|
807
|
+
# Try to extract session ID from structured output
|
|
764
808
|
if [[ -f "$output_file" ]]; then
|
|
765
|
-
local session_id
|
|
809
|
+
local session_id
|
|
810
|
+
session_id=$(extract_session_id_from_output "$output_file" 2>/dev/null || echo "")
|
|
766
811
|
if [[ -n "$session_id" && "$session_id" != "null" ]]; then
|
|
767
812
|
echo "$session_id" > "$CLAUDE_SESSION_FILE"
|
|
768
|
-
log_status "INFO" "Saved
|
|
813
|
+
log_status "INFO" "Saved session: ${session_id:0:20}..."
|
|
769
814
|
fi
|
|
770
815
|
fi
|
|
771
816
|
}
|
|
@@ -972,6 +1017,7 @@ update_session_last_used() {
|
|
|
972
1017
|
|
|
973
1018
|
# Global array for Claude command arguments (avoids shell injection)
|
|
974
1019
|
declare -a CLAUDE_CMD_ARGS=()
|
|
1020
|
+
declare -a LIVE_CMD_ARGS=()
|
|
975
1021
|
|
|
976
1022
|
# Build CLI command with platform driver (shell-injection safe)
|
|
977
1023
|
# Delegates to the active platform driver's driver_build_command()
|
|
@@ -980,6 +1026,45 @@ build_claude_command() {
|
|
|
980
1026
|
driver_build_command "$@"
|
|
981
1027
|
}
|
|
982
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
|
+
|
|
983
1068
|
# Main execution function
|
|
984
1069
|
execute_claude_code() {
|
|
985
1070
|
local timestamp=$(date '+%Y-%m-%d_%H-%M-%S')
|
|
@@ -996,9 +1081,9 @@ execute_claude_code() {
|
|
|
996
1081
|
fi
|
|
997
1082
|
echo "$loop_start_sha" > "$RALPH_DIR/.loop_start_sha"
|
|
998
1083
|
|
|
999
|
-
log_status "LOOP" "Executing
|
|
1084
|
+
log_status "LOOP" "Executing $DRIVER_DISPLAY_NAME (Call $calls_made/$MAX_CALLS_PER_HOUR)"
|
|
1000
1085
|
local timeout_seconds=$((CLAUDE_TIMEOUT_MINUTES * 60))
|
|
1001
|
-
log_status "INFO" "โณ Starting
|
|
1086
|
+
log_status "INFO" "โณ Starting $DRIVER_DISPLAY_NAME execution... (timeout: ${CLAUDE_TIMEOUT_MINUTES}m)"
|
|
1002
1087
|
|
|
1003
1088
|
# Build loop context for session continuity
|
|
1004
1089
|
local loop_context=""
|
|
@@ -1011,7 +1096,7 @@ execute_claude_code() {
|
|
|
1011
1096
|
|
|
1012
1097
|
# Initialize or resume session
|
|
1013
1098
|
local session_id=""
|
|
1014
|
-
if [[ "$CLAUDE_USE_CONTINUE" == "true" ]]; then
|
|
1099
|
+
if [[ "$CLAUDE_USE_CONTINUE" == "true" ]] && supports_driver_sessions; then
|
|
1015
1100
|
session_id=$(init_claude_session)
|
|
1016
1101
|
fi
|
|
1017
1102
|
|
|
@@ -1051,11 +1136,16 @@ execute_claude_code() {
|
|
|
1051
1136
|
# - --continue (session continuity)
|
|
1052
1137
|
# - -p (prompt content)
|
|
1053
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
|
+
|
|
1054
1144
|
# Check dependencies for live mode
|
|
1055
|
-
if ! command -v jq &> /dev/null; then
|
|
1145
|
+
if [[ "$LIVE_OUTPUT" == "true" ]] && ! command -v jq &> /dev/null; then
|
|
1056
1146
|
log_status "ERROR" "Live mode requires 'jq' but it's not installed. Falling back to background mode."
|
|
1057
1147
|
LIVE_OUTPUT=false
|
|
1058
|
-
elif ! command -v stdbuf &> /dev/null; then
|
|
1148
|
+
elif [[ "$LIVE_OUTPUT" == "true" ]] && ! command -v stdbuf &> /dev/null; then
|
|
1059
1149
|
log_status "ERROR" "Live mode requires 'stdbuf' (from coreutils) but it's not installed. Falling back to background mode."
|
|
1060
1150
|
LIVE_OUTPUT=false
|
|
1061
1151
|
fi
|
|
@@ -1070,45 +1160,18 @@ execute_claude_code() {
|
|
|
1070
1160
|
fi
|
|
1071
1161
|
|
|
1072
1162
|
if [[ "$LIVE_OUTPUT" == "true" ]]; then
|
|
1073
|
-
log_status "INFO" "๐บ Live output mode enabled - showing
|
|
1074
|
-
echo -e "${PURPLE}โโโโโโโโโโโโโโโโ
|
|
1075
|
-
|
|
1076
|
-
# Modify CLAUDE_CMD_ARGS: replace --output-format value with stream-json
|
|
1077
|
-
# and add streaming-specific flags
|
|
1078
|
-
local -a LIVE_CMD_ARGS=()
|
|
1079
|
-
local skip_next=false
|
|
1080
|
-
for arg in "${CLAUDE_CMD_ARGS[@]}"; do
|
|
1081
|
-
if [[ "$skip_next" == "true" ]]; then
|
|
1082
|
-
# Replace "json" with "stream-json" for output format
|
|
1083
|
-
LIVE_CMD_ARGS+=("stream-json")
|
|
1084
|
-
skip_next=false
|
|
1085
|
-
elif [[ "$arg" == "--output-format" ]]; then
|
|
1086
|
-
LIVE_CMD_ARGS+=("$arg")
|
|
1087
|
-
skip_next=true
|
|
1088
|
-
else
|
|
1089
|
-
LIVE_CMD_ARGS+=("$arg")
|
|
1090
|
-
fi
|
|
1091
|
-
done
|
|
1163
|
+
log_status "INFO" "๐บ Live output mode enabled - showing $DRIVER_DISPLAY_NAME streaming..."
|
|
1164
|
+
echo -e "${PURPLE}โโโโโโโโโโโโโโโโ ${DRIVER_DISPLAY_NAME} Output โโโโโโโโโโโโโโโโ${NC}"
|
|
1092
1165
|
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
elif .event.type == "content_block_start" and .event.content_block.type == "tool_use" then
|
|
1103
|
-
"\n\nโก [" + .event.content_block.name + "]\n"
|
|
1104
|
-
elif .event.type == "content_block_stop" then
|
|
1105
|
-
"\n"
|
|
1106
|
-
else
|
|
1107
|
-
empty
|
|
1108
|
-
end
|
|
1109
|
-
else
|
|
1110
|
-
empty
|
|
1111
|
-
end'
|
|
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
|
|
1171
|
+
|
|
1172
|
+
if [[ "$LIVE_OUTPUT" == "true" ]]; then
|
|
1173
|
+
local jq_filter
|
|
1174
|
+
jq_filter=$(get_live_stream_filter)
|
|
1112
1175
|
|
|
1113
1176
|
# Execute with streaming, preserving all flags from build_claude_command()
|
|
1114
1177
|
# Use stdbuf to disable buffering for real-time output
|
|
@@ -1140,34 +1203,26 @@ execute_claude_code() {
|
|
|
1140
1203
|
echo ""
|
|
1141
1204
|
echo -e "${PURPLE}โโโโโโโโโโโโโโโโ End of Output โโโโโโโโโโโโโโโโโโโ${NC}"
|
|
1142
1205
|
|
|
1143
|
-
#
|
|
1144
|
-
#
|
|
1145
|
-
#
|
|
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.
|
|
1146
1209
|
if [[ "$CLAUDE_USE_CONTINUE" == "true" && -f "$output_file" ]]; then
|
|
1147
|
-
# Preserve full stream output for analysis (don't overwrite output_file)
|
|
1148
1210
|
local stream_output_file="${output_file%.log}_stream.log"
|
|
1149
1211
|
cp "$output_file" "$stream_output_file"
|
|
1150
1212
|
|
|
1151
|
-
#
|
|
1152
|
-
# Use flexible regex to match various JSON formatting styles
|
|
1153
|
-
# Matches: "type":"result", "type": "result", "type" : "result"
|
|
1213
|
+
# Collapse Claude-style stream_json to the final result object when present.
|
|
1154
1214
|
local result_line=$(grep -E '"type"[[:space:]]*:[[:space:]]*"result"' "$output_file" 2>/dev/null | tail -1)
|
|
1155
1215
|
|
|
1156
1216
|
if [[ -n "$result_line" ]]; then
|
|
1157
|
-
# Validate that extracted line is valid JSON before using it
|
|
1158
1217
|
if echo "$result_line" | jq -e . >/dev/null 2>&1; then
|
|
1159
|
-
# Write validated result as the output_file for downstream processing
|
|
1160
|
-
# (save_claude_session and analyze_response expect JSON format)
|
|
1161
1218
|
echo "$result_line" > "$output_file"
|
|
1162
|
-
log_status "INFO" "
|
|
1219
|
+
log_status "INFO" "Collapsed streamed response to the final result record"
|
|
1163
1220
|
else
|
|
1164
|
-
log_status "WARN" "Extracted result line is not valid JSON, keeping stream output"
|
|
1165
|
-
# Restore original stream output
|
|
1166
1221
|
cp "$stream_output_file" "$output_file"
|
|
1222
|
+
log_status "WARN" "Final result record was invalid JSON, keeping full stream output"
|
|
1167
1223
|
fi
|
|
1168
1224
|
else
|
|
1169
|
-
log_status "
|
|
1170
|
-
# Keep stream output as-is for debugging
|
|
1225
|
+
log_status "INFO" "Keeping full stream output for shared response analysis"
|
|
1171
1226
|
fi
|
|
1172
1227
|
fi
|
|
1173
1228
|
else
|
|
@@ -1182,7 +1237,7 @@ execute_claude_code() {
|
|
|
1182
1237
|
then
|
|
1183
1238
|
: # Continue to wait loop
|
|
1184
1239
|
else
|
|
1185
|
-
log_status "ERROR" "โ Failed to start
|
|
1240
|
+
log_status "ERROR" "โ Failed to start $DRIVER_DISPLAY_NAME process (modern mode)"
|
|
1186
1241
|
# Fall back to legacy mode
|
|
1187
1242
|
log_status "INFO" "Falling back to legacy mode..."
|
|
1188
1243
|
use_modern_cli=false
|
|
@@ -1197,7 +1252,7 @@ execute_claude_code() {
|
|
|
1197
1252
|
then
|
|
1198
1253
|
: # Continue to wait loop
|
|
1199
1254
|
else
|
|
1200
|
-
log_status "ERROR" "โ Failed to start
|
|
1255
|
+
log_status "ERROR" "โ Failed to start $DRIVER_DISPLAY_NAME process"
|
|
1201
1256
|
return 1
|
|
1202
1257
|
fi
|
|
1203
1258
|
fi
|
|
@@ -1238,9 +1293,9 @@ EOF
|
|
|
1238
1293
|
# Only log if verbose mode is enabled
|
|
1239
1294
|
if [[ "$VERBOSE_PROGRESS" == "true" ]]; then
|
|
1240
1295
|
if [[ -n "$last_line" ]]; then
|
|
1241
|
-
log_status "INFO" "$progress_indicator
|
|
1296
|
+
log_status "INFO" "$progress_indicator $DRIVER_DISPLAY_NAME: $last_line... (${progress_counter}0s)"
|
|
1242
1297
|
else
|
|
1243
|
-
log_status "INFO" "$progress_indicator
|
|
1298
|
+
log_status "INFO" "$progress_indicator $DRIVER_DISPLAY_NAME working... (${progress_counter}0s elapsed)"
|
|
1244
1299
|
fi
|
|
1245
1300
|
fi
|
|
1246
1301
|
|
|
@@ -1259,15 +1314,15 @@ EOF
|
|
|
1259
1314
|
# Clear progress file
|
|
1260
1315
|
echo '{"status": "completed", "timestamp": "'$(date '+%Y-%m-%d %H:%M:%S')'"}' > "$PROGRESS_FILE"
|
|
1261
1316
|
|
|
1262
|
-
log_status "SUCCESS" "โ
|
|
1317
|
+
log_status "SUCCESS" "โ
$DRIVER_DISPLAY_NAME execution completed successfully"
|
|
1263
1318
|
|
|
1264
1319
|
# Save session ID from JSON output (Phase 1.1)
|
|
1265
|
-
if [[ "$CLAUDE_USE_CONTINUE" == "true" ]]; then
|
|
1320
|
+
if [[ "$CLAUDE_USE_CONTINUE" == "true" ]] && supports_driver_sessions; then
|
|
1266
1321
|
save_claude_session "$output_file"
|
|
1267
1322
|
fi
|
|
1268
1323
|
|
|
1269
1324
|
# Analyze the response
|
|
1270
|
-
log_status "INFO" "๐ Analyzing
|
|
1325
|
+
log_status "INFO" "๐ Analyzing $DRIVER_DISPLAY_NAME response..."
|
|
1271
1326
|
analyze_response "$output_file" "$loop_count"
|
|
1272
1327
|
local analysis_exit_code=$?
|
|
1273
1328
|
|
|
@@ -1356,7 +1411,7 @@ EOF
|
|
|
1356
1411
|
log_status "ERROR" "๐ซ Claude API 5-hour usage limit reached"
|
|
1357
1412
|
return 2 # Special return code for API limit
|
|
1358
1413
|
else
|
|
1359
|
-
log_status "ERROR" "โ
|
|
1414
|
+
log_status "ERROR" "โ $DRIVER_DISPLAY_NAME execution failed, check: $output_file"
|
|
1360
1415
|
return 1
|
|
1361
1416
|
fi
|
|
1362
1417
|
fi
|
|
@@ -1378,22 +1433,14 @@ loop_count=0
|
|
|
1378
1433
|
|
|
1379
1434
|
# Main loop
|
|
1380
1435
|
main() {
|
|
1381
|
-
|
|
1382
|
-
if load_ralphrc; then
|
|
1383
|
-
if [[ "$RALPHRC_LOADED" == "true" ]]; then
|
|
1384
|
-
log_status "INFO" "Loaded configuration from .ralphrc"
|
|
1385
|
-
fi
|
|
1386
|
-
fi
|
|
1387
|
-
|
|
1388
|
-
# Load platform driver (after .ralphrc so PLATFORM_DRIVER can be overridden)
|
|
1389
|
-
load_platform_driver
|
|
1436
|
+
initialize_runtime_context
|
|
1390
1437
|
|
|
1391
1438
|
# Validate --allowed-tools now that platform-specific VALID_TOOL_PATTERNS are loaded
|
|
1392
1439
|
if [[ "${_CLI_ALLOWED_TOOLS:-}" == "true" ]] && ! validate_allowed_tools "$CLAUDE_ALLOWED_TOOLS"; then
|
|
1393
1440
|
exit 1
|
|
1394
1441
|
fi
|
|
1395
1442
|
|
|
1396
|
-
log_status "SUCCESS" "๐ Ralph loop starting with
|
|
1443
|
+
log_status "SUCCESS" "๐ Ralph loop starting with $DRIVER_DISPLAY_NAME"
|
|
1397
1444
|
log_status "INFO" "Max calls per hour: $MAX_CALLS_PER_HOUR"
|
|
1398
1445
|
log_status "INFO" "Logs: $LOG_DIR/ | Docs: $DOCS_DIR/ | Status: $STATUS_FILE"
|
|
1399
1446
|
|
|
@@ -1417,19 +1464,19 @@ main() {
|
|
|
1417
1464
|
echo ""
|
|
1418
1465
|
|
|
1419
1466
|
# Check if this looks like a partial Ralph project
|
|
1420
|
-
if [[ -f "$RALPH_DIR/@fix_plan.md" ]] || [[ -d "$RALPH_DIR/specs" ]] || [[ -f "$RALPH_DIR
|
|
1421
|
-
echo "This appears to be a Ralph project but is missing .ralph/PROMPT.md."
|
|
1467
|
+
if [[ -f "$RALPH_DIR/@fix_plan.md" ]] || [[ -d "$RALPH_DIR/specs" ]] || [[ -f "$RALPH_DIR/@AGENT.md" ]]; then
|
|
1468
|
+
echo "This appears to be a bmalph/Ralph project but is missing .ralph/PROMPT.md."
|
|
1422
1469
|
echo "You may need to create or restore the PROMPT.md file."
|
|
1423
1470
|
else
|
|
1424
|
-
echo "This directory is not a Ralph project."
|
|
1471
|
+
echo "This directory is not a bmalph/Ralph project."
|
|
1425
1472
|
fi
|
|
1426
1473
|
|
|
1427
1474
|
echo ""
|
|
1428
1475
|
echo "To fix this:"
|
|
1429
|
-
echo " 1.
|
|
1430
|
-
echo " 2.
|
|
1431
|
-
echo " 3.
|
|
1432
|
-
echo " 4. Navigate to an existing Ralph project directory"
|
|
1476
|
+
echo " 1. Initialize bmalph in this project: bmalph init"
|
|
1477
|
+
echo " 2. Restore bundled Ralph files in an existing project: bmalph upgrade"
|
|
1478
|
+
echo " 3. Generate Ralph task files after planning: bmalph implement"
|
|
1479
|
+
echo " 4. Navigate to an existing bmalph/Ralph project directory"
|
|
1433
1480
|
echo " 5. Or create .ralph/PROMPT.md manually in this directory"
|
|
1434
1481
|
echo ""
|
|
1435
1482
|
echo "Ralph projects should contain: .ralph/PROMPT.md, .ralph/@fix_plan.md, .ralph/specs/, src/, etc."
|
|
@@ -1496,7 +1543,7 @@ main() {
|
|
|
1496
1543
|
echo -e "${RED}โ PERMISSION DENIED - Loop Halted โ${NC}"
|
|
1497
1544
|
echo -e "${RED}โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ${NC}"
|
|
1498
1545
|
echo ""
|
|
1499
|
-
echo -e "${YELLOW}
|
|
1546
|
+
echo -e "${YELLOW}$DRIVER_DISPLAY_NAME was denied permission to execute commands.${NC}"
|
|
1500
1547
|
echo ""
|
|
1501
1548
|
echo -e "${YELLOW}To fix this:${NC}"
|
|
1502
1549
|
echo " 1. Edit .ralphrc and update ALLOWED_TOOLS to include the required tools"
|
|
@@ -1507,8 +1554,8 @@ main() {
|
|
|
1507
1554
|
echo " - Bash(yarn *) - All yarn commands"
|
|
1508
1555
|
echo ""
|
|
1509
1556
|
echo -e "${YELLOW}After updating .ralphrc:${NC}"
|
|
1510
|
-
echo " ralph --reset-session # Clear stale session state"
|
|
1511
|
-
echo "
|
|
1557
|
+
echo " bash .ralph/ralph_loop.sh --reset-session # Clear stale session state"
|
|
1558
|
+
echo " bmalph run # Restart the loop"
|
|
1512
1559
|
echo ""
|
|
1513
1560
|
|
|
1514
1561
|
# Show current ALLOWED_TOOLS if .ralphrc exists
|
|
@@ -1553,7 +1600,7 @@ main() {
|
|
|
1553
1600
|
reset_session "circuit_breaker_trip"
|
|
1554
1601
|
update_status "$loop_count" "$(cat "$CALL_COUNT_FILE")" "circuit_breaker_open" "halted" "stagnation_detected"
|
|
1555
1602
|
log_status "ERROR" "๐ Circuit breaker has opened - halting loop"
|
|
1556
|
-
log_status "INFO" "Run 'ralph --reset-circuit' to reset the circuit breaker after addressing issues"
|
|
1603
|
+
log_status "INFO" "Run 'bash .ralph/ralph_loop.sh --reset-circuit' to reset the circuit breaker after addressing issues"
|
|
1557
1604
|
break
|
|
1558
1605
|
elif [ $exec_result -eq 2 ]; then
|
|
1559
1606
|
# API 5-hour limit reached - handle specially
|
|
@@ -1605,12 +1652,12 @@ main() {
|
|
|
1605
1652
|
# Help function
|
|
1606
1653
|
show_help() {
|
|
1607
1654
|
cat << HELPEOF
|
|
1608
|
-
Ralph Loop
|
|
1655
|
+
Ralph Loop
|
|
1609
1656
|
|
|
1610
1657
|
Usage: $0 [OPTIONS]
|
|
1611
1658
|
|
|
1612
|
-
IMPORTANT: This command must be run from a Ralph project directory.
|
|
1613
|
-
Use '
|
|
1659
|
+
IMPORTANT: This command must be run from a bmalph/Ralph project directory.
|
|
1660
|
+
Use 'bmalph init' in your project first.
|
|
1614
1661
|
|
|
1615
1662
|
Options:
|
|
1616
1663
|
-h, --help Show this help message
|
|
@@ -1619,15 +1666,15 @@ Options:
|
|
|
1619
1666
|
-s, --status Show current status and exit
|
|
1620
1667
|
-m, --monitor Start with tmux session and live monitor (requires tmux)
|
|
1621
1668
|
-v, --verbose Show detailed progress updates during execution
|
|
1622
|
-
-l, --live Show
|
|
1623
|
-
-t, --timeout MIN Set
|
|
1669
|
+
-l, --live Show live driver output in real-time (auto-switches to JSON output)
|
|
1670
|
+
-t, --timeout MIN Set driver execution timeout in minutes (default: $CLAUDE_TIMEOUT_MINUTES)
|
|
1624
1671
|
--reset-circuit Reset circuit breaker to CLOSED state
|
|
1625
1672
|
--circuit-status Show circuit breaker status and exit
|
|
1626
1673
|
--auto-reset-circuit Auto-reset circuit breaker on startup (bypasses cooldown)
|
|
1627
1674
|
--reset-session Reset session state and exit (clears session continuity)
|
|
1628
1675
|
|
|
1629
1676
|
Modern CLI Options (Phase 1.1):
|
|
1630
|
-
--output-format FORMAT Set
|
|
1677
|
+
--output-format FORMAT Set driver output format: json or text (default: $CLAUDE_OUTPUT_FORMAT)
|
|
1631
1678
|
Note: --live mode requires JSON and will auto-switch
|
|
1632
1679
|
--allowed-tools TOOLS Comma-separated list of allowed tools (default: $CLAUDE_ALLOWED_TOOLS)
|
|
1633
1680
|
--no-continue Disable session continuity across loops
|
|
@@ -1643,15 +1690,17 @@ Files created:
|
|
|
1643
1690
|
- .ralph/.last_reset: Timestamp of last rate limit reset
|
|
1644
1691
|
|
|
1645
1692
|
Example workflow:
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1693
|
+
cd my-project # Enter project directory
|
|
1694
|
+
bmalph init # Install bmalph + Ralph files
|
|
1695
|
+
bmalph implement # Generate Ralph task files
|
|
1696
|
+
$0 --monitor # Start Ralph with monitoring
|
|
1649
1697
|
|
|
1650
1698
|
Examples:
|
|
1699
|
+
bmalph run # Start Ralph via the bmalph CLI
|
|
1651
1700
|
$0 --calls 50 --prompt my_prompt.md
|
|
1652
|
-
$0 --monitor
|
|
1653
|
-
$0 --live
|
|
1654
|
-
$0 --live --verbose
|
|
1701
|
+
$0 --monitor # Start with integrated tmux monitoring
|
|
1702
|
+
$0 --live # Show live driver output in real-time (streaming)
|
|
1703
|
+
$0 --live --verbose # Live streaming + verbose logging
|
|
1655
1704
|
$0 --monitor --timeout 30 # 30-minute timeout for complex tasks
|
|
1656
1705
|
$0 --verbose --timeout 5 # 5-minute timeout with detailed progress
|
|
1657
1706
|
$0 --output-format text # Use legacy text output format
|