spec-and-loop 1.0.0 → 1.0.1
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-run.sh +217 -108
- package/scripts/setup.js +2 -2
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.1",
|
|
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/",
|
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)
|
|
41
|
-
-
|
|
42
|
-
-
|
|
76
|
+
- ralph CLI installed (npm install -g @th0rgal/ralph-wiggum)
|
|
77
|
+
- opencode CLI installed (npm install -g opencode-ai)
|
|
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,25 +140,23 @@ 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."
|
|
108
|
-
log_error "Please install opencode: npm install -g opencode"
|
|
155
|
+
log_error "Please install opencode: npm install -g opencode-ai"
|
|
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
|
|
|
@@ -473,22 +510,13 @@ get_git_history() {
|
|
|
473
510
|
gather_opencode_context() {
|
|
474
511
|
local task_description="$1"
|
|
475
512
|
|
|
476
|
-
log_verbose "Gathering opencode context..."
|
|
513
|
+
log_verbose "Gathering minimal opencode context..."
|
|
477
514
|
|
|
478
515
|
local context=""
|
|
479
516
|
|
|
480
517
|
context+="## Task"$'\n'
|
|
481
518
|
context+="$task_description"$'\n'$'\n'
|
|
482
519
|
|
|
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
520
|
echo "$context"
|
|
493
521
|
}
|
|
494
522
|
|
|
@@ -496,112 +524,191 @@ generate_opencode_prompt() {
|
|
|
496
524
|
local task_description="$1"
|
|
497
525
|
local ralph_dir="$2"
|
|
498
526
|
|
|
499
|
-
log_verbose "Generating opencode prompt..."
|
|
527
|
+
log_verbose "Generating minimal opencode prompt..."
|
|
500
528
|
|
|
501
529
|
local context
|
|
502
530
|
context=$(gather_opencode_context "$task_description")
|
|
503
531
|
|
|
504
532
|
local prompt=""
|
|
505
|
-
prompt+="
|
|
533
|
+
prompt+="Implement this task:"$'\n'
|
|
506
534
|
prompt+="$context"$'\n'
|
|
507
535
|
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
done
|
|
515
|
-
fi
|
|
516
|
-
prompt+=$'\n'
|
|
536
|
+
echo "$prompt"
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
sync_tasks_to_ralph() {
|
|
540
|
+
local change_dir="$1"
|
|
541
|
+
local ralph_dir="$2"
|
|
517
542
|
|
|
518
|
-
|
|
519
|
-
local
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
543
|
+
local tasks_file="$change_dir/tasks.md"
|
|
544
|
+
local ralph_tasks_file=".ralph/ralph-tasks.md"
|
|
545
|
+
local old_ralph_tasks_file="$change_dir/.ralph/ralph-tasks.md"
|
|
546
|
+
|
|
547
|
+
if [[ ! -f "$tasks_file" ]]; then
|
|
548
|
+
log_error "Tasks file not found: $tasks_file"
|
|
549
|
+
return 1
|
|
524
550
|
fi
|
|
525
|
-
prompt+=$'\n'
|
|
526
551
|
|
|
527
|
-
|
|
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'
|
|
552
|
+
local abs_tasks_file=$(realpath "$tasks_file" 2>/dev/null)
|
|
530
553
|
|
|
531
|
-
|
|
532
|
-
if
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
prompt+="$injected_context"$'\n'
|
|
554
|
+
# Clean up old Ralph tasks file in change directory if exists
|
|
555
|
+
if [[ -f "$old_ralph_tasks_file" ]]; then
|
|
556
|
+
log_verbose "Removing old Ralph tasks file from change directory: $old_ralph_tasks_file"
|
|
557
|
+
rm "$old_ralph_tasks_file"
|
|
536
558
|
fi
|
|
537
559
|
|
|
538
|
-
|
|
560
|
+
# Use symlink so Ralph and openspec-apply-change work on the SAME file
|
|
561
|
+
if [[ -L "$ralph_tasks_file" ]]; then
|
|
562
|
+
log_verbose "Symlink exists, ensuring it points to correct location"
|
|
563
|
+
local current_target=$(readlink -f "$ralph_tasks_file" 2>/dev/null || echo "")
|
|
564
|
+
|
|
565
|
+
if [[ "$current_target" != "$abs_tasks_file" ]]; then
|
|
566
|
+
log_verbose "Updating symlink to point to new change directory"
|
|
567
|
+
ln -sf "$abs_tasks_file" "$ralph_tasks_file"
|
|
568
|
+
fi
|
|
569
|
+
elif [[ -f "$ralph_tasks_file" ]]; then
|
|
570
|
+
# File exists but is not a symlink - replace with symlink
|
|
571
|
+
log_verbose "Replacing regular file with symlink to openspec tasks..."
|
|
572
|
+
rm "$ralph_tasks_file"
|
|
573
|
+
ln -sf "$abs_tasks_file" "$ralph_tasks_file"
|
|
574
|
+
else
|
|
575
|
+
# No file exists - create new symlink
|
|
576
|
+
log_verbose "Creating symlink from .ralph/ralph-tasks.md to openspec tasks..."
|
|
577
|
+
ln -sf "$abs_tasks_file" "$ralph_tasks_file"
|
|
578
|
+
fi
|
|
579
|
+
|
|
580
|
+
log_verbose "Symlink configured: $ralph_tasks_file -> $abs_tasks_file"
|
|
539
581
|
}
|
|
540
582
|
|
|
541
|
-
|
|
542
|
-
local
|
|
583
|
+
create_prompt_template() {
|
|
584
|
+
local change_dir="$1"
|
|
585
|
+
local template_file="$2"
|
|
543
586
|
|
|
544
|
-
log_verbose "
|
|
587
|
+
log_verbose "Creating custom prompt template..."
|
|
545
588
|
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
return 1
|
|
549
|
-
fi
|
|
589
|
+
local abs_change_dir
|
|
590
|
+
abs_change_dir=$(realpath "$change_dir" 2>/dev/null)
|
|
550
591
|
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
592
|
+
cat > "$template_file" << 'EOF'
|
|
593
|
+
# Ralph Wiggum Task Execution - Iteration {{iteration}} / {{max_iterations}}
|
|
594
|
+
|
|
595
|
+
Change directory: {{change_dir}}
|
|
596
|
+
|
|
597
|
+
## OpenSpec Artifacts Context
|
|
598
|
+
|
|
599
|
+
Include full context from openspec artifacts in {{change_dir}}:
|
|
600
|
+
- Read {{change_dir}}/proposal.md for the overall project goal
|
|
601
|
+
- Read {{change_dir}}/design.md for the technical design approach
|
|
602
|
+
- Read {{change_dir}}/specs/*/spec.md for the detailed specifications
|
|
603
|
+
|
|
604
|
+
## Task List
|
|
605
|
+
|
|
606
|
+
{{tasks}}
|
|
607
|
+
|
|
608
|
+
## Instructions
|
|
609
|
+
|
|
610
|
+
1. **Identify** current task:
|
|
611
|
+
- Find any task marked as [/] (in progress)
|
|
612
|
+
- If no task is in progress, pick the first task marked as [ ] (incomplete)
|
|
613
|
+
- Mark the task as [/] in the tasks file before starting work
|
|
614
|
+
|
|
615
|
+
2. **Implement** task using openspec-apply-change:
|
|
616
|
+
- Use the /opsx-apply skill to implement the current task
|
|
617
|
+
- Read the relevant openspec artifacts for context (proposal.md, design.md, specs)
|
|
618
|
+
- Follow the openspec workflow to complete the task
|
|
619
|
+
- The openspec-apply-change skill will implement changes and update task status automatically
|
|
620
|
+
|
|
621
|
+
3. **Complete** task:
|
|
622
|
+
- Verify that the implementation meets the requirements
|
|
623
|
+
- When the task is successfully completed, mark it as [x] in the tasks file
|
|
624
|
+
- Output: `<promise>{{task_promise}}</promise>`
|
|
625
|
+
|
|
626
|
+
4. **Continue** to the next task:
|
|
627
|
+
- The loop will continue with the next iteration
|
|
628
|
+
- Find the next incomplete task and repeat the process
|
|
629
|
+
|
|
630
|
+
## Critical Rules
|
|
631
|
+
|
|
632
|
+
- Work on ONE task at a time from the task list
|
|
633
|
+
- Use openspec-apply-change (/opsx-apply) for implementation
|
|
634
|
+
- ONLY output `<promise>{{task_promise}}</promise>` when the current task is complete and marked as [x]
|
|
635
|
+
- ONLY output `<promise>{{completion_promise}}</promise>` when ALL tasks are [x]
|
|
636
|
+
- Output promise tags DIRECTLY - do not quote them, explain them, or say you "will" output them
|
|
637
|
+
- Do NOT lie or output false promises to exit the loop
|
|
638
|
+
- If stuck, try a different approach
|
|
639
|
+
- Check your work before claiming completion
|
|
640
|
+
|
|
641
|
+
{{context}}
|
|
642
|
+
EOF
|
|
643
|
+
|
|
644
|
+
sed -i "s|{{change_dir}}|$abs_change_dir|g" "$template_file"
|
|
554
645
|
|
|
555
|
-
|
|
556
|
-
return $exit_code
|
|
646
|
+
log_verbose "Prompt template created: $template_file"
|
|
557
647
|
}
|
|
558
648
|
|
|
559
|
-
|
|
560
|
-
local
|
|
649
|
+
restore_ralph_state_from_tasks() {
|
|
650
|
+
local tasks_file="$1"
|
|
651
|
+
local ralph_loop_file=".ralph/ralph-loop.state.json"
|
|
561
652
|
|
|
562
|
-
|
|
653
|
+
if [[ ! -f "$ralph_loop_file" ]]; then
|
|
654
|
+
log_verbose "No Ralph state file found, nothing to restore"
|
|
655
|
+
return 0
|
|
656
|
+
fi
|
|
563
657
|
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
658
|
+
# Count completed tasks in tasks.md
|
|
659
|
+
local completed_count=$(grep -c "^- \[x\]" "$tasks_file" 2>/dev/null || echo "0")
|
|
660
|
+
local next_iteration=$((completed_count + 1))
|
|
661
|
+
log_verbose "Found $completed_count completed tasks in tasks.md, setting iteration to $next_iteration"
|
|
662
|
+
|
|
663
|
+
# Update Ralph state to resume from completed task
|
|
664
|
+
local updated_state
|
|
665
|
+
updated_state=$(jq --argjson state "$(cat "$ralph_loop_file")" --arg iter "$next_iteration" '
|
|
666
|
+
.iteration = $iter |
|
|
667
|
+
.active = true
|
|
668
|
+
' 2>/dev/null)
|
|
669
|
+
|
|
670
|
+
if [[ -n "$updated_state" ]]; then
|
|
671
|
+
log_verbose "Updated Ralph state: iteration set to $next_iteration"
|
|
672
|
+
echo "$updated_state" > "$ralph_loop_file"
|
|
570
673
|
fi
|
|
571
674
|
}
|
|
572
675
|
|
|
573
|
-
|
|
574
|
-
local
|
|
676
|
+
execute_ralph_loop() {
|
|
677
|
+
local change_dir="$1"
|
|
678
|
+
local ralph_dir="$2"
|
|
679
|
+
local tasks_file="$change_dir/tasks.md"
|
|
680
|
+
local max_iterations="${3:-50}"
|
|
575
681
|
|
|
576
|
-
log_info "Starting
|
|
682
|
+
log_info "Starting Ralph Wiggum loop with open-ralph-wiggum..."
|
|
683
|
+
log_info "Max iterations: $max_iterations"
|
|
684
|
+
log_info "Change directory: $change_dir"
|
|
577
685
|
|
|
578
|
-
|
|
579
|
-
|
|
686
|
+
if ! command -v ralph &> /dev/null; then
|
|
687
|
+
log_error "ralph CLI not found."
|
|
688
|
+
log_error "Please install open-ralph-wiggum: npm install -g @th0rgal/ralph-wiggum"
|
|
689
|
+
return 1
|
|
690
|
+
fi
|
|
580
691
|
|
|
581
|
-
|
|
582
|
-
local task_description="${TASKS[$i]}"
|
|
583
|
-
local task_id="${TASK_IDS[$i]}"
|
|
584
|
-
|
|
585
|
-
log_info "Executing task $((i+1))/$total_tasks: $task_description"
|
|
586
|
-
|
|
587
|
-
local prompt
|
|
588
|
-
prompt=$(generate_opencode_prompt "$task_description" "$ralph_dir")
|
|
589
|
-
|
|
590
|
-
local output
|
|
591
|
-
output=$(execute_opencode "$prompt")
|
|
592
|
-
local exit_code=$?
|
|
593
|
-
|
|
594
|
-
if [[ $exit_code -eq 0 ]]; then
|
|
595
|
-
log_info "Task completed successfully"
|
|
596
|
-
create_git_commit "$task_description"
|
|
597
|
-
else
|
|
598
|
-
log_error "Task failed with exit code: $exit_code"
|
|
599
|
-
log_error "Output: $output"
|
|
600
|
-
break
|
|
601
|
-
fi
|
|
602
|
-
done
|
|
692
|
+
local template_file="$ralph_dir/prompt-template.md"
|
|
603
693
|
|
|
604
|
-
|
|
694
|
+
sync_tasks_to_ralph "$change_dir" "$ralph_dir"
|
|
695
|
+
create_prompt_template "$change_dir" "$template_file"
|
|
696
|
+
|
|
697
|
+
local prd_content
|
|
698
|
+
prd_content=$(generate_prd "$change_dir")
|
|
699
|
+
|
|
700
|
+
# Restore Ralph state from tasks.md before running
|
|
701
|
+
restore_ralph_state_from_tasks "$tasks_file"
|
|
702
|
+
|
|
703
|
+
log_info "Delegating to ralph CLI..."
|
|
704
|
+
ralph "$prd_content" \
|
|
705
|
+
--agent opencode \
|
|
706
|
+
--tasks \
|
|
707
|
+
--max-iterations "$max_iterations" \
|
|
708
|
+
--prompt-template "$template_file" \
|
|
709
|
+
--verbose-tools
|
|
710
|
+
|
|
711
|
+
return $?
|
|
605
712
|
}
|
|
606
713
|
|
|
607
714
|
initialize_tracking() {
|
|
@@ -743,7 +850,9 @@ main() {
|
|
|
743
850
|
log_info "PRD generation complete"
|
|
744
851
|
log_info "Found ${#TASKS[@]} tasks to execute"
|
|
745
852
|
|
|
746
|
-
|
|
853
|
+
local max_iterations="${MAX_ITERATIONS:-50}"
|
|
854
|
+
|
|
855
|
+
execute_ralph_loop "$change_dir" "$ralph_dir" "$max_iterations"
|
|
747
856
|
|
|
748
857
|
log_info "ralph-run.sh initialized successfully"
|
|
749
858
|
}
|
package/scripts/setup.js
CHANGED
|
@@ -37,7 +37,7 @@ console.log(' ralph-run --change <name> # Run ralph loop');
|
|
|
37
37
|
console.log(' ralph-run # Auto-detect change');
|
|
38
38
|
console.log('');
|
|
39
39
|
console.log('Prerequisites:');
|
|
40
|
-
console.log(' - openspec CLI: npm install -g openspec');
|
|
41
|
-
console.log(' - opencode CLI: npm install -g opencode');
|
|
40
|
+
console.log(' - openspec CLI: npm install -g @fission-ai/openspec@latest');
|
|
41
|
+
console.log(' - opencode CLI: npm install -g opencode-ai (or see https://opencode.ai/install)');
|
|
42
42
|
console.log(' - jq CLI: apt install jq / brew install jq');
|
|
43
43
|
console.log(' - git: git init');
|