spec-and-loop 3.0.3 → 3.3.0
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/OPENSPEC-RALPH-BP.md +99 -503
- package/lib/mini-ralph/history.js +4 -0
- package/lib/mini-ralph/index.js +1 -0
- package/lib/mini-ralph/prompt.js +0 -5
- package/lib/mini-ralph/runner.js +455 -20
- package/lib/mini-ralph/tasks.js +0 -34
- package/package.json +1 -1
- package/scripts/mini-ralph-cli.js +12 -0
- package/scripts/ralph-run.sh +147 -180
package/package.json
CHANGED
|
@@ -22,6 +22,11 @@
|
|
|
22
22
|
* --stall-threshold <n> Halt after N consecutive no-op iterations (default: 3; 0 disables)
|
|
23
23
|
* --completion-promise <s> Completion promise string (default: COMPLETE)
|
|
24
24
|
* --task-promise <s> Task promise string (default: READY_FOR_NEXT_TASK)
|
|
25
|
+
* --blocked-handoff-promise <s>
|
|
26
|
+
* Blocked-handoff promise string (default: BLOCKED_HANDOFF).
|
|
27
|
+
* Loop exits cleanly with `blocked_handoff` when the
|
|
28
|
+
* agent emits this tag and writes the agent's note
|
|
29
|
+
* to <ralph-dir>/HANDOFF.md.
|
|
25
30
|
* --no-commit Suppress auto-commit
|
|
26
31
|
* --model <name> Optional model override
|
|
27
32
|
* --verbose Verbose output
|
|
@@ -53,6 +58,7 @@ function parseArgs(argv) {
|
|
|
53
58
|
stallThreshold: 3,
|
|
54
59
|
completionPromise: 'COMPLETE',
|
|
55
60
|
taskPromise: 'READY_FOR_NEXT_TASK',
|
|
61
|
+
blockedHandoffPromise: 'BLOCKED_HANDOFF',
|
|
56
62
|
noCommit: false,
|
|
57
63
|
model: '',
|
|
58
64
|
verbose: false,
|
|
@@ -101,6 +107,9 @@ function parseArgs(argv) {
|
|
|
101
107
|
case '--task-promise':
|
|
102
108
|
opts.taskPromise = args[++i];
|
|
103
109
|
break;
|
|
110
|
+
case '--blocked-handoff-promise':
|
|
111
|
+
opts.blockedHandoffPromise = args[++i];
|
|
112
|
+
break;
|
|
104
113
|
case '--no-commit':
|
|
105
114
|
opts.noCommit = true;
|
|
106
115
|
break;
|
|
@@ -154,6 +163,8 @@ Options:
|
|
|
154
163
|
--stall-threshold <n> Halt after N consecutive no-op iterations (default: 3; 0 disables)
|
|
155
164
|
--completion-promise <s> Completion promise string
|
|
156
165
|
--task-promise <s> Task promise string
|
|
166
|
+
--blocked-handoff-promise <s>
|
|
167
|
+
Blocked-handoff promise string (default: BLOCKED_HANDOFF)
|
|
157
168
|
--no-commit Suppress auto-commit
|
|
158
169
|
--model <name> Model override
|
|
159
170
|
--verbose Verbose output
|
|
@@ -212,6 +223,7 @@ async function main() {
|
|
|
212
223
|
stallThreshold: opts.stallThreshold,
|
|
213
224
|
completionPromise: opts.completionPromise,
|
|
214
225
|
taskPromise: opts.taskPromise,
|
|
226
|
+
blockedHandoffPromise: opts.blockedHandoffPromise,
|
|
215
227
|
noCommit: opts.noCommit,
|
|
216
228
|
model: opts.model,
|
|
217
229
|
verbose: opts.verbose,
|
package/scripts/ralph-run.sh
CHANGED
|
@@ -333,69 +333,58 @@ validate_dependencies() {
|
|
|
333
333
|
log_verbose "All dependencies validated"
|
|
334
334
|
}
|
|
335
335
|
|
|
336
|
+
should_auto_fix_artifacts() {
|
|
337
|
+
case "${RALPH_RUN_AUTO_FIX_ARTIFACTS:-}" in
|
|
338
|
+
1|true|TRUE|yes|YES)
|
|
339
|
+
return 0
|
|
340
|
+
;;
|
|
341
|
+
0|false|FALSE|no|NO)
|
|
342
|
+
return 1
|
|
343
|
+
;;
|
|
344
|
+
esac
|
|
345
|
+
|
|
346
|
+
[[ -t 0 ]]
|
|
347
|
+
}
|
|
348
|
+
|
|
336
349
|
ensure_artifacts_present() {
|
|
337
350
|
local change_dir="$1"
|
|
338
351
|
local change_name="$2"
|
|
339
352
|
|
|
340
|
-
local
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
"
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
local missing=()
|
|
347
|
-
for file in "${required_files[@]}"; do
|
|
348
|
-
if [[ ! -f "$change_dir/$file" ]]; then
|
|
349
|
-
missing+=("$file")
|
|
350
|
-
fi
|
|
351
|
-
done
|
|
353
|
+
local status_json
|
|
354
|
+
status_json=$(openspec status --change "$change_name" --json 2>/dev/null)
|
|
355
|
+
if [[ $? -ne 0 ]]; then
|
|
356
|
+
log_error "Failed to query openspec status for change: $change_name"
|
|
357
|
+
exit 1
|
|
358
|
+
fi
|
|
352
359
|
|
|
353
|
-
|
|
360
|
+
local blocked
|
|
361
|
+
blocked=$(echo "$status_json" | jq -r '.artifacts[] | select(.status == "blocked") | .id' 2>/dev/null)
|
|
362
|
+
if [[ -z "$blocked" ]]; then
|
|
354
363
|
return 0
|
|
355
364
|
fi
|
|
356
365
|
|
|
357
|
-
log_info "
|
|
366
|
+
log_info "Blocked artifacts detected: $blocked"
|
|
367
|
+
if ! should_auto_fix_artifacts; then
|
|
368
|
+
log_error "OpenSpec artifacts are blocked and this is a non-interactive run."
|
|
369
|
+
log_error 'Run `ralph-run init` or complete the artifacts manually, then rerun.'
|
|
370
|
+
log_error "Set RALPH_RUN_AUTO_FIX_ARTIFACTS=true to opt into opencode artifact repair in automation."
|
|
371
|
+
exit 1
|
|
372
|
+
fi
|
|
373
|
+
|
|
358
374
|
log_info "Invoking opencode to complete missing artifacts..."
|
|
359
375
|
|
|
360
376
|
opencode run "/opsx-ff $change_name" || true
|
|
361
377
|
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
378
|
+
status_json=$(openspec status --change "$change_name" --json 2>/dev/null)
|
|
379
|
+
blocked=$(echo "$status_json" | jq -r '.artifacts[] | select(.status == "blocked") | .id' 2>/dev/null)
|
|
380
|
+
if [[ -n "$blocked" ]]; then
|
|
381
|
+
log_error "Artifacts still blocked after /opsx-ff: $blocked"
|
|
382
|
+
exit 1
|
|
383
|
+
fi
|
|
368
384
|
|
|
369
385
|
log_info "All missing artifacts generated"
|
|
370
386
|
}
|
|
371
387
|
|
|
372
|
-
validate_openspec_artifacts() {
|
|
373
|
-
local change_dir="$1"
|
|
374
|
-
|
|
375
|
-
log_verbose "Validating OpenSpec artifacts..."
|
|
376
|
-
|
|
377
|
-
local required_files=(
|
|
378
|
-
"proposal.md"
|
|
379
|
-
"tasks.md"
|
|
380
|
-
"design.md"
|
|
381
|
-
)
|
|
382
|
-
|
|
383
|
-
for file in "${required_files[@]}"; do
|
|
384
|
-
if [[ ! -f "$change_dir/$file" ]]; then
|
|
385
|
-
log_error "Required artifact not found: $file"
|
|
386
|
-
exit 1
|
|
387
|
-
fi
|
|
388
|
-
log_verbose "Found artifact: $file"
|
|
389
|
-
done
|
|
390
|
-
|
|
391
|
-
if [[ ! -d "$change_dir/specs" ]]; then
|
|
392
|
-
log_error "Required directory not found: specs/"
|
|
393
|
-
exit 1
|
|
394
|
-
fi
|
|
395
|
-
log_verbose "Found directory: specs/"
|
|
396
|
-
|
|
397
|
-
log_info "All OpenSpec artifacts validated"
|
|
398
|
-
}
|
|
399
388
|
|
|
400
389
|
setup_ralph_directory() {
|
|
401
390
|
local change_dir="$1"
|
|
@@ -682,15 +671,21 @@ validate_script_state() {
|
|
|
682
671
|
|
|
683
672
|
log_verbose "Validating script state..."
|
|
684
673
|
|
|
685
|
-
|
|
686
|
-
".ralph"
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
674
|
+
if [[ ! -d "$change_dir/.ralph" ]]; then
|
|
675
|
+
log_verbose "Required directory not found: .ralph (will be created)"
|
|
676
|
+
fi
|
|
677
|
+
|
|
678
|
+
if [[ ! -d "$change_dir/specs" ]]; then
|
|
679
|
+
log_error "Required directory not found: specs"
|
|
680
|
+
return 1
|
|
681
|
+
fi
|
|
682
|
+
|
|
683
|
+
local first_spec=""
|
|
684
|
+
first_spec=$(find "$change_dir/specs" -name "spec.md" -type f -print -quit 2>/dev/null || true)
|
|
685
|
+
if [[ -z "$first_spec" ]]; then
|
|
686
|
+
log_error "No spec.md files found under specs"
|
|
687
|
+
return 1
|
|
688
|
+
fi
|
|
694
689
|
|
|
695
690
|
local required_files=(
|
|
696
691
|
"tasks.md"
|
|
@@ -810,111 +805,7 @@ sync_tasks_to_ralph() {
|
|
|
810
805
|
log_verbose "Symlink configured: $ralph_tasks_file -> $abs_tasks_file"
|
|
811
806
|
}
|
|
812
807
|
|
|
813
|
-
create_prompt_template() {
|
|
814
|
-
local change_dir="$1"
|
|
815
|
-
local template_file="$2"
|
|
816
|
-
|
|
817
|
-
log_verbose "Creating custom prompt template..."
|
|
818
|
-
|
|
819
|
-
local abs_change_dir
|
|
820
|
-
abs_change_dir=$(get_realpath "$change_dir")
|
|
821
|
-
|
|
822
|
-
cat > "$template_file" << 'EOF'
|
|
823
|
-
# Ralph Wiggum Task Execution - Iteration {{iteration}} / {{max_iterations}}
|
|
824
|
-
|
|
825
|
-
Change directory: {{change_dir}}
|
|
826
|
-
|
|
827
|
-
## OpenSpec Artifacts
|
|
828
|
-
|
|
829
|
-
{{_openspec_manifest}}
|
|
830
|
-
|
|
831
|
-
## Fresh Task Context
|
|
832
|
-
|
|
833
|
-
{{task_context}}
|
|
834
|
-
|
|
835
|
-
## Instructions
|
|
836
|
-
|
|
837
|
-
Before implementing, read the OpenSpec artifacts listed above that are relevant to the current task.
|
|
838
|
-
|
|
839
|
-
Follow this loop contract EXACTLY. Do not skip steps. Do not batch. Do not output a promise until every step is done.
|
|
840
|
-
|
|
841
|
-
1. Work on the task shown in `## Fresh Task Context` above. Before editing any marker, open `tasks.md` at `{{change_dir}}/tasks.md` and verify that same task is still `- [ ] ` or `- [/] ` on disk (it may have been closed by a prior iteration if you are resuming).
|
|
842
|
-
2. Edit `tasks.md` in place to change that line's marker to `- [/] ` (in-progress). You MUST use your file edit tool to modify the file on disk — a shell `cp`, `sed`, or print-to-stdout does not count. Verify by re-reading the file.
|
|
843
|
-
3. Implement the smallest change that fully satisfies the task's Done-when conditions. Run the task's verification command if one is specified.
|
|
844
|
-
4. On success, edit `tasks.md` again in place to change that line's marker from `- [/] ` to `- [x] `. Verify by re-reading the file and confirming the `[x]` is present on that exact line.
|
|
845
|
-
5. ONLY after step 4 writes `[x]` to disk, output `<promise>{{task_promise}}</promise>` on its own line.
|
|
846
|
-
6. If and only if EVERY task line in `tasks.md` is `- [x] `, output `<promise>{{completion_promise}}</promise>` instead.
|
|
847
808
|
|
|
848
|
-
Hard rules:
|
|
849
|
-
- If you do not actually modify `tasks.md` on disk in this iteration, DO NOT output any promise tag. Output a short failure note instead and stop.
|
|
850
|
-
- Never output `<promise>{{task_promise}}</promise>` while the task you just worked on is still `- [ ]` on disk. That causes the same task to repeat forever.
|
|
851
|
-
- Promise tags must be on their own line, literal, unquoted, and not described in prose.
|
|
852
|
-
- If an approach fails twice, try a different one.
|
|
853
|
-
- If the task is already satisfied by prior work (e.g. target file already exists with the right content), you STILL must flip the checkbox to `[x]` in `tasks.md` before emitting the promise.
|
|
854
|
-
|
|
855
|
-
## Commit Contract
|
|
856
|
-
|
|
857
|
-
{{commit_contract}}
|
|
858
|
-
EOF
|
|
859
|
-
|
|
860
|
-
# Determine repo root for AGENTS.md probe
|
|
861
|
-
local repo_root
|
|
862
|
-
repo_root=$(git rev-parse --show-toplevel 2>/dev/null) || repo_root=""
|
|
863
|
-
|
|
864
|
-
# Build the manifest body
|
|
865
|
-
local manifest_body
|
|
866
|
-
manifest_body="Read these as needed (source of truth for this change):"$'\n'$'\n'
|
|
867
|
-
manifest_body+="- $abs_change_dir/proposal.md"$'\n'
|
|
868
|
-
manifest_body+="- $abs_change_dir/design.md"$'\n'
|
|
869
|
-
|
|
870
|
-
# Pre-expand specs/*/spec.md into concrete paths
|
|
871
|
-
if [[ -d "$abs_change_dir/specs" ]]; then
|
|
872
|
-
while IFS= read -r spec_path; do
|
|
873
|
-
[[ -n "$spec_path" ]] && manifest_body+="- $spec_path"$'\n'
|
|
874
|
-
done < <(find "$abs_change_dir/specs" -name spec.md -type f 2>/dev/null | sort)
|
|
875
|
-
fi
|
|
876
|
-
|
|
877
|
-
# Optionally append AGENTS.md reference
|
|
878
|
-
local agents_line
|
|
879
|
-
agents_line=$(probe_agents_md "$repo_root")
|
|
880
|
-
if [[ -n "$agents_line" ]]; then
|
|
881
|
-
manifest_body+=$'\n'"$agents_line"
|
|
882
|
-
fi
|
|
883
|
-
|
|
884
|
-
# Append Ralph best practices guide if project is ralphified
|
|
885
|
-
if check_ralphified; then
|
|
886
|
-
local bp_manifest_path="$abs_change_dir/../../OPENSPEC-RALPH-BP.md"
|
|
887
|
-
if [[ ! -f "$bp_manifest_path" ]]; then
|
|
888
|
-
bp_manifest_path="$repo_root/openspec/OPENSPEC-RALPH-BP.md"
|
|
889
|
-
fi
|
|
890
|
-
if [[ -f "$bp_manifest_path" ]]; then
|
|
891
|
-
manifest_body+=$'\n'"- $bp_manifest_path (Ralph best practices guide)"
|
|
892
|
-
fi
|
|
893
|
-
fi
|
|
894
|
-
|
|
895
|
-
# Substitute {{_openspec_manifest}} using awk with a manifest temp file
|
|
896
|
-
# (awk -v cannot handle multi-line values; use getline from a file instead)
|
|
897
|
-
local _manifest_file
|
|
898
|
-
_manifest_file=$(mktemp 2>/dev/null || mktemp -t ralph-manifest)
|
|
899
|
-
printf '%s' "$manifest_body" > "$_manifest_file"
|
|
900
|
-
local _tmpfile
|
|
901
|
-
_tmpfile=$(mktemp 2>/dev/null || mktemp -t ralph-template)
|
|
902
|
-
awk -v mf="$_manifest_file" '
|
|
903
|
-
{
|
|
904
|
-
if ($0 == "{{_openspec_manifest}}") {
|
|
905
|
-
while ((getline line < mf) > 0) { print line }
|
|
906
|
-
close(mf)
|
|
907
|
-
} else { print }
|
|
908
|
-
}
|
|
909
|
-
' "$template_file" > "$_tmpfile" && mv "$_tmpfile" "$template_file"
|
|
910
|
-
rm -f "$_manifest_file"
|
|
911
|
-
|
|
912
|
-
# Substitute {{change_dir}}
|
|
913
|
-
_tmpfile=$(mktemp 2>/dev/null || mktemp -t ralph-template)
|
|
914
|
-
sed "s|{{change_dir}}|$abs_change_dir|g" "$template_file" > "$_tmpfile" && mv "$_tmpfile" "$template_file"
|
|
915
|
-
|
|
916
|
-
log_verbose "Prompt template created: $template_file"
|
|
917
|
-
}
|
|
918
809
|
|
|
919
810
|
probe_agents_md() {
|
|
920
811
|
local repo_root="$1"
|
|
@@ -1064,14 +955,11 @@ execute_ralph_loop() {
|
|
|
1064
955
|
return 1
|
|
1065
956
|
fi
|
|
1066
957
|
|
|
1067
|
-
local template_file="$ralph_dir/prompt-template.md"
|
|
1068
|
-
|
|
1069
958
|
# Clean up old output directories and setup new one
|
|
1070
959
|
cleanup_old_output
|
|
1071
960
|
local output_dir=$(setup_output_capture "$ralph_dir")
|
|
1072
961
|
|
|
1073
962
|
sync_tasks_to_ralph "$change_dir" "$ralph_dir"
|
|
1074
|
-
create_prompt_template "$change_dir" "$template_file"
|
|
1075
963
|
|
|
1076
964
|
# Output files
|
|
1077
965
|
local stdout_log="$output_dir/ralph-stdout.log"
|
|
@@ -1080,13 +968,38 @@ execute_ralph_loop() {
|
|
|
1080
968
|
log_info "Invoking internal mini Ralph runtime..."
|
|
1081
969
|
log_info "Capturing output to: $output_dir"
|
|
1082
970
|
|
|
971
|
+
local ralph_prompt_text="/opsx-apply $CHANGE_NAME
|
|
972
|
+
|
|
973
|
+
You are operating inside an automated loop. Follow these constraints EXACTLY:
|
|
974
|
+
|
|
975
|
+
1. Implement exactly ONE pending task from the task list /opsx-apply shows you.
|
|
976
|
+
2. After marking the task checkbox [x] on disk, output <promise>READY_FOR_NEXT_TASK</promise> on its own line.
|
|
977
|
+
3. If and only if EVERY task checkbox is [x], output <promise>COMPLETE</promise> instead.
|
|
978
|
+
4. Do not ask questions or wait for input. If you cannot make progress on the current task because an external decision is required (revert protected drift outside the change scope, file an out-of-scope refactor, escalate to a human reviewer, etc.), STOP and emit a structured handoff in this exact form:
|
|
979
|
+
|
|
980
|
+
## Blocker Note
|
|
981
|
+
<one paragraph describing what is blocked>
|
|
982
|
+
|
|
983
|
+
## Why
|
|
984
|
+
<one paragraph: which task spec clause / invariant fired, and what evidence (file paths, hashes, test names) supports the diagnosis>
|
|
985
|
+
|
|
986
|
+
## Suggested Next Step
|
|
987
|
+
<one or two bullets the human can execute to unblock>
|
|
988
|
+
|
|
989
|
+
<promise>BLOCKED_HANDOFF</promise>
|
|
990
|
+
|
|
991
|
+
The runner will save this note to .ralph/HANDOFF.md and exit cleanly with reason=blocked_handoff. Do NOT keep retrying the same task; emit the handoff and stop. Do NOT emit BLOCKED_HANDOFF for transient errors that a retry could fix (network blips, tool-not-found that is fixable by an absolute path, etc.) — those are normal failures the loop will retry on its own.
|
|
992
|
+
5. If the task is already satisfied by prior work, still flip the checkbox to [x] before emitting the promise.
|
|
993
|
+
|
|
994
|
+
Do not create git commits yourself. The Ralph runner manages automatic task commits when auto-commit is enabled."
|
|
995
|
+
|
|
1083
996
|
# Build the mini-ralph-cli arguments
|
|
1084
997
|
local mini_ralph_args=(
|
|
1085
|
-
"--prompt-template" "$template_file"
|
|
1086
998
|
"--ralph-dir" "$ralph_dir"
|
|
1087
999
|
"--tasks-file" "$change_dir/tasks.md"
|
|
1088
1000
|
"--tasks"
|
|
1089
1001
|
"--max-iterations" "$max_iterations"
|
|
1002
|
+
"--prompt-text" "$ralph_prompt_text"
|
|
1090
1003
|
)
|
|
1091
1004
|
|
|
1092
1005
|
if [[ "$no_commit" == true ]]; then
|
|
@@ -1101,12 +1014,53 @@ execute_ralph_loop() {
|
|
|
1101
1014
|
mini_ralph_args+=("--quiet")
|
|
1102
1015
|
fi
|
|
1103
1016
|
|
|
1104
|
-
# Run the internal mini Ralph CLI and capture output
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
wait
|
|
1017
|
+
# Run the internal mini Ralph CLI and capture output.
|
|
1018
|
+
#
|
|
1019
|
+
# Avoid Bash process substitution here. macOS ships Bash 3.2, and under
|
|
1020
|
+
# Bats' captured `run` wrapper a bare `wait` after `> >(tee ...)` can hang
|
|
1021
|
+
# after the node child has already exited. Explicit FIFOs give us concrete
|
|
1022
|
+
# tee PIDs to wait on and work consistently on macOS and Linux.
|
|
1023
|
+
local stdout_pipe="$output_dir/ralph-stdout.pipe"
|
|
1024
|
+
local stderr_pipe="$output_dir/ralph-stderr.pipe"
|
|
1025
|
+
local node_exit_code=0
|
|
1026
|
+
local tee_stdout_pid=""
|
|
1027
|
+
local tee_stderr_pid=""
|
|
1028
|
+
local had_errexit=false
|
|
1029
|
+
case $- in
|
|
1030
|
+
*e*)
|
|
1031
|
+
had_errexit=true
|
|
1032
|
+
set +e
|
|
1033
|
+
;;
|
|
1034
|
+
esac
|
|
1035
|
+
|
|
1036
|
+
if mkfifo "$stdout_pipe" "$stderr_pipe" 2>/dev/null; then
|
|
1037
|
+
tee "$stdout_log" < "$stdout_pipe" &
|
|
1038
|
+
tee_stdout_pid=$!
|
|
1039
|
+
tee "$stderr_log" < "$stderr_pipe" >&2 &
|
|
1040
|
+
tee_stderr_pid=$!
|
|
1041
|
+
|
|
1042
|
+
node "$MINI_RALPH_CLI" "${mini_ralph_args[@]}" > "$stdout_pipe" 2> "$stderr_pipe"
|
|
1043
|
+
node_exit_code=$?
|
|
1044
|
+
|
|
1045
|
+
wait "$tee_stdout_pid" 2>/dev/null || true
|
|
1046
|
+
wait "$tee_stderr_pid" 2>/dev/null || true
|
|
1047
|
+
rm -f "$stdout_pipe" "$stderr_pipe"
|
|
1048
|
+
else
|
|
1049
|
+
log_verbose "mkfifo unavailable; capturing output without live tee"
|
|
1050
|
+
node "$MINI_RALPH_CLI" "${mini_ralph_args[@]}" > "$stdout_log" 2> "$stderr_log"
|
|
1051
|
+
node_exit_code=$?
|
|
1052
|
+
if [[ -s "$stdout_log" ]]; then
|
|
1053
|
+
cat "$stdout_log"
|
|
1054
|
+
fi
|
|
1055
|
+
if [[ -s "$stderr_log" ]]; then
|
|
1056
|
+
cat "$stderr_log" >&2
|
|
1057
|
+
fi
|
|
1058
|
+
fi
|
|
1059
|
+
|
|
1060
|
+
if [[ "$had_errexit" == true ]]; then
|
|
1061
|
+
set -e
|
|
1062
|
+
fi
|
|
1063
|
+
|
|
1110
1064
|
return $node_exit_code
|
|
1111
1065
|
}
|
|
1112
1066
|
|
|
@@ -1285,6 +1239,7 @@ check_ralphified() {
|
|
|
1285
1239
|
|
|
1286
1240
|
show_ralphify_warning() {
|
|
1287
1241
|
local change_name="$1"
|
|
1242
|
+
local preset_choice="${RALPH_RUN_RALPHIFY_CHOICE:-}"
|
|
1288
1243
|
|
|
1289
1244
|
cat >&2 << 'WARNING_BOX'
|
|
1290
1245
|
┌─────────────────────────────────────────────────────────────────────┐
|
|
@@ -1299,16 +1254,29 @@ show_ralphify_warning() {
|
|
|
1299
1254
|
└─────────────────────────────────────────────────────────────────────┘
|
|
1300
1255
|
WARNING_BOX
|
|
1301
1256
|
|
|
1257
|
+
if [[ -z "$preset_choice" && ! -t 0 ]]; then
|
|
1258
|
+
log_info "Non-interactive environment detected. Continuing without Ralph Wiggum configuration."
|
|
1259
|
+
log_info 'Run `ralph-run init` to configure Ralph Wiggum best practices before the next interactive run.'
|
|
1260
|
+
return 0
|
|
1261
|
+
fi
|
|
1262
|
+
|
|
1302
1263
|
while true; do
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1264
|
+
local choice=""
|
|
1265
|
+
if [[ -n "$preset_choice" ]]; then
|
|
1266
|
+
choice="$preset_choice"
|
|
1267
|
+
preset_choice=""
|
|
1268
|
+
log_info "Using RALPH_RUN_RALPHIFY_CHOICE=$choice"
|
|
1269
|
+
else
|
|
1270
|
+
echo "" >&2
|
|
1271
|
+
echo "Choose an option:" >&2
|
|
1272
|
+
echo " [A] Run ralphify init and redo the proposal, then continue" >&2
|
|
1273
|
+
echo " [C] Continue without init" >&2
|
|
1274
|
+
echo " [Q] Quit" >&2
|
|
1275
|
+
printf "Enter choice: " >&2
|
|
1276
|
+
if ! read -r choice; then
|
|
1277
|
+
log_info "Non-interactive environment detected. Continuing without Ralph Wiggum configuration."
|
|
1278
|
+
return 0
|
|
1279
|
+
fi
|
|
1312
1280
|
fi
|
|
1313
1281
|
|
|
1314
1282
|
case "$choice" in
|
|
@@ -1474,7 +1442,6 @@ main() {
|
|
|
1474
1442
|
|
|
1475
1443
|
ensure_artifacts_present "$change_dir" "$CHANGE_NAME"
|
|
1476
1444
|
|
|
1477
|
-
validate_openspec_artifacts "$change_dir"
|
|
1478
1445
|
validate_script_state "$change_dir"
|
|
1479
1446
|
local ralph_dir=$(setup_ralph_directory "$change_dir")
|
|
1480
1447
|
|