spec-and-loop 1.0.0 → 1.0.2
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/QUICKSTART.md +7 -7
- package/README.md +21 -29
- package/package.json +4 -4
- package/scripts/ralph-monitor.sh +96 -0
- package/scripts/ralph-run.sh +351 -183
package/QUICKSTART.md
CHANGED
|
@@ -8,10 +8,10 @@ Install these tools (one-time setup):
|
|
|
8
8
|
|
|
9
9
|
```bash
|
|
10
10
|
# 1. Install openspec (OpenSpec CLI)
|
|
11
|
-
npm install -g openspec
|
|
11
|
+
npm install -g @fission-ai/openspec@latest
|
|
12
12
|
|
|
13
13
|
# 2. Install opencode (agentic coding assistant)
|
|
14
|
-
npm install -g opencode
|
|
14
|
+
npm install -g opencode-ai
|
|
15
15
|
|
|
16
16
|
# 3. Install jq (command-line JSON processor)
|
|
17
17
|
# Ubuntu/Debian:
|
|
@@ -32,7 +32,7 @@ npm install -g spec-and-loop
|
|
|
32
32
|
|
|
33
33
|
**Prerequisites:** Install openspec and opencode:
|
|
34
34
|
```bash
|
|
35
|
-
npm install -g openspec opencode
|
|
35
|
+
npm install -g @fission-ai/openspec@latest opencode-ai
|
|
36
36
|
```
|
|
37
37
|
|
|
38
38
|
## Quick Demo (5 Minutes)
|
|
@@ -47,10 +47,10 @@ git init
|
|
|
47
47
|
openspec init
|
|
48
48
|
|
|
49
49
|
# 3. Create a new change
|
|
50
|
-
|
|
50
|
+
openspec new add-hello-world
|
|
51
51
|
|
|
52
52
|
# 4. Fast-forward through artifact creation
|
|
53
|
-
|
|
53
|
+
openspec ff
|
|
54
54
|
|
|
55
55
|
# 5. Run the ralph loop (executes tasks with opencode)
|
|
56
56
|
ralph-run --change add-hello-world
|
|
@@ -156,7 +156,7 @@ git diff HEAD~15 # See full implementation
|
|
|
156
156
|
### "openspec CLI not found" or "opencode CLI not found"
|
|
157
157
|
|
|
158
158
|
```bash
|
|
159
|
-
npm install -g openspec opencode
|
|
159
|
+
npm install -g @fission-ai/openspec@latest opencode-ai
|
|
160
160
|
```
|
|
161
161
|
|
|
162
162
|
### "jq CLI not found"
|
|
@@ -198,7 +198,7 @@ source ~/.bashrc
|
|
|
198
198
|
grep "^\- \[x\]" openspec/changes/my-feature/tasks.md
|
|
199
199
|
|
|
200
200
|
# Or create a new change
|
|
201
|
-
|
|
201
|
+
openspec new another-feature
|
|
202
202
|
```
|
|
203
203
|
|
|
204
204
|
## Features at a Glance
|
package/README.md
CHANGED
|
@@ -8,41 +8,35 @@ OpenSpec + Ralph Loop integration for iterative development with opencode.
|
|
|
8
8
|
|
|
9
9
|
OpenSpec provides excellent structure for planning (proposal → specs → design → tasks) but leaves execution manual. Ralph Wiggum's iterative development loop (execute → commit → repeat) is powerful but requires PRD format instead of OpenSpec specs.
|
|
10
10
|
|
|
11
|
-
**This utility bridges the gap**: use OpenSpec for planning, then automatically execute tasks with full context using opencode agentic coding assistant.
|
|
12
|
-
|
|
13
11
|
## Installation
|
|
14
12
|
|
|
15
13
|
```bash
|
|
16
14
|
npm install -g spec-and-loop
|
|
17
15
|
```
|
|
18
16
|
|
|
19
|
-
**Prerequisites:** You need
|
|
17
|
+
**Prerequisites:** You need OpenSpec and the OpenCode AI agent installed:
|
|
20
18
|
|
|
21
19
|
```bash
|
|
22
|
-
|
|
20
|
+
# Install OpenSpec and OpenCode (recommended)
|
|
21
|
+
npm install -g @fission-ai/openspec@latest opencode-ai
|
|
23
22
|
```
|
|
24
23
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
**[🚀 Get Started in 5 Minutes](./QUICKSTART.md)**
|
|
24
|
+
Alternative OpenCode install methods (if you prefer):
|
|
28
25
|
|
|
29
26
|
```bash
|
|
30
|
-
#
|
|
31
|
-
|
|
27
|
+
# npm (recommended)
|
|
28
|
+
npm install -g opencode-ai
|
|
32
29
|
|
|
33
|
-
#
|
|
34
|
-
|
|
30
|
+
# Install script (general use)
|
|
31
|
+
curl -fsSL https://opencode.ai/install | bash
|
|
35
32
|
|
|
36
|
-
#
|
|
37
|
-
|
|
33
|
+
# Homebrew (macOS / Linux)
|
|
34
|
+
brew install anomalyco/tap/opencode
|
|
38
35
|
|
|
39
|
-
#
|
|
40
|
-
ralph-run --change add-user-auth
|
|
36
|
+
# Windows: use WSL and install via one of the Linux methods above
|
|
41
37
|
```
|
|
42
38
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
## Quick Start
|
|
39
|
+
**[🚀 Get Started in 5 Minutes](./QUICKSTART.md)**
|
|
46
40
|
|
|
47
41
|
```bash
|
|
48
42
|
# 1. Initialize OpenSpec in your project
|
|
@@ -58,30 +52,28 @@ openspec ff add-user-auth
|
|
|
58
52
|
ralph-run --change add-user-auth
|
|
59
53
|
```
|
|
60
54
|
|
|
61
|
-
|
|
55
|
+
For detailed step-by-step instructions, see [QUICKSTART.md](./QUICKSTART.md).
|
|
62
56
|
|
|
63
|
-
|
|
64
|
-
ralph-run
|
|
65
|
-
```
|
|
57
|
+
<!-- Duplicate Quick Start removed; see QUICKSTART.md for full instructions -->
|
|
66
58
|
|
|
67
59
|
## Prerequisites
|
|
68
60
|
|
|
69
61
|
Before using spec-and-loop, ensure you have:
|
|
70
62
|
|
|
71
|
-
1. **Node.js
|
|
63
|
+
1. **Node.js** - For package installation
|
|
72
64
|
```bash
|
|
73
|
-
node --version # Should be
|
|
74
|
-
npm --version # Should be 6+
|
|
65
|
+
node --version # Should be >=24
|
|
75
66
|
```
|
|
76
67
|
|
|
77
68
|
2. **openspec** - OpenSpec CLI for specification workflow
|
|
78
69
|
```bash
|
|
79
|
-
npm install -g openspec
|
|
70
|
+
npm install -g @fission-ai/openspec@latest
|
|
80
71
|
```
|
|
81
72
|
|
|
82
73
|
3. **opencode** - Agentic coding assistant
|
|
83
74
|
```bash
|
|
84
|
-
|
|
75
|
+
# Install via npm
|
|
76
|
+
npm install -g opencode-ai
|
|
85
77
|
```
|
|
86
78
|
|
|
87
79
|
4. **jq** - Command-line JSON processor
|
|
@@ -321,7 +313,7 @@ For common issues and solutions, see [QUICKSTART.md#troubleshooting](./QUICKSTAR
|
|
|
321
313
|
|
|
322
314
|
```bash
|
|
323
315
|
# opencode not found?
|
|
324
|
-
npm install -g opencode
|
|
316
|
+
npm install -g opencode-ai
|
|
325
317
|
|
|
326
318
|
# jq not found?
|
|
327
319
|
sudo apt install jq # or: brew install jq
|
|
@@ -341,4 +333,4 @@ export PATH="$PATH:$(npm root -g)/.bin"
|
|
|
341
333
|
|
|
342
334
|
## License
|
|
343
335
|
|
|
344
|
-
|
|
336
|
+
GPL-3.0
|
package/package.json
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "spec-and-loop",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.2",
|
|
4
4
|
"description": "OpenSpec + Ralph Loop integration for iterative development with opencode",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"bin": {
|
|
7
|
-
"ralph-run": "
|
|
7
|
+
"ralph-run": "bin/ralph-run"
|
|
8
8
|
},
|
|
9
9
|
"scripts": {
|
|
10
10
|
"postinstall": "node scripts/setup.js"
|
|
11
11
|
},
|
|
12
12
|
"dependencies": {
|
|
13
|
-
"openspec": "
|
|
13
|
+
"@fission-ai/openspec": "latest"
|
|
14
14
|
},
|
|
15
15
|
"keywords": [
|
|
16
16
|
"openspec",
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
"license": "GPL-3.0",
|
|
24
24
|
"repository": {
|
|
25
25
|
"type": "git",
|
|
26
|
-
"url": "https://github.com/ncheaz/spec-and-loop.git"
|
|
26
|
+
"url": "git+https://github.com/ncheaz/spec-and-loop.git"
|
|
27
27
|
},
|
|
28
28
|
"files": [
|
|
29
29
|
"bin/",
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
|
|
3
|
+
set -e
|
|
4
|
+
|
|
5
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
6
|
+
CHANGE_NAME="${1:-auto-detect}"
|
|
7
|
+
|
|
8
|
+
if [[ "$CHANGE_NAME" == "auto-detect" ]]; then
|
|
9
|
+
# Auto-detect most recent change
|
|
10
|
+
CHANGE_NAME=$(ls -t openspec/changes/ 2>/dev/null | head -1)
|
|
11
|
+
if [[ -z "$CHANGE_NAME" ]]; then
|
|
12
|
+
echo "No changes found in openspec/changes/"
|
|
13
|
+
exit 1
|
|
14
|
+
fi
|
|
15
|
+
fi
|
|
16
|
+
|
|
17
|
+
TASKS_FILE="$SCRIPT_DIR/../openspec/changes/$CHANGE_NAME/tasks.md"
|
|
18
|
+
RALPH_STATE="$SCRIPT_DIR/../.ralph/ralph-loop.state.json"
|
|
19
|
+
|
|
20
|
+
if [[ ! -f "$TASKS_FILE" ]]; then
|
|
21
|
+
echo "Tasks file not found: $TASKS_FILE"
|
|
22
|
+
exit 1
|
|
23
|
+
fi
|
|
24
|
+
|
|
25
|
+
clear
|
|
26
|
+
while true; do
|
|
27
|
+
clear
|
|
28
|
+
|
|
29
|
+
echo "======================================================================="
|
|
30
|
+
echo " Ralph Progress Monitor - Change: $CHANGE_NAME"
|
|
31
|
+
echo "======================================================================="
|
|
32
|
+
echo ""
|
|
33
|
+
|
|
34
|
+
# Progress bar
|
|
35
|
+
total=$(grep -c "^- \[" "$TASKS_FILE" 2>/dev/null) || total=0
|
|
36
|
+
completed=$(grep -c "^- \[x\]" "$TASKS_FILE" 2>/dev/null) || completed=0
|
|
37
|
+
in_progress=$(grep -c "^- \[\/\]" "$TASKS_FILE" 2>/dev/null) || in_progress=0
|
|
38
|
+
|
|
39
|
+
remaining=$((total - completed - in_progress))
|
|
40
|
+
|
|
41
|
+
if [[ $total -gt 0 ]]; then
|
|
42
|
+
progress=$((completed * 100 / total))
|
|
43
|
+
echo " Progress: $completed/$total tasks completed ($progress%)"
|
|
44
|
+
echo " Status: $in_progress in progress, $remaining remaining"
|
|
45
|
+
|
|
46
|
+
# Simple progress bar
|
|
47
|
+
filled=$((completed * 50 / total))
|
|
48
|
+
bar=$(printf '#%.0s' $(seq 1 $filled))
|
|
49
|
+
empty=$(printf '.%.0s' $(seq 1 $((50 - filled))))
|
|
50
|
+
echo " |$bar$empty|"
|
|
51
|
+
fi
|
|
52
|
+
echo ""
|
|
53
|
+
|
|
54
|
+
# Ralph state
|
|
55
|
+
if [[ -f "$RALPH_STATE" ]]; then
|
|
56
|
+
echo " Ralph State:"
|
|
57
|
+
jq -r '
|
|
58
|
+
" Iteration: \(.iteration)/\(.maxIterations)",
|
|
59
|
+
" Active: \(.active)",
|
|
60
|
+
" Mode: \(.tasksMode // "N/A")",
|
|
61
|
+
" Prompt: \(.completionPromise // "N/A")"
|
|
62
|
+
' "$RALPH_STATE" 2>/dev/null || echo " Unable to read state"
|
|
63
|
+
echo ""
|
|
64
|
+
fi
|
|
65
|
+
|
|
66
|
+
# Current task
|
|
67
|
+
echo " Current Task:"
|
|
68
|
+
current_task=$(grep -n "^- \[\/\]" "$TASKS_FILE" 2>/dev/null | head -1)
|
|
69
|
+
if [[ -n "$current_task" ]]; then
|
|
70
|
+
echo " $current_task"
|
|
71
|
+
else
|
|
72
|
+
# Show next incomplete task
|
|
73
|
+
next_task=$(grep -n "^- \[ \]" "$TASKS_FILE" 2>/dev/null | head -1)
|
|
74
|
+
if [[ -n "$next_task" ]]; then
|
|
75
|
+
echo " Next: $next_task"
|
|
76
|
+
else
|
|
77
|
+
echo " No current task (idle)"
|
|
78
|
+
fi
|
|
79
|
+
fi
|
|
80
|
+
echo ""
|
|
81
|
+
|
|
82
|
+
# Recent completed tasks (last 3)
|
|
83
|
+
echo " Recently Completed:"
|
|
84
|
+
grep "^- \[x\]" "$TASKS_FILE" 2>/dev/null | tail -3 | sed 's/^- \[x\] / /'
|
|
85
|
+
echo ""
|
|
86
|
+
|
|
87
|
+
# File status
|
|
88
|
+
echo " Last Updated: $(stat -c "%y" "$TASKS_FILE" 2>/dev/null | cut -d'.' -f1)"
|
|
89
|
+
echo ""
|
|
90
|
+
|
|
91
|
+
echo "======================================================================="
|
|
92
|
+
echo " Press Ctrl+C to exit | Refreshing in 2 seconds..."
|
|
93
|
+
echo "======================================================================="
|
|
94
|
+
|
|
95
|
+
sleep 2
|
|
96
|
+
done
|
package/scripts/ralph-run.sh
CHANGED
|
@@ -1,11 +1,44 @@
|
|
|
1
1
|
#!/bin/bash
|
|
2
2
|
|
|
3
3
|
set -e
|
|
4
|
-
trap 'handle_error $?' EXIT
|
|
5
4
|
|
|
6
5
|
VERSION="1.0.0"
|
|
6
|
+
|
|
7
|
+
# Add Bun to PATH if installed
|
|
8
|
+
if [[ -d "$HOME/.bun/bin" ]]; then
|
|
9
|
+
export PATH="$HOME/.bun/bin:$PATH"
|
|
10
|
+
fi
|
|
11
|
+
|
|
7
12
|
CHANGE_NAME=""
|
|
13
|
+
MAX_ITERATIONS=""
|
|
8
14
|
ERROR_OCCURRED=false
|
|
15
|
+
CLEANUP_IN_PROGRESS=false
|
|
16
|
+
|
|
17
|
+
# Trap signals for proper cleanup
|
|
18
|
+
cleanup() {
|
|
19
|
+
# Prevent multiple cleanup calls
|
|
20
|
+
if [[ "$CLEANUP_IN_PROGRESS" == "true" ]]; then
|
|
21
|
+
return 0
|
|
22
|
+
fi
|
|
23
|
+
CLEANUP_IN_PROGRESS=true
|
|
24
|
+
|
|
25
|
+
local exit_code=$1
|
|
26
|
+
log_info "Cleaning up..."
|
|
27
|
+
|
|
28
|
+
# NOTE: We do NOT kill ralph/bun processes here because:
|
|
29
|
+
# 1. Ralph runs synchronously in the foreground
|
|
30
|
+
# 2. Ctrl+C (SIGINT) naturally propagates to child processes
|
|
31
|
+
# 3. Using pkill -f "bun" is DANGEROUS - it matches gnome-session-binary!
|
|
32
|
+
# 4. Using pkill -f "ralph" could kill other user processes
|
|
33
|
+
# The shell's process group handling ensures clean termination.
|
|
34
|
+
|
|
35
|
+
if [[ $exit_code -ne 0 ]]; then
|
|
36
|
+
log_error "Script terminated with exit code: $exit_code"
|
|
37
|
+
fi
|
|
38
|
+
exit $exit_code
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
trap 'cleanup $?' EXIT INT TERM QUIT
|
|
9
42
|
|
|
10
43
|
handle_error() {
|
|
11
44
|
local exit_code=$1
|
|
@@ -26,20 +59,22 @@ USAGE:
|
|
|
26
59
|
ralph-run [OPTIONS]
|
|
27
60
|
|
|
28
61
|
OPTIONS:
|
|
29
|
-
--change <name>
|
|
30
|
-
--
|
|
31
|
-
--
|
|
62
|
+
--change <name> Specify the OpenSpec change to execute (default: auto-detect)
|
|
63
|
+
--max-iterations <n> Maximum iterations for Ralph loop (default: 50)
|
|
64
|
+
--verbose, -v Enable verbose mode for debugging
|
|
65
|
+
--help, -h Show this help message
|
|
32
66
|
|
|
33
67
|
EXAMPLES:
|
|
34
68
|
ralph-run # Auto-detect most recent change
|
|
35
69
|
ralph-run --change my-feature # Execute specific change
|
|
70
|
+
ralph-run --max-iterations 100 # Limit loop to 100 iterations
|
|
36
71
|
ralph-run --verbose # Run with debug output
|
|
37
72
|
|
|
38
73
|
PREREQUISITES:
|
|
39
74
|
- Git repository (git init)
|
|
40
75
|
- OpenSpec artifacts created (openspec init, opsx-new, opsx-ff)
|
|
76
|
+
- ralph CLI installed (npm install -g @th0rgal/ralph-wiggum)
|
|
41
77
|
- opencode CLI installed (npm install -g opencode)
|
|
42
|
-
- jq CLI installed (apt install jq / brew install jq)
|
|
43
78
|
|
|
44
79
|
EOF
|
|
45
80
|
}
|
|
@@ -51,6 +86,10 @@ parse_arguments() {
|
|
|
51
86
|
CHANGE_NAME="$2"
|
|
52
87
|
shift 2
|
|
53
88
|
;;
|
|
89
|
+
--max-iterations)
|
|
90
|
+
MAX_ITERATIONS="$2"
|
|
91
|
+
shift 2
|
|
92
|
+
;;
|
|
54
93
|
--verbose|-v)
|
|
55
94
|
VERBOSE=true
|
|
56
95
|
shift
|
|
@@ -75,12 +114,12 @@ parse_arguments() {
|
|
|
75
114
|
|
|
76
115
|
log_verbose() {
|
|
77
116
|
if [[ "$VERBOSE" == true ]]; then
|
|
78
|
-
echo "[VERBOSE] $*"
|
|
117
|
+
echo "[VERBOSE] $*" >&2
|
|
79
118
|
fi
|
|
80
119
|
}
|
|
81
120
|
|
|
82
121
|
log_info() {
|
|
83
|
-
echo "[INFO] $*"
|
|
122
|
+
echo "[INFO] $*" >&2
|
|
84
123
|
}
|
|
85
124
|
|
|
86
125
|
log_error() {
|
|
@@ -101,7 +140,15 @@ validate_git_repository() {
|
|
|
101
140
|
|
|
102
141
|
validate_dependencies() {
|
|
103
142
|
log_verbose "Validating dependencies..."
|
|
104
|
-
|
|
143
|
+
|
|
144
|
+
# Check for ralph
|
|
145
|
+
if ! command -v ralph &> /dev/null; then
|
|
146
|
+
log_error "ralph CLI not found."
|
|
147
|
+
log_error "Please install open-ralph-wiggum: npm install -g @th0rgal/ralph-wiggum"
|
|
148
|
+
exit 1
|
|
149
|
+
fi
|
|
150
|
+
log_verbose "Found: ralph"
|
|
151
|
+
|
|
105
152
|
# Check for opencode
|
|
106
153
|
if ! command -v opencode &> /dev/null; then
|
|
107
154
|
log_error "opencode CLI not found."
|
|
@@ -109,17 +156,7 @@ validate_dependencies() {
|
|
|
109
156
|
exit 1
|
|
110
157
|
fi
|
|
111
158
|
log_verbose "Found: opencode"
|
|
112
|
-
|
|
113
|
-
# Check for jq
|
|
114
|
-
if ! command -v jq &> /dev/null; then
|
|
115
|
-
log_error "jq CLI not found."
|
|
116
|
-
log_error "Please install jq:"
|
|
117
|
-
log_error " Ubuntu/Debian: apt install jq"
|
|
118
|
-
log_error " macOS: brew install jq"
|
|
119
|
-
exit 1
|
|
120
|
-
fi
|
|
121
|
-
log_verbose "Found: jq"
|
|
122
|
-
|
|
159
|
+
|
|
123
160
|
log_verbose "All dependencies validated"
|
|
124
161
|
}
|
|
125
162
|
|
|
@@ -250,7 +287,16 @@ generate_prd() {
|
|
|
250
287
|
prd_content+="$OPENSPEC_SPECS"$'\n'$'\n'
|
|
251
288
|
|
|
252
289
|
prd_content+="## Design"$'\n'$'\n'
|
|
253
|
-
prd_content+="$OPENSPEC_DESIGN"$'\n'
|
|
290
|
+
prd_content+="$OPENSPEC_DESIGN"$'\n'$'\n'
|
|
291
|
+
|
|
292
|
+
# Add current task context for Ralph to use in commits
|
|
293
|
+
local task_context
|
|
294
|
+
task_context=$(get_current_task_context "$change_dir")
|
|
295
|
+
|
|
296
|
+
if [[ -n "$task_context" ]]; then
|
|
297
|
+
prd_content+="## Current Task Context"$'\n'$'\n'
|
|
298
|
+
prd_content+="$task_context"$'\n'$'\n'
|
|
299
|
+
fi
|
|
254
300
|
|
|
255
301
|
echo "$prd_content"
|
|
256
302
|
}
|
|
@@ -473,22 +519,13 @@ get_git_history() {
|
|
|
473
519
|
gather_opencode_context() {
|
|
474
520
|
local task_description="$1"
|
|
475
521
|
|
|
476
|
-
log_verbose "Gathering opencode context..."
|
|
522
|
+
log_verbose "Gathering minimal opencode context..."
|
|
477
523
|
|
|
478
524
|
local context=""
|
|
479
525
|
|
|
480
526
|
context+="## Task"$'\n'
|
|
481
527
|
context+="$task_description"$'\n'$'\n'
|
|
482
528
|
|
|
483
|
-
context+="## Proposal Summary"$'\n'
|
|
484
|
-
context+="$(echo "$OPENSPEC_PROPOSAL" | head -20)"$'\n'$'\n'
|
|
485
|
-
|
|
486
|
-
context+="## Design Decisions"$'\n'
|
|
487
|
-
context+="$(echo "$OPENSPEC_DESIGN" | head -30)"$'\n'$'\n'
|
|
488
|
-
|
|
489
|
-
context+="## Specifications"$'\n'
|
|
490
|
-
context+="$(echo "$OPENSPEC_SPECS" | head -50)"$'\n'$'\n'
|
|
491
|
-
|
|
492
529
|
echo "$context"
|
|
493
530
|
}
|
|
494
531
|
|
|
@@ -496,227 +533,357 @@ generate_opencode_prompt() {
|
|
|
496
533
|
local task_description="$1"
|
|
497
534
|
local ralph_dir="$2"
|
|
498
535
|
|
|
499
|
-
log_verbose "Generating opencode prompt..."
|
|
536
|
+
log_verbose "Generating minimal opencode prompt..."
|
|
500
537
|
|
|
501
538
|
local context
|
|
502
539
|
context=$(gather_opencode_context "$task_description")
|
|
503
540
|
|
|
504
541
|
local prompt=""
|
|
505
|
-
prompt+="
|
|
542
|
+
prompt+="Implement this task:"$'\n'
|
|
506
543
|
prompt+="$context"$'\n'
|
|
507
544
|
|
|
508
|
-
prompt+="## Recent Git History"$'\n'
|
|
509
|
-
local git_history
|
|
510
|
-
git_history=$(get_git_history 10)
|
|
511
|
-
if [[ -n "$git_history" ]]; then
|
|
512
|
-
echo "$git_history" | while IFS='|' read -r hash date author message; do
|
|
513
|
-
prompt+="- $hash ($date $author): $message"$'\n'
|
|
514
|
-
done
|
|
515
|
-
fi
|
|
516
|
-
prompt+=$'\n'
|
|
517
|
-
|
|
518
|
-
prompt+="## Error History"$'\n'
|
|
519
|
-
local errors_file="$ralph_dir/errors.md"
|
|
520
|
-
if [[ -f "$errors_file" ]]; then
|
|
521
|
-
prompt+="$(cat "$errors_file" | tail -50)"$'\n'
|
|
522
|
-
else
|
|
523
|
-
prompt+="(No previous errors)"$'\n'
|
|
524
|
-
fi
|
|
525
|
-
prompt+=$'\n'
|
|
526
|
-
|
|
527
|
-
prompt+="## Instructions"$'\n'
|
|
528
|
-
prompt+="Implement the task above. Use the context provided to understand the requirements and any relevant design decisions."$'\n'
|
|
529
|
-
prompt+="If there are previous errors, use them to guide your implementation to avoid repeating mistakes."$'\n'
|
|
530
|
-
|
|
531
|
-
local injected_context
|
|
532
|
-
if injected_context=$(handle_context_injection "$ralph_dir"); then
|
|
533
|
-
prompt+=$'\n'
|
|
534
|
-
prompt+="## Injected Context"$'\n'
|
|
535
|
-
prompt+="$injected_context"$'\n'
|
|
536
|
-
fi
|
|
537
|
-
|
|
538
545
|
echo "$prompt"
|
|
539
546
|
}
|
|
540
547
|
|
|
541
|
-
|
|
542
|
-
local
|
|
548
|
+
sync_tasks_to_ralph() {
|
|
549
|
+
local change_dir="$1"
|
|
550
|
+
local ralph_dir="$2"
|
|
543
551
|
|
|
544
|
-
|
|
552
|
+
local tasks_file="$change_dir/tasks.md"
|
|
553
|
+
local ralph_tasks_file=".ralph/ralph-tasks.md"
|
|
554
|
+
local old_ralph_tasks_file="$change_dir/.ralph/ralph-tasks.md"
|
|
545
555
|
|
|
546
|
-
if !
|
|
547
|
-
log_error "
|
|
556
|
+
if [[ ! -f "$tasks_file" ]]; then
|
|
557
|
+
log_error "Tasks file not found: $tasks_file"
|
|
548
558
|
return 1
|
|
549
559
|
fi
|
|
550
560
|
|
|
551
|
-
local
|
|
552
|
-
output=$(echo "$prompt" | opencode 2>&1)
|
|
553
|
-
local exit_code=$?
|
|
561
|
+
local abs_tasks_file=$(realpath "$tasks_file" 2>/dev/null)
|
|
554
562
|
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
local task_description="$1"
|
|
561
|
-
|
|
562
|
-
log_verbose "Creating git commit..."
|
|
563
|
+
# Clean up old Ralph tasks file in change directory if exists
|
|
564
|
+
if [[ -f "$old_ralph_tasks_file" ]]; then
|
|
565
|
+
log_verbose "Removing old Ralph tasks file from change directory: $old_ralph_tasks_file"
|
|
566
|
+
rm "$old_ralph_tasks_file"
|
|
567
|
+
fi
|
|
563
568
|
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
569
|
+
# Use symlink so Ralph and openspec-apply-change work on the SAME file
|
|
570
|
+
if [[ -L "$ralph_tasks_file" ]]; then
|
|
571
|
+
log_verbose "Symlink exists, ensuring it points to correct location"
|
|
572
|
+
local current_target=$(readlink -f "$ralph_tasks_file" 2>/dev/null || echo "")
|
|
573
|
+
|
|
574
|
+
if [[ "$current_target" != "$abs_tasks_file" ]]; then
|
|
575
|
+
log_verbose "Updating symlink to point to new change directory"
|
|
576
|
+
ln -sf "$abs_tasks_file" "$ralph_tasks_file"
|
|
577
|
+
fi
|
|
578
|
+
elif [[ -f "$ralph_tasks_file" ]]; then
|
|
579
|
+
# File exists but is not a symlink - replace with symlink
|
|
580
|
+
log_verbose "Replacing regular file with symlink to openspec tasks..."
|
|
581
|
+
rm "$ralph_tasks_file"
|
|
582
|
+
ln -sf "$abs_tasks_file" "$ralph_tasks_file"
|
|
568
583
|
else
|
|
569
|
-
|
|
584
|
+
# No file exists - create new symlink
|
|
585
|
+
log_verbose "Creating symlink from .ralph/ralph-tasks.md to openspec tasks..."
|
|
586
|
+
ln -sf "$abs_tasks_file" "$ralph_tasks_file"
|
|
570
587
|
fi
|
|
588
|
+
|
|
589
|
+
log_verbose "Symlink configured: $ralph_tasks_file -> $abs_tasks_file"
|
|
571
590
|
}
|
|
572
591
|
|
|
573
|
-
|
|
574
|
-
local
|
|
592
|
+
create_prompt_template() {
|
|
593
|
+
local change_dir="$1"
|
|
594
|
+
local template_file="$2"
|
|
575
595
|
|
|
576
|
-
|
|
596
|
+
log_verbose "Creating custom prompt template..."
|
|
577
597
|
|
|
578
|
-
local
|
|
579
|
-
|
|
598
|
+
local abs_change_dir
|
|
599
|
+
abs_change_dir=$(realpath "$change_dir" 2>/dev/null)
|
|
580
600
|
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
601
|
+
cat > "$template_file" << 'EOF'
|
|
602
|
+
# Ralph Wiggum Task Execution - Iteration {{iteration}} / {{max_iterations}}
|
|
603
|
+
|
|
604
|
+
Change directory: {{change_dir}}
|
|
605
|
+
|
|
606
|
+
## OpenSpec Artifacts Context
|
|
607
|
+
|
|
608
|
+
Include full context from openspec artifacts in {{change_dir}}:
|
|
609
|
+
- Read {{change_dir}}/proposal.md for the overall project goal
|
|
610
|
+
- Read {{change_dir}}/design.md for the technical design approach
|
|
611
|
+
- Read {{change_dir}}/specs/*/spec.md for the detailed specifications
|
|
612
|
+
|
|
613
|
+
## Task List
|
|
614
|
+
|
|
615
|
+
{{tasks}}
|
|
616
|
+
|
|
617
|
+
## Instructions
|
|
618
|
+
|
|
619
|
+
1. **Identify** current task:
|
|
620
|
+
- Find any task marked as [/] (in progress)
|
|
621
|
+
- If no task is in progress, pick the first task marked as [ ] (incomplete)
|
|
622
|
+
- Mark the task as [/] in the tasks file before starting work
|
|
623
|
+
|
|
624
|
+
2. **Implement** task using openspec-apply-change:
|
|
625
|
+
- Use the /opsx-apply skill to implement the current task
|
|
626
|
+
- Read the relevant openspec artifacts for context (proposal.md, design.md, specs)
|
|
627
|
+
- Follow the openspec workflow to complete the task
|
|
628
|
+
- The openspec-apply-change skill will implement changes and update task status automatically
|
|
629
|
+
|
|
630
|
+
3. **Complete** task:
|
|
631
|
+
- Verify that the implementation meets the requirements
|
|
632
|
+
- When the task is successfully completed, mark it as [x] in the tasks file
|
|
633
|
+
- Output: `<promise>{{task_promise}}</promise>`
|
|
634
|
+
|
|
635
|
+
4. **Continue** to the next task:
|
|
636
|
+
- The loop will continue with the next iteration
|
|
637
|
+
- Find the next incomplete task and repeat the process
|
|
638
|
+
|
|
639
|
+
## Critical Rules
|
|
640
|
+
|
|
641
|
+
- Work on ONE task at a time from the task list
|
|
642
|
+
- Use openspec-apply-change (/opsx-apply) for implementation
|
|
643
|
+
- ONLY output `<promise>{{task_promise}}</promise>` when the current task is complete and marked as [x]
|
|
644
|
+
- ONLY output `<promise>{{completion_promise}}</promise>` when ALL tasks are [x]
|
|
645
|
+
- Output promise tags DIRECTLY - do not quote them, explain them, or say you "will" output them
|
|
646
|
+
- Do NOT lie or output false promises to exit the loop
|
|
647
|
+
- If stuck, try a different approach
|
|
648
|
+
- Check your work before claiming completion
|
|
649
|
+
|
|
650
|
+
## CRITICAL: Git Commit Format (MANDATORY)
|
|
651
|
+
|
|
652
|
+
When making git commits, you MUST use this EXACT format:
|
|
653
|
+
|
|
654
|
+
```
|
|
655
|
+
Ralph iteration <N>: <brief description of work completed>
|
|
656
|
+
|
|
657
|
+
Tasks completed:
|
|
658
|
+
- [x] <task.number> <task description text>
|
|
659
|
+
- [x] <task.number> <task description text>
|
|
660
|
+
...
|
|
661
|
+
```
|
|
662
|
+
|
|
663
|
+
**Requirements:**
|
|
664
|
+
1. Use iteration number from Ralph's state (e.g., "Ralph iteration 7")
|
|
665
|
+
2. Include a BRIEF description summarizing what was done
|
|
666
|
+
3. List ALL completed tasks with their numbers and full descriptions
|
|
667
|
+
4. Use the EXACT format: "- [x] <task.number> <task description>"
|
|
668
|
+
5. Read the "## Completed Tasks for Git Commit" section from the PRD for the task list
|
|
669
|
+
|
|
670
|
+
**FORBIDDEN:**
|
|
671
|
+
- DO NOT use generic messages like "work in progress" or "iteration N"
|
|
672
|
+
- DO NOT skip task numbers
|
|
673
|
+
- DO NOT truncate task descriptions
|
|
674
|
+
- DO NOT create commits without task information
|
|
675
|
+
|
|
676
|
+
**Example:**
|
|
677
|
+
```
|
|
678
|
+
Ralph iteration 7: Implement unit tests for response processing
|
|
679
|
+
|
|
680
|
+
Tasks completed:
|
|
681
|
+
- [x] 11.6 Write unit test for personality state management
|
|
682
|
+
- [x] 11.7 Write unit test for personality validation
|
|
683
|
+
- [x] 11.8 Write unit test for system prompt validation
|
|
684
|
+
```
|
|
685
|
+
|
|
686
|
+
{{context}}
|
|
687
|
+
EOF
|
|
603
688
|
|
|
604
|
-
|
|
689
|
+
sed -i "s|{{change_dir}}|$abs_change_dir|g" "$template_file"
|
|
690
|
+
|
|
691
|
+
log_verbose "Prompt template created: $template_file"
|
|
605
692
|
}
|
|
606
693
|
|
|
607
|
-
|
|
608
|
-
local
|
|
609
|
-
local
|
|
694
|
+
restore_ralph_state_from_tasks() {
|
|
695
|
+
local tasks_file="$1"
|
|
696
|
+
local ralph_loop_file=".ralph/ralph-loop.state.json"
|
|
610
697
|
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
log_verbose "Creating tracking.json..."
|
|
615
|
-
echo '{"tasks":{}}' > "$tracking_file"
|
|
698
|
+
if [[ ! -f "$ralph_loop_file" ]]; then
|
|
699
|
+
log_verbose "No Ralph state file found, nothing to restore"
|
|
700
|
+
return 0
|
|
616
701
|
fi
|
|
617
702
|
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
read_tracking() {
|
|
622
|
-
local tracking_file="$1"
|
|
703
|
+
# Read current iteration from state file - don't use completed task count
|
|
704
|
+
local current_iteration
|
|
705
|
+
current_iteration=$(jq -r '.iteration // 0' "$ralph_loop_file" 2>/dev/null || echo "0")
|
|
623
706
|
|
|
624
|
-
|
|
707
|
+
# Count completed tasks for informational purposes only
|
|
708
|
+
local completed_count=$(grep -c "^- \[x\]" "$tasks_file" 2>/dev/null || echo "0")
|
|
709
|
+
log_verbose "Found $completed_count completed tasks in tasks.md (iteration $current_iteration)"
|
|
625
710
|
|
|
626
|
-
|
|
627
|
-
|
|
711
|
+
# Read maxIterations from state file
|
|
712
|
+
local max_iterations
|
|
713
|
+
max_iterations=$(jq -r '.maxIterations // 50' "$ralph_loop_file" 2>/dev/null || echo "50")
|
|
714
|
+
|
|
715
|
+
# Only update iteration if it's 0 or missing (fresh start)
|
|
716
|
+
if [[ $current_iteration -eq 0 ]]; then
|
|
717
|
+
log_verbose "Setting initial iteration to 1 (max: $max_iterations)"
|
|
718
|
+
local updated_state
|
|
719
|
+
updated_state=$(jq --argjson state "$(cat "$ralph_loop_file")" '
|
|
720
|
+
.iteration = 1 |
|
|
721
|
+
.active = true
|
|
722
|
+
' 2>/dev/null)
|
|
723
|
+
|
|
724
|
+
if [[ -n "$updated_state" ]]; then
|
|
725
|
+
echo "$updated_state" > "$ralph_loop_file"
|
|
726
|
+
fi
|
|
628
727
|
else
|
|
629
|
-
|
|
728
|
+
log_verbose "Ralph state preserved at iteration $current_iteration"
|
|
630
729
|
fi
|
|
631
730
|
}
|
|
632
731
|
|
|
633
|
-
|
|
732
|
+
get_current_task_context() {
|
|
634
733
|
local change_dir="$1"
|
|
635
|
-
local
|
|
636
|
-
local complete="$3"
|
|
734
|
+
local tasks_file="$change_dir/tasks.md"
|
|
637
735
|
|
|
638
|
-
|
|
736
|
+
if [[ ! -f "$tasks_file" ]]; then
|
|
737
|
+
echo ""
|
|
738
|
+
return
|
|
739
|
+
fi
|
|
639
740
|
|
|
640
|
-
|
|
641
|
-
local temp_file=$(mktemp)
|
|
741
|
+
log_verbose "Reading current task context from tasks.md..."
|
|
642
742
|
|
|
743
|
+
local context=""
|
|
744
|
+
local found_task=false
|
|
745
|
+
local all_completed_tasks=""
|
|
746
|
+
local current_task_desc=""
|
|
747
|
+
|
|
748
|
+
while IFS= read -r line; do
|
|
749
|
+
if [[ "$line" =~ ^-\ \[/\] ]]; then
|
|
750
|
+
# Found in-progress task - extract description
|
|
751
|
+
current_task_desc="${line#- [/] }"
|
|
752
|
+
found_task=true
|
|
753
|
+
break
|
|
754
|
+
elif [[ "$line" =~ ^-\ \[\ \] ]] && [[ "$found_task" == "false" ]]; then
|
|
755
|
+
# Found incomplete task - extract description
|
|
756
|
+
current_task_desc="${line#- [ ] }"
|
|
757
|
+
found_task=true
|
|
758
|
+
break
|
|
759
|
+
fi
|
|
760
|
+
done < "$tasks_file"
|
|
761
|
+
|
|
762
|
+
# Also collect all completed tasks for commit message
|
|
643
763
|
local line_number=0
|
|
644
764
|
while IFS= read -r line; do
|
|
645
765
|
((line_number++)) || true
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
echo "${line/- \[ \]/- [x]}" >> "$temp_file"
|
|
650
|
-
else
|
|
651
|
-
echo "${line/- \[x\]/- [ ]}" >> "$temp_file"
|
|
652
|
-
fi
|
|
653
|
-
else
|
|
654
|
-
echo "$line" >> "$temp_file"
|
|
766
|
+
if [[ "$line" =~ ^-\ \[x\] ]]; then
|
|
767
|
+
# Use the full line as-is to preserve task number and description
|
|
768
|
+
all_completed_tasks+="$line"$'\n'
|
|
655
769
|
fi
|
|
656
770
|
done < "$tasks_file"
|
|
657
771
|
|
|
658
|
-
|
|
772
|
+
if [[ "$found_task" == "true" ]]; then
|
|
773
|
+
context="## Current Task"$'\n'
|
|
774
|
+
context+="- $current_task_desc"$'\n'
|
|
775
|
+
fi
|
|
776
|
+
|
|
777
|
+
if [[ -n "$all_completed_tasks" ]]; then
|
|
778
|
+
context+="## Completed Tasks for Git Commit"$'\n'
|
|
779
|
+
context+="$all_completed_tasks"
|
|
780
|
+
fi
|
|
781
|
+
|
|
782
|
+
echo "$context"
|
|
659
783
|
}
|
|
660
784
|
|
|
661
|
-
|
|
662
|
-
local
|
|
663
|
-
local task_id="$2"
|
|
664
|
-
local complete="$3"
|
|
785
|
+
setup_output_capture() {
|
|
786
|
+
local ralph_dir="$1"
|
|
665
787
|
|
|
666
|
-
log_verbose "
|
|
788
|
+
log_verbose "Setting up output capture..."
|
|
667
789
|
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
fi
|
|
790
|
+
# Create timestamped output directory in /tmp
|
|
791
|
+
local timestamp=$(date +"%Y%m%d_%H%M%S")
|
|
792
|
+
local output_dir="/tmp/ralph-run-$timestamp"
|
|
672
793
|
|
|
673
|
-
|
|
674
|
-
|
|
794
|
+
mkdir -p "$output_dir"
|
|
795
|
+
log_info "Output directory: $output_dir"
|
|
675
796
|
|
|
676
|
-
|
|
677
|
-
|
|
797
|
+
# Store output directory path in Ralph directory for reference
|
|
798
|
+
echo "$output_dir" > "$ralph_dir/.output_dir"
|
|
678
799
|
|
|
679
|
-
echo "$
|
|
800
|
+
echo "$output_dir"
|
|
680
801
|
}
|
|
681
802
|
|
|
682
|
-
|
|
803
|
+
cleanup_old_output() {
|
|
804
|
+
log_verbose "Cleaning up old Ralph output directories..."
|
|
805
|
+
|
|
806
|
+
# Keep last 3 Ralph output directories, delete older ones
|
|
807
|
+
find /tmp -type d -name "ralph-run-*" -mtime +7d 2>/dev/null | while read old_dir; do
|
|
808
|
+
log_verbose "Removing old output directory: $old_dir"
|
|
809
|
+
rm -rf "$old_dir"
|
|
810
|
+
done
|
|
811
|
+
}
|
|
812
|
+
|
|
813
|
+
execute_ralph_loop() {
|
|
683
814
|
local change_dir="$1"
|
|
684
|
-
local
|
|
685
|
-
local
|
|
686
|
-
local tracking_file="$4"
|
|
815
|
+
local ralph_dir="$2"
|
|
816
|
+
local max_iterations="${3:-50}"
|
|
687
817
|
|
|
688
|
-
|
|
818
|
+
log_info "Starting Ralph Wiggum loop with open-ralph-wiggum..."
|
|
819
|
+
log_info "Max iterations: $max_iterations"
|
|
820
|
+
log_info "Change directory: $change_dir"
|
|
689
821
|
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
822
|
+
if ! command -v ralph &> /dev/null; then
|
|
823
|
+
log_error "ralph CLI not found."
|
|
824
|
+
log_error "Please install open-ralph-wiggum: npm install -g @th0rgal/ralph-wiggum"
|
|
825
|
+
return 1
|
|
826
|
+
fi
|
|
693
827
|
|
|
694
|
-
|
|
695
|
-
cp "$tracking_file" "$tracking_backup"
|
|
828
|
+
local template_file="$ralph_dir/prompt-template.md"
|
|
696
829
|
|
|
697
|
-
|
|
698
|
-
|
|
830
|
+
# Clean up old output directories and setup new one
|
|
831
|
+
cleanup_old_output
|
|
832
|
+
local output_dir=$(setup_output_capture "$ralph_dir")
|
|
699
833
|
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
834
|
+
sync_tasks_to_ralph "$change_dir" "$ralph_dir"
|
|
835
|
+
create_prompt_template "$change_dir" "$template_file"
|
|
836
|
+
|
|
837
|
+
# Generate PRD and write to file
|
|
838
|
+
local prd_content
|
|
839
|
+
prd_content=$(generate_prd "$change_dir")
|
|
840
|
+
echo "$prd_content" > "$ralph_dir/PRD.md"
|
|
841
|
+
|
|
842
|
+
# Get current task context for Ralph to use in commits
|
|
843
|
+
local task_context
|
|
844
|
+
task_context=$(get_current_task_context "$change_dir")
|
|
845
|
+
|
|
846
|
+
# Create context injection file for Ralph
|
|
847
|
+
local context_file="$ralph_dir/.context_injection"
|
|
848
|
+
if [[ -n "$task_context" ]]; then
|
|
849
|
+
log_verbose "Writing task context injection..."
|
|
850
|
+
echo "$task_context" > "$context_file"
|
|
705
851
|
fi
|
|
706
852
|
|
|
707
|
-
|
|
708
|
-
|
|
853
|
+
# Restore Ralph state from tasks.md before running
|
|
854
|
+
restore_ralph_state_from_tasks "$change_dir/tasks.md"
|
|
709
855
|
|
|
710
|
-
|
|
711
|
-
|
|
856
|
+
# Initialize context injections file for Ralph to read context
|
|
857
|
+
initialize_context_injections "$ralph_dir"
|
|
858
|
+
|
|
859
|
+
# Output files
|
|
860
|
+
local stdout_log="$output_dir/ralph-stdout.log"
|
|
861
|
+
local stderr_log="$output_dir/ralph-stderr.log"
|
|
862
|
+
|
|
863
|
+
log_info "Delegating to ralph CLI..."
|
|
864
|
+
log_info "Capturing output to: $output_dir"
|
|
865
|
+
|
|
866
|
+
# Run Ralph and capture output to both console and files
|
|
867
|
+
{
|
|
868
|
+
ralph --prompt-file "$ralph_dir/PRD.md" \
|
|
869
|
+
--agent opencode \
|
|
870
|
+
--tasks \
|
|
871
|
+
--max-iterations "$max_iterations" \
|
|
872
|
+
--prompt-template "$template_file" \
|
|
873
|
+
--verbose-tools
|
|
874
|
+
} > >(tee "$stdout_log") 2> >(tee "$stderr_log")
|
|
875
|
+
|
|
876
|
+
return $?
|
|
712
877
|
}
|
|
713
878
|
|
|
879
|
+
|
|
880
|
+
|
|
714
881
|
main() {
|
|
715
882
|
parse_arguments "$@"
|
|
716
|
-
|
|
883
|
+
|
|
717
884
|
log_verbose "Starting ralph-run v$VERSION"
|
|
718
885
|
log_verbose "Change name: ${CHANGE_NAME:-<auto-detect>}"
|
|
719
|
-
|
|
886
|
+
|
|
720
887
|
validate_git_repository
|
|
721
888
|
validate_dependencies
|
|
722
889
|
|
|
@@ -729,7 +896,6 @@ main() {
|
|
|
729
896
|
validate_openspec_artifacts "$change_dir"
|
|
730
897
|
validate_script_state "$change_dir"
|
|
731
898
|
local ralph_dir=$(setup_ralph_directory "$change_dir")
|
|
732
|
-
local tracking_file=$(initialize_tracking "$ralph_dir")
|
|
733
899
|
|
|
734
900
|
log_info "Change directory: $change_dir"
|
|
735
901
|
log_info "Ralph directory: $ralph_dir"
|
|
@@ -743,7 +909,9 @@ main() {
|
|
|
743
909
|
log_info "PRD generation complete"
|
|
744
910
|
log_info "Found ${#TASKS[@]} tasks to execute"
|
|
745
911
|
|
|
746
|
-
|
|
912
|
+
local max_iterations="${MAX_ITERATIONS:-50}"
|
|
913
|
+
|
|
914
|
+
execute_ralph_loop "$change_dir" "$ralph_dir" "$max_iterations"
|
|
747
915
|
|
|
748
916
|
log_info "ralph-run.sh initialized successfully"
|
|
749
917
|
}
|