spec-and-loop 1.0.7 → 1.0.8
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/package.json +1 -1
- package/scripts/ralph-monitor.sh +53 -6
- package/scripts/ralph-run.sh +80 -13
- package/scripts/setup.js +1 -1
package/package.json
CHANGED
package/scripts/ralph-monitor.sh
CHANGED
|
@@ -13,6 +13,16 @@ detect_os() {
|
|
|
13
13
|
|
|
14
14
|
detect_os
|
|
15
15
|
|
|
16
|
+
# Cross-platform file modification time
|
|
17
|
+
get_file_mtime() {
|
|
18
|
+
local file="$1"
|
|
19
|
+
if [[ "$OS" == "macOS" ]]; then
|
|
20
|
+
stat -f %m "$file" 2>/dev/null || echo 0
|
|
21
|
+
else
|
|
22
|
+
stat -c %Y "$file" 2>/dev/null || echo 0
|
|
23
|
+
fi
|
|
24
|
+
}
|
|
25
|
+
|
|
16
26
|
# Cross-platform file modification time display
|
|
17
27
|
get_file_mtime_display() {
|
|
18
28
|
local file="$1"
|
|
@@ -23,20 +33,57 @@ get_file_mtime_display() {
|
|
|
23
33
|
fi
|
|
24
34
|
}
|
|
25
35
|
|
|
26
|
-
|
|
36
|
+
resolve_project_root() {
|
|
37
|
+
local git_root=""
|
|
38
|
+
git_root=$(git rev-parse --show-toplevel 2>/dev/null || echo "")
|
|
39
|
+
|
|
40
|
+
if [[ -n "$git_root" ]]; then
|
|
41
|
+
printf "%s" "$git_root"
|
|
42
|
+
else
|
|
43
|
+
pwd
|
|
44
|
+
fi
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
auto_detect_change() {
|
|
48
|
+
local project_root="$1"
|
|
49
|
+
local changes_dir="$project_root/openspec/changes"
|
|
50
|
+
|
|
51
|
+
if [[ ! -d "$changes_dir" ]]; then
|
|
52
|
+
echo ""
|
|
53
|
+
return 1
|
|
54
|
+
fi
|
|
55
|
+
|
|
56
|
+
local latest_change=""
|
|
57
|
+
local latest_time=0
|
|
58
|
+
|
|
59
|
+
for change_dir in "$changes_dir"/*; do
|
|
60
|
+
if [[ -d "$change_dir" && -f "$change_dir/tasks.md" ]]; then
|
|
61
|
+
local mod_time
|
|
62
|
+
mod_time=$(get_file_mtime "$change_dir/tasks.md")
|
|
63
|
+
|
|
64
|
+
if [[ "$mod_time" -gt "$latest_time" ]]; then
|
|
65
|
+
latest_time="$mod_time"
|
|
66
|
+
latest_change=$(basename "$change_dir")
|
|
67
|
+
fi
|
|
68
|
+
fi
|
|
69
|
+
done
|
|
70
|
+
|
|
71
|
+
printf "%s" "$latest_change"
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
PROJECT_ROOT="$(resolve_project_root)"
|
|
27
75
|
CHANGE_NAME="${1:-auto-detect}"
|
|
28
76
|
|
|
29
77
|
if [[ "$CHANGE_NAME" == "auto-detect" ]]; then
|
|
30
|
-
|
|
31
|
-
CHANGE_NAME=$(ls -t openspec/changes/ 2>/dev/null | head -1)
|
|
78
|
+
CHANGE_NAME=$(auto_detect_change "$PROJECT_ROOT")
|
|
32
79
|
if [[ -z "$CHANGE_NAME" ]]; then
|
|
33
|
-
echo "No changes found in openspec/changes/"
|
|
80
|
+
echo "No changes found in $PROJECT_ROOT/openspec/changes/"
|
|
34
81
|
exit 1
|
|
35
82
|
fi
|
|
36
83
|
fi
|
|
37
84
|
|
|
38
|
-
TASKS_FILE="$
|
|
39
|
-
RALPH_STATE="$
|
|
85
|
+
TASKS_FILE="$PROJECT_ROOT/openspec/changes/$CHANGE_NAME/tasks.md"
|
|
86
|
+
RALPH_STATE="$PROJECT_ROOT/.ralph/ralph-loop.state.json"
|
|
40
87
|
|
|
41
88
|
if [[ ! -f "$TASKS_FILE" ]]; then
|
|
42
89
|
echo "Tasks file not found: $TASKS_FILE"
|
package/scripts/ralph-run.sh
CHANGED
|
@@ -61,6 +61,64 @@ get_realpath() {
|
|
|
61
61
|
fi
|
|
62
62
|
}
|
|
63
63
|
|
|
64
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
65
|
+
LOCAL_NODE_BIN="$SCRIPT_DIR/../node_modules/.bin"
|
|
66
|
+
BUNDLED_RALPH_JS="$SCRIPT_DIR/../node_modules/@th0rgal/ralph-wiggum/bin/ralph.js"
|
|
67
|
+
RALPH_CMD=()
|
|
68
|
+
|
|
69
|
+
if [[ -d "$LOCAL_NODE_BIN" ]]; then
|
|
70
|
+
case ":$PATH:" in
|
|
71
|
+
*":$LOCAL_NODE_BIN:"*) ;;
|
|
72
|
+
*) export PATH="$LOCAL_NODE_BIN:$PATH" ;;
|
|
73
|
+
esac
|
|
74
|
+
fi
|
|
75
|
+
|
|
76
|
+
get_temp_root() {
|
|
77
|
+
local temp_root="${TMPDIR:-/tmp}"
|
|
78
|
+
temp_root="${temp_root%/}"
|
|
79
|
+
|
|
80
|
+
if [[ -z "$temp_root" ]]; then
|
|
81
|
+
temp_root="/tmp"
|
|
82
|
+
fi
|
|
83
|
+
|
|
84
|
+
printf "%s" "$temp_root"
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
make_temp_dir() {
|
|
88
|
+
local prefix="${1:-ralph-run}"
|
|
89
|
+
local temp_root
|
|
90
|
+
temp_root=$(get_temp_root)
|
|
91
|
+
|
|
92
|
+
local temp_dir=""
|
|
93
|
+
temp_dir=$(mktemp -d "${temp_root}/${prefix}-XXXXXX" 2>/dev/null) || \
|
|
94
|
+
temp_dir=$(mktemp -d -t "$prefix" 2>/dev/null) || \
|
|
95
|
+
temp_dir=""
|
|
96
|
+
|
|
97
|
+
if [[ -n "$temp_dir" ]]; then
|
|
98
|
+
printf "%s" "$temp_dir"
|
|
99
|
+
return 0
|
|
100
|
+
fi
|
|
101
|
+
|
|
102
|
+
local fallback_dir="${temp_root}/${prefix}-$(date +"%Y%m%d_%H%M%S")-$$"
|
|
103
|
+
mkdir -p "$fallback_dir"
|
|
104
|
+
printf "%s" "$fallback_dir"
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
resolve_ralph_command() {
|
|
108
|
+
if command -v ralph >/dev/null 2>&1; then
|
|
109
|
+
RALPH_CMD=("ralph")
|
|
110
|
+
return 0
|
|
111
|
+
fi
|
|
112
|
+
|
|
113
|
+
if [[ -f "$BUNDLED_RALPH_JS" ]] && command -v node >/dev/null 2>&1; then
|
|
114
|
+
RALPH_CMD=("node" "$BUNDLED_RALPH_JS")
|
|
115
|
+
return 0
|
|
116
|
+
fi
|
|
117
|
+
|
|
118
|
+
RALPH_CMD=()
|
|
119
|
+
return 1
|
|
120
|
+
}
|
|
121
|
+
|
|
64
122
|
CHANGE_NAME=""
|
|
65
123
|
MAX_ITERATIONS=""
|
|
66
124
|
ERROR_OCCURRED=false
|
|
@@ -126,7 +184,7 @@ PREREQUISITES:
|
|
|
126
184
|
- Git repository (git init)
|
|
127
185
|
- OpenSpec artifacts created (openspec init, opsx-new, opsx-ff)
|
|
128
186
|
- ralph CLI installed (npm install -g @th0rgal/ralph-wiggum)
|
|
129
|
-
- opencode CLI installed (npm install -g opencode)
|
|
187
|
+
- opencode CLI installed (npm install -g opencode-ai)
|
|
130
188
|
|
|
131
189
|
EOF
|
|
132
190
|
}
|
|
@@ -193,21 +251,29 @@ validate_git_repository() {
|
|
|
193
251
|
validate_dependencies() {
|
|
194
252
|
log_verbose "Validating dependencies..."
|
|
195
253
|
|
|
196
|
-
|
|
197
|
-
if ! command -v ralph &> /dev/null; then
|
|
254
|
+
if ! resolve_ralph_command; then
|
|
198
255
|
log_error "ralph CLI not found."
|
|
199
256
|
log_error "Please install open-ralph-wiggum: npm install -g @th0rgal/ralph-wiggum"
|
|
257
|
+
log_error "If spec-and-loop is globally installed, reinstalling it should also restore the bundled Ralph dependency."
|
|
200
258
|
exit 1
|
|
201
259
|
fi
|
|
202
|
-
log_verbose "Found:
|
|
260
|
+
log_verbose "Found Ralph command: ${RALPH_CMD[*]}"
|
|
203
261
|
|
|
204
262
|
# Check for opencode
|
|
205
263
|
if ! command -v opencode &> /dev/null; then
|
|
206
264
|
log_error "opencode CLI not found."
|
|
207
|
-
log_error "Please install opencode: npm install -g opencode"
|
|
265
|
+
log_error "Please install opencode: npm install -g opencode-ai"
|
|
208
266
|
exit 1
|
|
209
267
|
fi
|
|
210
268
|
log_verbose "Found: opencode"
|
|
269
|
+
|
|
270
|
+
# Check for jq
|
|
271
|
+
if ! command -v jq &> /dev/null; then
|
|
272
|
+
log_error "jq CLI not found."
|
|
273
|
+
log_error "Please install jq: brew install jq / apt-get install jq"
|
|
274
|
+
exit 1
|
|
275
|
+
fi
|
|
276
|
+
log_verbose "Found: jq"
|
|
211
277
|
|
|
212
278
|
log_verbose "All dependencies validated"
|
|
213
279
|
}
|
|
@@ -854,11 +920,9 @@ setup_output_capture() {
|
|
|
854
920
|
|
|
855
921
|
log_verbose "Setting up output capture..."
|
|
856
922
|
|
|
857
|
-
#
|
|
858
|
-
local
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
mkdir -p "$output_dir"
|
|
923
|
+
# Use the system temp directory so macOS and Linux both work naturally.
|
|
924
|
+
local output_dir
|
|
925
|
+
output_dir=$(make_temp_dir "ralph-run")
|
|
862
926
|
log_info "Output directory: $output_dir"
|
|
863
927
|
|
|
864
928
|
# Store output directory path in Ralph directory for reference
|
|
@@ -870,8 +934,11 @@ setup_output_capture() {
|
|
|
870
934
|
cleanup_old_output() {
|
|
871
935
|
log_verbose "Cleaning up old Ralph output directories..."
|
|
872
936
|
|
|
937
|
+
local temp_root
|
|
938
|
+
temp_root=$(get_temp_root)
|
|
939
|
+
|
|
873
940
|
# Keep last 3 Ralph output directories, delete older ones
|
|
874
|
-
find
|
|
941
|
+
find "$temp_root" -type d -name "ralph-run*" -mtime +7 2>/dev/null | while IFS= read -r old_dir; do
|
|
875
942
|
log_verbose "Removing old output directory: $old_dir"
|
|
876
943
|
rm -rf "$old_dir"
|
|
877
944
|
done
|
|
@@ -886,7 +953,7 @@ execute_ralph_loop() {
|
|
|
886
953
|
log_info "Max iterations: $max_iterations"
|
|
887
954
|
log_info "Change directory: $change_dir"
|
|
888
955
|
|
|
889
|
-
if !
|
|
956
|
+
if ! resolve_ralph_command; then
|
|
890
957
|
log_error "ralph CLI not found."
|
|
891
958
|
log_error "Please install open-ralph-wiggum: npm install -g @th0rgal/ralph-wiggum"
|
|
892
959
|
return 1
|
|
@@ -932,7 +999,7 @@ execute_ralph_loop() {
|
|
|
932
999
|
|
|
933
1000
|
# Run Ralph and capture output to both console and files
|
|
934
1001
|
{
|
|
935
|
-
|
|
1002
|
+
"${RALPH_CMD[@]}" --prompt-file "$ralph_dir/PRD.md" \
|
|
936
1003
|
--agent opencode \
|
|
937
1004
|
--tasks \
|
|
938
1005
|
--max-iterations "$max_iterations" \
|
package/scripts/setup.js
CHANGED
|
@@ -38,6 +38,6 @@ console.log(' ralph-run # Auto-detect change');
|
|
|
38
38
|
console.log('');
|
|
39
39
|
console.log('Prerequisites:');
|
|
40
40
|
console.log(' - openspec CLI: npm install -g openspec');
|
|
41
|
-
console.log(' - opencode CLI: npm install -g opencode');
|
|
41
|
+
console.log(' - opencode CLI: npm install -g opencode-ai');
|
|
42
42
|
console.log(' - jq CLI: apt install jq / brew install jq');
|
|
43
43
|
console.log(' - git: git init');
|