spec-and-loop 2.0.0 → 2.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 +233 -32
- package/README.md +129 -41
- package/lib/mini-ralph/errors.js +70 -0
- package/lib/mini-ralph/index.js +2 -0
- package/lib/mini-ralph/invoker.js +1 -0
- package/lib/mini-ralph/runner.js +74 -3
- package/lib/mini-ralph/status.js +14 -0
- package/package.json +3 -2
- package/scripts/ralph-run.sh +4 -0
package/QUICKSTART.md
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# Quick Start Guide
|
|
2
2
|
|
|
3
|
+
> **Version Compatibility:** OpenSpec 1.2.0 | spec-and-loop 2.0.0
|
|
4
|
+
|
|
3
5
|
Get up and running with **spec-and-loop** in 5 minutes!
|
|
4
6
|
|
|
5
7
|
## Prerequisites
|
|
@@ -7,8 +9,8 @@ Get up and running with **spec-and-loop** in 5 minutes!
|
|
|
7
9
|
Install these tools (one-time setup):
|
|
8
10
|
|
|
9
11
|
```bash
|
|
10
|
-
# 1. Install openspec (OpenSpec CLI)
|
|
11
|
-
npm install -g @fission-ai/openspec@
|
|
12
|
+
# 1. Install openspec (OpenSpec CLI) - pinned to version 1.2.0
|
|
13
|
+
npm install -g @fission-ai/openspec@1.2.0
|
|
12
14
|
|
|
13
15
|
# 2. Install opencode (agentic coding assistant)
|
|
14
16
|
npm install -g opencode-ai
|
|
@@ -24,7 +26,8 @@ brew install jq
|
|
|
24
26
|
git init
|
|
25
27
|
```
|
|
26
28
|
|
|
27
|
-
> **Note:**
|
|
29
|
+
> **Note:** This guide is for OpenSpec 1.2.0 and spec-and-loop 2.0.0.
|
|
30
|
+
> No external `ralph` CLI needed — `spec-and-loop` includes its own internal
|
|
28
31
|
> mini Ralph loop engine. Just install `opencode` and you're ready to go. The
|
|
29
32
|
> runtime prompt is self-contained and does not depend on editor-specific slash
|
|
30
33
|
> commands or local-only skills.
|
|
@@ -32,7 +35,7 @@ git init
|
|
|
32
35
|
## Installation
|
|
33
36
|
|
|
34
37
|
```bash
|
|
35
|
-
npm install -g spec-and-loop
|
|
38
|
+
npm install -g spec-and-loop@2.0.0
|
|
36
39
|
```
|
|
37
40
|
|
|
38
41
|
## Quick Demo (5 Minutes)
|
|
@@ -47,10 +50,13 @@ git init
|
|
|
47
50
|
openspec init
|
|
48
51
|
|
|
49
52
|
# 3. Create a new change
|
|
50
|
-
openspec new add-hello-world
|
|
53
|
+
openspec new change add-hello-world
|
|
51
54
|
|
|
52
|
-
# 4.
|
|
53
|
-
openspec
|
|
55
|
+
# 4. Review and complete the OpenSpec artifacts
|
|
56
|
+
# (openspec/changes/add-hello-world/proposal.md)
|
|
57
|
+
# (openspec/changes/add-hello-world/design.md)
|
|
58
|
+
# (openspec/changes/add-hello-world/specs/*/spec.md)
|
|
59
|
+
# (openspec/changes/add-hello-world/tasks.md)
|
|
54
60
|
|
|
55
61
|
# 5. Run the ralph loop (executes tasks with opencode)
|
|
56
62
|
ralph-run --change add-hello-world
|
|
@@ -101,12 +107,27 @@ ralph-run --status
|
|
|
101
107
|
### OpenSpec Commands
|
|
102
108
|
|
|
103
109
|
```bash
|
|
104
|
-
|
|
105
|
-
openspec
|
|
106
|
-
openspec
|
|
107
|
-
openspec
|
|
108
|
-
openspec
|
|
109
|
-
|
|
110
|
+
# Core workflow
|
|
111
|
+
openspec init # Initialize OpenSpec in current directory
|
|
112
|
+
openspec new change <name> # Create a new change directory
|
|
113
|
+
openspec show <item-name> # Show a change or spec in detail
|
|
114
|
+
openspec archive <change-name> # Archive a completed change
|
|
115
|
+
|
|
116
|
+
# Information and status
|
|
117
|
+
openspec list # List all active changes (use --specs to list specs)
|
|
118
|
+
openspec status --change <name> # Display artifact completion status for a change
|
|
119
|
+
openspec validate <item-name> # Validate changes and specs
|
|
120
|
+
|
|
121
|
+
# View and manage
|
|
122
|
+
openspec view # Display interactive dashboard of specs and changes
|
|
123
|
+
openspec update # Update OpenSpec instruction files
|
|
124
|
+
openspec config # View and modify global OpenSpec configuration
|
|
125
|
+
|
|
126
|
+
# Advanced
|
|
127
|
+
openspec spec # Manage and view OpenSpec specifications
|
|
128
|
+
openspec instructions # Output enriched instructions for creating artifacts
|
|
129
|
+
openspec templates # Show resolved template paths for artifacts
|
|
130
|
+
openspec schemas # List available workflow schemas
|
|
110
131
|
```
|
|
111
132
|
|
|
112
133
|
### Ralph Loop Commands
|
|
@@ -133,7 +154,7 @@ git init
|
|
|
133
154
|
openspec init
|
|
134
155
|
|
|
135
156
|
# 2. Create a feature
|
|
136
|
-
openspec new user-authentication
|
|
157
|
+
openspec new change user-authentication
|
|
137
158
|
|
|
138
159
|
# 3. Go through the workflow
|
|
139
160
|
# - Create proposal: Why add auth?
|
|
@@ -141,77 +162,257 @@ openspec new user-authentication
|
|
|
141
162
|
# - Create design: Use JWT, store hashed passwords
|
|
142
163
|
# - Create tasks: 15 checkboxes for implementation
|
|
143
164
|
|
|
144
|
-
# 4.
|
|
145
|
-
openspec ff user-authentication
|
|
146
|
-
|
|
147
|
-
# 5. Execute the implementation
|
|
165
|
+
# 4. Execute the implementation
|
|
148
166
|
ralph-run --change user-authentication
|
|
149
167
|
|
|
150
|
-
#
|
|
168
|
+
# 5. Watch the magic happen!
|
|
151
169
|
# [INFO] Found 15 tasks to execute
|
|
152
170
|
# [INFO] Executing task 1/15: Create User model
|
|
153
171
|
# [INFO] Executing task 2/15: Implement password hashing
|
|
154
172
|
# ...
|
|
155
173
|
|
|
156
|
-
#
|
|
174
|
+
# 6. Add context mid-run if needed (from another terminal)
|
|
157
175
|
ralph-run --add-context "Prefer bcrypt over argon2 for password hashing"
|
|
158
176
|
|
|
159
|
-
#
|
|
177
|
+
# 7. Check status
|
|
160
178
|
ralph-run --status
|
|
161
179
|
|
|
162
|
-
#
|
|
180
|
+
# 8. Verify the implementation
|
|
163
181
|
git log --oneline # 15 commits, one per task
|
|
164
182
|
git diff HEAD~15 # See full implementation
|
|
165
183
|
```
|
|
166
184
|
|
|
167
185
|
## Troubleshooting
|
|
168
186
|
|
|
169
|
-
### "openspec
|
|
187
|
+
### "openspec: command not found"
|
|
188
|
+
|
|
189
|
+
**Problem:** OpenSpec CLI is not installed or not in PATH
|
|
190
|
+
|
|
191
|
+
**Solution:**
|
|
192
|
+
```bash
|
|
193
|
+
# Install with pinned version (recommended)
|
|
194
|
+
npm install -g @fission-ai/openspec@1.2.0
|
|
195
|
+
|
|
196
|
+
# Verify installation
|
|
197
|
+
openspec --version
|
|
198
|
+
|
|
199
|
+
# If command still not found, add npm global bin to PATH
|
|
200
|
+
export PATH="$PATH:$(npm root -g)/.bin"
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
### "opencode: command not found"
|
|
170
204
|
|
|
205
|
+
**Problem:** opencode CLI is not installed or not in PATH
|
|
206
|
+
|
|
207
|
+
**Solution:**
|
|
171
208
|
```bash
|
|
172
|
-
|
|
209
|
+
# Install opencode
|
|
210
|
+
npm install -g opencode-ai
|
|
211
|
+
|
|
212
|
+
# Verify installation
|
|
213
|
+
opencode --version
|
|
214
|
+
|
|
215
|
+
# If command still not found, add npm global bin to PATH
|
|
216
|
+
export PATH="$PATH:$(npm root -g)/.bin"
|
|
173
217
|
```
|
|
174
218
|
|
|
175
219
|
### "jq CLI not found"
|
|
176
220
|
|
|
221
|
+
**Problem:** jq (JSON processor) is not installed
|
|
222
|
+
|
|
223
|
+
**Solution:**
|
|
177
224
|
```bash
|
|
178
225
|
# Ubuntu/Debian
|
|
179
226
|
sudo apt install jq
|
|
180
227
|
|
|
181
228
|
# macOS
|
|
182
229
|
brew install jq
|
|
230
|
+
|
|
231
|
+
# Verify installation
|
|
232
|
+
jq --version
|
|
183
233
|
```
|
|
184
234
|
|
|
185
235
|
### "Not a git repository"
|
|
186
236
|
|
|
237
|
+
**Problem:** You're not in a git repository
|
|
238
|
+
|
|
239
|
+
**Solution:**
|
|
187
240
|
```bash
|
|
241
|
+
# Initialize git in current directory
|
|
188
242
|
git init
|
|
243
|
+
|
|
244
|
+
# Verify
|
|
245
|
+
git status
|
|
189
246
|
```
|
|
190
247
|
|
|
191
248
|
### "command not found: ralph-run"
|
|
192
249
|
|
|
193
|
-
**Problem:** npm bin directory not in PATH
|
|
250
|
+
**Problem:** spec-and-loop npm bin directory not in PATH
|
|
194
251
|
|
|
195
252
|
**Solution:**
|
|
196
253
|
```bash
|
|
197
|
-
# Add
|
|
198
|
-
export PATH="$PATH:$(npm root -g)/.bin"
|
|
254
|
+
# Add npm global bin directory to PATH
|
|
255
|
+
echo 'export PATH="$PATH:$(npm root -g)/.bin"' >> ~/.bashrc
|
|
256
|
+
# Or for zsh:
|
|
257
|
+
echo 'export PATH="$PATH:$(npm root -g)/.bin"' >> ~/.zshrc
|
|
199
258
|
|
|
200
259
|
# Reload shell
|
|
201
260
|
source ~/.bashrc
|
|
261
|
+
# or
|
|
262
|
+
source ~/.zshrc
|
|
263
|
+
|
|
264
|
+
# Verify
|
|
265
|
+
ralph-run --help
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
### "Internal mini Ralph runtime not found"
|
|
269
|
+
|
|
270
|
+
**Problem:** spec-and-loop installation is incomplete or node is missing
|
|
271
|
+
|
|
272
|
+
**Solution:**
|
|
273
|
+
```bash
|
|
274
|
+
# Ensure spec-and-loop is properly installed
|
|
275
|
+
npm uninstall -g spec-and-loop
|
|
276
|
+
npm install -g spec-and-loop
|
|
277
|
+
|
|
278
|
+
# Ensure Node.js is installed (version 24.0.0 or higher)
|
|
279
|
+
node --version
|
|
280
|
+
|
|
281
|
+
# If node is not installed, install from https://nodejs.org
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
### "OpenSpec changes directory not found"
|
|
285
|
+
|
|
286
|
+
**Problem:** OpenSpec has not been initialized or no changes exist
|
|
287
|
+
|
|
288
|
+
**Solution:**
|
|
289
|
+
```bash
|
|
290
|
+
# Initialize OpenSpec
|
|
291
|
+
openspec init
|
|
292
|
+
|
|
293
|
+
# Create a new change
|
|
294
|
+
openspec new change my-feature
|
|
295
|
+
|
|
296
|
+
# Verify directory exists
|
|
297
|
+
ls -la openspec/changes/
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
### "No changes found with tasks.md"
|
|
301
|
+
|
|
302
|
+
**Problem:** No OpenSpec changes with tasks files exist
|
|
303
|
+
|
|
304
|
+
**Solution:**
|
|
305
|
+
```bash
|
|
306
|
+
# List available changes
|
|
307
|
+
openspec list
|
|
308
|
+
|
|
309
|
+
# Create a new change if needed
|
|
310
|
+
openspec new change my-new-feature
|
|
311
|
+
|
|
312
|
+
# Ensure tasks.md exists in your change directory
|
|
313
|
+
ls -la openspec/changes/my-new-feature/tasks.md
|
|
202
314
|
```
|
|
203
315
|
|
|
204
316
|
### "No tasks to execute"
|
|
205
317
|
|
|
206
|
-
**Problem:** All tasks
|
|
318
|
+
**Problem:** All tasks in tasks.md are already marked complete
|
|
319
|
+
|
|
320
|
+
**Solution:**
|
|
321
|
+
```bash
|
|
322
|
+
# Check tasks.md for incomplete tasks
|
|
323
|
+
grep "^\- \[ \]" openspec/changes/my-new-feature/tasks.md
|
|
324
|
+
|
|
325
|
+
# If no incomplete tasks, create a new change
|
|
326
|
+
openspec new change another-feature
|
|
327
|
+
|
|
328
|
+
# Or uncheck a task by editing tasks.md manually:
|
|
329
|
+
# Change: - [x] This task is done
|
|
330
|
+
# To: - [ ] This task needs work
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
### "Required artifact not found"
|
|
334
|
+
|
|
335
|
+
**Problem:** OpenSpec artifacts (proposal.md, design.md, tasks.md) are missing
|
|
207
336
|
|
|
208
337
|
**Solution:**
|
|
209
338
|
```bash
|
|
210
|
-
# Check
|
|
211
|
-
|
|
339
|
+
# Check what artifacts exist in your change directory
|
|
340
|
+
ls -la openspec/changes/my-new-feature/
|
|
341
|
+
|
|
342
|
+
# Create missing artifacts manually or use openspec new change
|
|
343
|
+
openspec new change my-new-feature
|
|
344
|
+
|
|
345
|
+
# Or manually create the required files:
|
|
346
|
+
# - openspec/changes/my-new-feature/proposal.md
|
|
347
|
+
# - openspec/changes/my-new-feature/design.md
|
|
348
|
+
# - openspec/changes/my-new-feature/specs/spec-name/spec.md
|
|
349
|
+
# - openspec/changes/my-new-feature/tasks.md
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+
### "Required directory not found: specs/"
|
|
353
|
+
|
|
354
|
+
**Problem:** The specs directory is missing from your change
|
|
355
|
+
|
|
356
|
+
**Solution:**
|
|
357
|
+
```bash
|
|
358
|
+
# Create the specs directory
|
|
359
|
+
mkdir -p openspec/changes/my-new-feature/specs
|
|
360
|
+
|
|
361
|
+
# Create at least one spec file
|
|
362
|
+
mkdir -p openspec/changes/my-new-feature/specs/main-feature
|
|
363
|
+
echo "# Main Feature Spec" > openspec/changes/my-new-feature/specs/main-feature/spec.md
|
|
364
|
+
|
|
365
|
+
# Verify
|
|
366
|
+
ls -la openspec/changes/my-new-feature/specs/
|
|
367
|
+
```
|
|
368
|
+
|
|
369
|
+
### "opencode CLI not found"
|
|
370
|
+
|
|
371
|
+
**Problem:** opencode is not installed globally
|
|
372
|
+
|
|
373
|
+
**Solution:**
|
|
374
|
+
```bash
|
|
375
|
+
# Install opencode
|
|
376
|
+
npm install -g opencode-ai
|
|
377
|
+
|
|
378
|
+
# Verify installation
|
|
379
|
+
opencode --version
|
|
380
|
+
|
|
381
|
+
# Add to PATH if needed
|
|
382
|
+
export PATH="$PATH:$(npm root -g)/.bin"
|
|
383
|
+
```
|
|
384
|
+
|
|
385
|
+
### "Node.js version too old"
|
|
386
|
+
|
|
387
|
+
**Problem:** Node.js version is below the required version (24.0.0+)
|
|
388
|
+
|
|
389
|
+
**Solution:**
|
|
390
|
+
```bash
|
|
391
|
+
# Check current Node.js version
|
|
392
|
+
node --version
|
|
393
|
+
|
|
394
|
+
# If version is below 24.0.0, upgrade Node.js:
|
|
395
|
+
# Using nvm (recommended):
|
|
396
|
+
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.0/install.sh | bash
|
|
397
|
+
nvm install 24
|
|
398
|
+
nvm use 24
|
|
399
|
+
|
|
400
|
+
# Or install from https://nodejs.org
|
|
401
|
+
```
|
|
402
|
+
|
|
403
|
+
### "npm: command not found"
|
|
404
|
+
|
|
405
|
+
**Problem:** npm is not installed or not in PATH
|
|
406
|
+
|
|
407
|
+
**Solution:**
|
|
408
|
+
```bash
|
|
409
|
+
# npm comes with Node.js. Install Node.js from https://nodejs.org
|
|
410
|
+
|
|
411
|
+
# After installing Node.js, verify:
|
|
412
|
+
npm --version
|
|
413
|
+
node --version
|
|
212
414
|
|
|
213
|
-
#
|
|
214
|
-
openspec new another-feature
|
|
415
|
+
# If still not found, restart your terminal or add to PATH
|
|
215
416
|
```
|
|
216
417
|
|
|
217
418
|
## Features at a Glance
|
package/README.md
CHANGED
|
@@ -4,7 +4,9 @@ OpenSpec + Ralph Loop integration for iterative development with opencode.
|
|
|
4
4
|
|
|
5
5
|

|
|
6
6
|

|
|
7
|
-
[](https://badge.fury.io/js/spec-and-loop)
|
|
7
|
+
[](https://badge.fury.io/js/spec-and-loop.svg)
|
|
8
|
+
|
|
9
|
+
**Version:** spec-and-loop 2.0.0 + OpenSpec 1.2.0
|
|
8
10
|
|
|
9
11
|
**[Quick Start Guide](./QUICKSTART.md)** - Get up and running in 5 minutes!
|
|
10
12
|
|
|
@@ -14,16 +16,18 @@ OpenSpec provides excellent structure for planning (proposal → specs → desig
|
|
|
14
16
|
|
|
15
17
|
The runtime prompt is self-contained: it does not depend on Cursor-only slash commands or editor-local skills.
|
|
16
18
|
|
|
19
|
+
**Version Requirements:** This documentation applies to OpenSpec 1.2.0 and spec-and-loop 2.0.0.
|
|
20
|
+
|
|
17
21
|
## Installation
|
|
18
22
|
|
|
19
23
|
```bash
|
|
20
|
-
npm install -g spec-and-loop
|
|
24
|
+
npm install -g spec-and-loop@2.0.0
|
|
21
25
|
```
|
|
22
26
|
|
|
23
27
|
**Prerequisites:** You need OpenSpec and the OpenCode AI agent installed:
|
|
24
28
|
|
|
25
29
|
```bash
|
|
26
|
-
npm install -g @fission-ai/openspec@
|
|
30
|
+
npm install -g @fission-ai/openspec@1.2.0 opencode-ai
|
|
27
31
|
```
|
|
28
32
|
|
|
29
33
|
Alternative OpenCode install methods:
|
|
@@ -43,10 +47,13 @@ brew install anomalyco/tap/opencode
|
|
|
43
47
|
openspec init
|
|
44
48
|
|
|
45
49
|
# 2. Create a new change
|
|
46
|
-
openspec new add-user-auth
|
|
50
|
+
openspec new change add-user-auth
|
|
47
51
|
|
|
48
|
-
# 3.
|
|
49
|
-
openspec
|
|
52
|
+
# 3. Review and complete the OpenSpec artifacts
|
|
53
|
+
# (openspec/changes/add-user-auth/proposal.md)
|
|
54
|
+
# (openspec/changes/add-user-auth/design.md)
|
|
55
|
+
# (openspec/changes/add-user-auth/specs/*/spec.md)
|
|
56
|
+
# (openspec/changes/add-user-auth/tasks.md)
|
|
50
57
|
|
|
51
58
|
# 4. Run the ralph loop (executes tasks with opencode)
|
|
52
59
|
ralph-run --change add-user-auth
|
|
@@ -56,6 +63,8 @@ For detailed step-by-step instructions, see [QUICKSTART.md](./QUICKSTART.md).
|
|
|
56
63
|
|
|
57
64
|
## Testing
|
|
58
65
|
|
|
66
|
+
*Testing suite for spec-and-loop 2.0.0*
|
|
67
|
+
|
|
59
68
|
Spec-and-loop includes a comprehensive test suite to ensure reliability and cross-platform compatibility.
|
|
60
69
|
|
|
61
70
|
**[Testing Guide](./TESTING.md)** - Detailed instructions for running tests
|
|
@@ -89,17 +98,19 @@ All tests are run automatically via GitHub Actions on every push and pull reques
|
|
|
89
98
|
|
|
90
99
|
## Prerequisites
|
|
91
100
|
|
|
101
|
+
*Required for spec-and-loop 2.0.0 with OpenSpec 1.2.0*
|
|
102
|
+
|
|
92
103
|
Before using spec-and-loop, ensure you have:
|
|
93
104
|
|
|
94
|
-
1. **Node.js** - For package installation
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
105
|
+
1. **Node.js** - For package installation (requires >=24.0.0)
|
|
106
|
+
```bash
|
|
107
|
+
node --version # Should be >=24.0.0
|
|
108
|
+
```
|
|
98
109
|
|
|
99
|
-
2. **openspec** - OpenSpec CLI for specification workflow
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
110
|
+
2. **openspec** - OpenSpec CLI for specification workflow (requires 1.2.0)
|
|
111
|
+
```bash
|
|
112
|
+
npm install -g @fission-ai/openspec@1.2.0
|
|
113
|
+
```
|
|
103
114
|
|
|
104
115
|
3. **opencode** - Agentic coding assistant
|
|
105
116
|
```bash
|
|
@@ -124,14 +135,13 @@ For complete installation instructions, see [QUICKSTART.md](./QUICKSTART.md).
|
|
|
124
135
|
|
|
125
136
|
## Commands
|
|
126
137
|
|
|
138
|
+
*Documentation applies to OpenSpec 1.2.0 and spec-and-loop 2.0.0*
|
|
139
|
+
|
|
127
140
|
### OpenSpec Commands
|
|
128
141
|
|
|
129
142
|
- `openspec init` - Initialize OpenSpec in current directory
|
|
130
|
-
- `openspec new <name>` -
|
|
131
|
-
- `openspec
|
|
132
|
-
- `openspec continue <name>` - Continue working on change
|
|
133
|
-
- `openspec apply <name>` - Apply change (implementation)
|
|
134
|
-
- `openspec archive <name>` - Archive a completed change
|
|
143
|
+
- `openspec new change <name>` - Create a new change with artifact templates
|
|
144
|
+
- `openspec --help` - View all available commands and their syntax
|
|
135
145
|
|
|
136
146
|
### Ralph Loop Commands
|
|
137
147
|
|
|
@@ -139,24 +149,26 @@ For complete installation instructions, see [QUICKSTART.md](./QUICKSTART.md).
|
|
|
139
149
|
ralph-run [OPTIONS]
|
|
140
150
|
|
|
141
151
|
OPTIONS:
|
|
142
|
-
--change <name> OpenSpec change to execute (default: auto-detect)
|
|
143
|
-
--max-iterations <n> Maximum iterations (default: 50)
|
|
144
|
-
--no-commit Suppress automatic git commits
|
|
145
|
-
--verbose, -v Enable verbose
|
|
152
|
+
--change <name> Specify the OpenSpec change to execute (default: auto-detect)
|
|
153
|
+
--max-iterations <n> Maximum iterations for Ralph loop (default: 50)
|
|
154
|
+
--no-commit Suppress automatic git commits during the loop
|
|
155
|
+
--verbose, -v Enable verbose mode for debugging
|
|
156
|
+
--help, -h Show this help message
|
|
146
157
|
|
|
147
158
|
OBSERVABILITY AND CONTROL:
|
|
148
|
-
--status Print loop status dashboard and exit
|
|
149
|
-
--add-context <text> Add context to inject into the next iteration
|
|
150
|
-
--clear-context Clear any pending context
|
|
159
|
+
--status Print the current loop status dashboard and exit
|
|
160
|
+
--add-context <text> Add pending context to inject into the next iteration and exit
|
|
161
|
+
--clear-context Clear any pending context and exit
|
|
151
162
|
```
|
|
152
163
|
|
|
153
164
|
## How It Works
|
|
154
165
|
|
|
166
|
+
*Workflow for OpenSpec 1.2.0 + spec-and-loop 2.0.0*
|
|
167
|
+
|
|
155
168
|
### Step 1: Create Spec with OpenSpec
|
|
156
169
|
|
|
157
170
|
```bash
|
|
158
|
-
openspec new my-feature
|
|
159
|
-
openspec ff my-feature
|
|
171
|
+
openspec new change my-feature
|
|
160
172
|
```
|
|
161
173
|
|
|
162
174
|
This creates:
|
|
@@ -165,6 +177,8 @@ This creates:
|
|
|
165
177
|
- **design.md**: Technical decisions and architecture
|
|
166
178
|
- **tasks.md**: Implementation tasks as checkboxes
|
|
167
179
|
|
|
180
|
+
After creating the change, manually complete the OpenSpec artifacts by filling in proposal.md, design.md, specs/*/spec.md, and tasks.md.
|
|
181
|
+
|
|
168
182
|
**Example tasks.md:**
|
|
169
183
|
```markdown
|
|
170
184
|
## Implementation
|
|
@@ -185,12 +199,16 @@ ralph-run --change my-feature
|
|
|
185
199
|
|
|
186
200
|
1. **Validation**: Checks for required OpenSpec artifacts and git repository
|
|
187
201
|
2. **PRD Generation**: Converts proposal + specs + design → PRD format for internal use
|
|
188
|
-
3. **
|
|
202
|
+
3. **Setup**: Creates .ralph directory, syncs tasks symlink, and sets up output capture
|
|
203
|
+
4. **Task Execution**: For each incomplete task:
|
|
189
204
|
- Generates context-rich prompt (full OpenSpec artifacts + a fresh task snapshot + recent loop signals)
|
|
190
205
|
- Runs `opencode` with the prompt via the internal mini Ralph engine
|
|
206
|
+
- Captures output to temp directory for review and debugging
|
|
207
|
+
- Logs any errors to `.ralph/errors.md` with timestamps
|
|
191
208
|
- Creates git commit with task description (unless `--no-commit`)
|
|
192
209
|
- Marks task complete in tasks.md
|
|
193
|
-
|
|
210
|
+
5. **Cleanup**: Automatically removes old output directories (older than 7 days)
|
|
211
|
+
6. **Completion**: All tasks done
|
|
194
212
|
|
|
195
213
|
### Step 3: Monitor Progress
|
|
196
214
|
|
|
@@ -210,12 +228,21 @@ ralph-run --add-context "Prefer async/await over callbacks"
|
|
|
210
228
|
|
|
211
229
|
## Example Workflow
|
|
212
230
|
|
|
231
|
+
*Example workflow for OpenSpec 1.2.0 and spec-and-loop 2.0.0*
|
|
232
|
+
|
|
213
233
|
```bash
|
|
214
|
-
# 1.
|
|
215
|
-
|
|
216
|
-
|
|
234
|
+
# 1. Initialize OpenSpec in your project
|
|
235
|
+
cd my-web-app
|
|
236
|
+
git init
|
|
237
|
+
openspec init
|
|
217
238
|
|
|
218
|
-
# 2.
|
|
239
|
+
# 2. Create a new change
|
|
240
|
+
openspec new change user-auth
|
|
241
|
+
|
|
242
|
+
# 3. Complete OpenSpec artifacts manually or use opencode skills
|
|
243
|
+
# (review and fill in proposal.md, design.md, specs/*/spec.md, tasks.md)
|
|
244
|
+
|
|
245
|
+
# 4. Execute with Ralph
|
|
219
246
|
ralph-run --change user-auth
|
|
220
247
|
|
|
221
248
|
# Output:
|
|
@@ -224,7 +251,7 @@ ralph-run --change user-auth
|
|
|
224
251
|
# [INFO] Executing task 2/15: Implement password hashing
|
|
225
252
|
# ...
|
|
226
253
|
|
|
227
|
-
#
|
|
254
|
+
# 5. Verify implementation
|
|
228
255
|
git log --oneline # 15 commits, one per task
|
|
229
256
|
git diff HEAD~15 # See full implementation
|
|
230
257
|
```
|
|
@@ -241,10 +268,15 @@ git diff HEAD~15 # See full implementation
|
|
|
241
268
|
| **Auto-Resume** | Interrupted? Run again — picks up where left off |
|
|
242
269
|
| **Context Injection** | `--add-context` injects guidance into the next iteration |
|
|
243
270
|
| **Loop Status** | `--status` shows active state, history, and struggle indicators |
|
|
271
|
+
| **Error Tracking** | Automatic error logging and archiving for debugging |
|
|
272
|
+
| **Output Capture** | Loop output captured to temp directories for review |
|
|
273
|
+
| **Cross-Platform** | Full support for Linux and macOS with portable operations |
|
|
244
274
|
| **No External Ralph** | Self-contained mini Ralph engine — no external `ralph` CLI needed |
|
|
245
275
|
|
|
246
276
|
## Features
|
|
247
277
|
|
|
278
|
+
*Features available in spec-and-loop 2.0.0 with OpenSpec 1.2.0*
|
|
279
|
+
|
|
248
280
|
### Mini Ralph Loop Engine
|
|
249
281
|
|
|
250
282
|
`spec-and-loop` includes a first-party mini Ralph implementation (`lib/mini-ralph/`) that
|
|
@@ -272,11 +304,17 @@ this repository's OpenSpec-first workflow (multi-agent rotation, plugin toggles,
|
|
|
272
304
|
- **Auto-resume**: Interrupted? Run again — picks up where left off
|
|
273
305
|
- **Context injection**: `--add-context` / `--clear-context` via each change's `.ralph/ralph-context.md`
|
|
274
306
|
- **Error recovery**: Recent loop signals help guide subsequent tasks
|
|
307
|
+
- **Error tracking**: Automatic error logging to `.ralph/errors.md` with timestamps and archiving
|
|
275
308
|
- **Task synchronization**: `tasks.md` and the per-change `.ralph/ralph-tasks.md` symlink stay in sync
|
|
309
|
+
- **Output capture**: Loop output captured to temp directories for review and debugging
|
|
310
|
+
- **Cross-platform**: Portable operations for Linux and macOS (stat, md5sum, realpath)
|
|
311
|
+
- **Cleanup**: Automatic cleanup of old output directories (older than 7 days)
|
|
276
312
|
- **Idempotent**: Run multiple times safely
|
|
277
313
|
|
|
278
314
|
## Advanced Usage
|
|
279
315
|
|
|
316
|
+
*Advanced features for spec-and-loop 2.0.0*
|
|
317
|
+
|
|
280
318
|
### Context Injection
|
|
281
319
|
|
|
282
320
|
Inject custom instructions into the next iteration:
|
|
@@ -322,8 +360,33 @@ ralph-run --verbose --change my-feature
|
|
|
322
360
|
cat openspec/changes/my-feature/.ralph/PRD.md
|
|
323
361
|
```
|
|
324
362
|
|
|
363
|
+
### Review Loop Output
|
|
364
|
+
|
|
365
|
+
```bash
|
|
366
|
+
# Find the latest output directory path
|
|
367
|
+
cat openspec/changes/my-feature/.ralph/.output_dir
|
|
368
|
+
|
|
369
|
+
# View stdout and stderr logs
|
|
370
|
+
cat openspec/changes/my-feature/.ralph/.output_dir/ralph-stdout.log
|
|
371
|
+
cat openspec/changes/my-feature/.ralph/.output_dir/ralph-stderr.log
|
|
372
|
+
```
|
|
373
|
+
|
|
374
|
+
Output is captured to temporary directories for debugging. Old output directories are automatically cleaned up after 7 days.
|
|
375
|
+
|
|
376
|
+
### View Error Logs
|
|
377
|
+
|
|
378
|
+
```bash
|
|
379
|
+
# View recent errors
|
|
380
|
+
cat openspec/changes/my-feature/.ralph/errors.md
|
|
381
|
+
|
|
382
|
+
# Archived errors are saved with timestamps
|
|
383
|
+
ls openspec/changes/my-feature/.ralph/errors_*.md
|
|
384
|
+
```
|
|
385
|
+
|
|
325
386
|
## Architecture
|
|
326
387
|
|
|
388
|
+
*Architecture for spec-and-loop 2.0.0 with OpenSpec 1.2.0*
|
|
389
|
+
|
|
327
390
|
This package integrates:
|
|
328
391
|
- **OpenSpec**: Structured specification workflow
|
|
329
392
|
- **opencode**: Agentic coding assistant for task execution
|
|
@@ -357,16 +420,41 @@ openspec/changes/<name>/
|
|
|
357
420
|
│ └── api/
|
|
358
421
|
│ └── spec.md
|
|
359
422
|
└── .ralph/ # Internal loop state (auto-generated, per change)
|
|
360
|
-
├── PRD.md
|
|
361
|
-
├──
|
|
362
|
-
├── ralph-
|
|
363
|
-
├── ralph-
|
|
364
|
-
├── ralph-
|
|
365
|
-
|
|
423
|
+
├── PRD.md # Generated product requirements document
|
|
424
|
+
├── prompt-template.md # Template used for generating prompts
|
|
425
|
+
├── ralph-history.json # Iteration history and state
|
|
426
|
+
├── ralph-loop.state.json # Current loop state and iteration count
|
|
427
|
+
├── ralph-tasks.md # Symlink to ../tasks.md (syncs task state)
|
|
428
|
+
├── .output_dir # Path to latest output capture directory
|
|
429
|
+
├── ralph-context.md # (Optional) Pending context for next iteration
|
|
430
|
+
├── errors.md # (Optional) Error logs with timestamps
|
|
431
|
+
├── errors_*.md # (Optional) Archived error logs
|
|
432
|
+
└── *.md # (Optional) Research artifacts created during task execution
|
|
366
433
|
```
|
|
367
434
|
|
|
435
|
+
**Note:** Files marked as (Optional) are created only when needed:
|
|
436
|
+
- `ralph-context.md`: Created when you use `--add-context`
|
|
437
|
+
- `errors.md` and `errors_*.md`: Created when errors occur during loop execution
|
|
438
|
+
- Additional `*.md` files: Research artifacts created by opencode during task execution (e.g., verification outputs, analysis documents)
|
|
439
|
+
|
|
440
|
+
### Cross-Platform Support
|
|
441
|
+
|
|
442
|
+
*Cross-platform support verified for spec-and-loop 2.0.0*
|
|
443
|
+
|
|
444
|
+
`spec-and-loop` is designed to work seamlessly on both Linux and macOS. The script includes portable implementations for:
|
|
445
|
+
|
|
446
|
+
- **File modification times**: Uses `stat -f %m` on macOS and `stat -c %Y` on Linux
|
|
447
|
+
- **MD5 hashing**: Supports both `md5sum` (Linux) and `md5 -q` (macOS)
|
|
448
|
+
- **Path resolution**: Falls back from `realpath` to `readlink -f` to manual path construction
|
|
449
|
+
- **Temp directories**: Uses `TMPDIR` environment variable or `/tmp` as fallback
|
|
450
|
+
- **Cleanup**: Portable `find` and `rm` operations for old output directories
|
|
451
|
+
|
|
452
|
+
All features work identically on both platforms without requiring platform-specific configuration.
|
|
453
|
+
|
|
368
454
|
## Troubleshooting
|
|
369
455
|
|
|
456
|
+
*Troubleshooting guide for spec-and-loop 2.0.0 with OpenSpec 1.2.0*
|
|
457
|
+
|
|
370
458
|
For common issues and solutions, see [QUICKSTART.md#troubleshooting](./QUICKSTART.md#troubleshooting).
|
|
371
459
|
|
|
372
460
|
**Quick fixes:**
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
|
|
6
|
+
const ERRORS_FILE = 'errors.md';
|
|
7
|
+
|
|
8
|
+
function errorsPath(ralphDir) {
|
|
9
|
+
return path.join(ralphDir, ERRORS_FILE);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
function read(ralphDir, limit) {
|
|
13
|
+
const file = errorsPath(ralphDir);
|
|
14
|
+
if (!fs.existsSync(file)) return '';
|
|
15
|
+
const content = fs.readFileSync(file, 'utf8').trim();
|
|
16
|
+
if (!content) return '';
|
|
17
|
+
const entries = content.split(/^---$/m).filter(e => e.trim());
|
|
18
|
+
if (!entries.length) return '';
|
|
19
|
+
if (limit !== undefined && limit < entries.length) {
|
|
20
|
+
return entries.slice(-limit).join('\n---\n');
|
|
21
|
+
}
|
|
22
|
+
return entries.join('\n---\n');
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function append(ralphDir, entry) {
|
|
26
|
+
_ensureDir(ralphDir);
|
|
27
|
+
const file = errorsPath(ralphDir);
|
|
28
|
+
const existing = fs.existsSync(file) ? fs.readFileSync(file, 'utf8') : '';
|
|
29
|
+
const separator = existing && !existing.endsWith('\n') ? '\n' : '';
|
|
30
|
+
const timestamp = new Date().toISOString();
|
|
31
|
+
const text = [
|
|
32
|
+
'---',
|
|
33
|
+
`Timestamp: ${timestamp}`,
|
|
34
|
+
`Iteration: ${entry.iteration}`,
|
|
35
|
+
`Task: ${entry.task}`,
|
|
36
|
+
`Exit Code: ${entry.exitCode}`,
|
|
37
|
+
'',
|
|
38
|
+
'### stderr',
|
|
39
|
+
entry.stderr || '',
|
|
40
|
+
'',
|
|
41
|
+
'### stdout',
|
|
42
|
+
entry.stdout || '',
|
|
43
|
+
'',
|
|
44
|
+
].join('\n');
|
|
45
|
+
fs.writeFileSync(file, `${existing}${separator}${text}`, 'utf8');
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function clear(ralphDir) {
|
|
49
|
+
const file = errorsPath(ralphDir);
|
|
50
|
+
if (fs.existsSync(file)) {
|
|
51
|
+
fs.unlinkSync(file);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function archive(ralphDir) {
|
|
56
|
+
const file = errorsPath(ralphDir);
|
|
57
|
+
if (!fs.existsSync(file)) return null;
|
|
58
|
+
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
|
|
59
|
+
const archiveFile = path.join(ralphDir, `errors_${timestamp}.md`);
|
|
60
|
+
fs.copyFileSync(file, archiveFile);
|
|
61
|
+
return archiveFile;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function _ensureDir(ralphDir) {
|
|
65
|
+
if (!fs.existsSync(ralphDir)) {
|
|
66
|
+
fs.mkdirSync(ralphDir, { recursive: true });
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
module.exports = { errorsPath, read, append, clear, archive };
|
package/lib/mini-ralph/index.js
CHANGED
|
@@ -18,6 +18,7 @@ const runner = require('./runner');
|
|
|
18
18
|
const state = require('./state');
|
|
19
19
|
const history = require('./history');
|
|
20
20
|
const context = require('./context');
|
|
21
|
+
const errors = require('./errors');
|
|
21
22
|
const tasks = require('./tasks');
|
|
22
23
|
const status = require('./status');
|
|
23
24
|
const prompt = require('./prompt');
|
|
@@ -84,6 +85,7 @@ module.exports = {
|
|
|
84
85
|
_state: state,
|
|
85
86
|
_history: history,
|
|
86
87
|
_context: context,
|
|
88
|
+
_errors: errors,
|
|
87
89
|
_tasks: tasks,
|
|
88
90
|
_prompt: prompt,
|
|
89
91
|
_runner: runner,
|
package/lib/mini-ralph/runner.js
CHANGED
|
@@ -18,6 +18,7 @@ const context = require('./context');
|
|
|
18
18
|
const tasks = require('./tasks');
|
|
19
19
|
const prompt = require('./prompt');
|
|
20
20
|
const invoker = require('./invoker');
|
|
21
|
+
const errors = require('./errors');
|
|
21
22
|
|
|
22
23
|
const DEFAULTS = {
|
|
23
24
|
minIterations: 1,
|
|
@@ -93,7 +94,8 @@ async function run(opts) {
|
|
|
93
94
|
|
|
94
95
|
// Build the prompt for this iteration
|
|
95
96
|
const renderedPrompt = await prompt.render(options, iterationCount);
|
|
96
|
-
const
|
|
97
|
+
const errorContent = errors.read(ralphDir, 3);
|
|
98
|
+
const iterationFeedback = _buildIterationFeedback(history.recent(ralphDir, 3), errorContent);
|
|
97
99
|
|
|
98
100
|
// Inject any pending context
|
|
99
101
|
const pendingContext = context.consume(ralphDir);
|
|
@@ -146,6 +148,17 @@ async function run(opts) {
|
|
|
146
148
|
completedTasks: completedTasks.map((task) => task.fullDescription || task.description),
|
|
147
149
|
});
|
|
148
150
|
|
|
151
|
+
if (result.exitCode !== 0) {
|
|
152
|
+
const currentTask = _getCurrentTaskDescription(tasksBefore);
|
|
153
|
+
errors.append(ralphDir, {
|
|
154
|
+
iteration: iterationCount,
|
|
155
|
+
task: currentTask,
|
|
156
|
+
exitCode: result.exitCode,
|
|
157
|
+
stderr: result.stderr || '',
|
|
158
|
+
stdout: result.stdout || '',
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
|
|
149
162
|
// Auto-commit only for successful task/completion iterations.
|
|
150
163
|
if (
|
|
151
164
|
!options.noCommit &&
|
|
@@ -174,6 +187,14 @@ async function run(opts) {
|
|
|
174
187
|
}
|
|
175
188
|
}
|
|
176
189
|
|
|
190
|
+
if (completed) {
|
|
191
|
+
const archivePath = errors.archive(ralphDir);
|
|
192
|
+
if (archivePath && options.verbose) {
|
|
193
|
+
process.stderr.write(`[mini-ralph] errors archived to ${archivePath}\n`);
|
|
194
|
+
}
|
|
195
|
+
errors.clear(ralphDir);
|
|
196
|
+
}
|
|
197
|
+
|
|
177
198
|
// Mark loop as inactive
|
|
178
199
|
state.update(ralphDir, { active: false, completedAt: new Date().toISOString() });
|
|
179
200
|
|
|
@@ -321,7 +342,7 @@ function _formatAutoCommitMessage(iteration, completedTasks) {
|
|
|
321
342
|
* @param {Array<object>} recentHistory
|
|
322
343
|
* @returns {string}
|
|
323
344
|
*/
|
|
324
|
-
function _buildIterationFeedback(recentHistory) {
|
|
345
|
+
function _buildIterationFeedback(recentHistory, errorContent) {
|
|
325
346
|
if (!Array.isArray(recentHistory) || recentHistory.length === 0) {
|
|
326
347
|
return '';
|
|
327
348
|
}
|
|
@@ -344,7 +365,22 @@ function _buildIterationFeedback(recentHistory) {
|
|
|
344
365
|
}
|
|
345
366
|
|
|
346
367
|
if (issues.length > 0) {
|
|
347
|
-
|
|
368
|
+
let line = `- Iteration ${entry.iteration}: ${issues.join('; ')}.`;
|
|
369
|
+
|
|
370
|
+
if (entry.exitCode !== 0 && errorContent) {
|
|
371
|
+
const errorDetails = _extractErrorForIteration(errorContent, entry.iteration);
|
|
372
|
+
if (errorDetails) {
|
|
373
|
+
line += '\n Error output:';
|
|
374
|
+
if (errorDetails.stderr) {
|
|
375
|
+
line += `\n ${errorDetails.stderr}`;
|
|
376
|
+
}
|
|
377
|
+
if (errorDetails.stdout) {
|
|
378
|
+
line += `\n stdout: ${errorDetails.stdout}`;
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
problemLines.push(line);
|
|
348
384
|
}
|
|
349
385
|
}
|
|
350
386
|
|
|
@@ -358,6 +394,39 @@ function _buildIterationFeedback(recentHistory) {
|
|
|
358
394
|
].join('\n');
|
|
359
395
|
}
|
|
360
396
|
|
|
397
|
+
function _extractErrorForIteration(errorContent, iteration) {
|
|
398
|
+
if (!errorContent) return null;
|
|
399
|
+
|
|
400
|
+
const entries = errorContent.split(/^---$/m).filter((e) => e.trim());
|
|
401
|
+
|
|
402
|
+
for (const entry of entries) {
|
|
403
|
+
if (!entry.includes(`Iteration: ${iteration}`)) continue;
|
|
404
|
+
|
|
405
|
+
let stderr = '';
|
|
406
|
+
let stdout = '';
|
|
407
|
+
|
|
408
|
+
const stderrMatch = entry.match(/### stderr\n([\s\S]*?)(?=\n### stdout|$)/);
|
|
409
|
+
const stdoutMatch = entry.match(/### stdout\n([\s\S]*?)$/);
|
|
410
|
+
|
|
411
|
+
if (stderrMatch) stderr = stderrMatch[1].trim();
|
|
412
|
+
if (stdoutMatch) stdout = stdoutMatch[1].trim();
|
|
413
|
+
|
|
414
|
+
if (stderr.length > 2000) stderr = stderr.substring(0, 2000) + '...';
|
|
415
|
+
if (stdout.length > 500) stdout = stdout.substring(0, 500) + '...';
|
|
416
|
+
|
|
417
|
+
return { stderr, stdout };
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
return null;
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
function _getCurrentTaskDescription(tasksBefore) {
|
|
424
|
+
if (!Array.isArray(tasksBefore) || tasksBefore.length === 0) return 'N/A';
|
|
425
|
+
const incomplete = tasksBefore.find((t) => t.status !== 'completed');
|
|
426
|
+
if (incomplete) return incomplete.fullDescription || incomplete.description || 'N/A';
|
|
427
|
+
return 'N/A';
|
|
428
|
+
}
|
|
429
|
+
|
|
361
430
|
function _taskIdentity(task) {
|
|
362
431
|
return task.number
|
|
363
432
|
? `${task.number}|${task.fullDescription || task.description}`
|
|
@@ -412,4 +481,6 @@ module.exports = {
|
|
|
412
481
|
_completedTaskDelta,
|
|
413
482
|
_formatAutoCommitMessage,
|
|
414
483
|
_buildIterationFeedback,
|
|
484
|
+
_extractErrorForIteration,
|
|
485
|
+
_getCurrentTaskDescription,
|
|
415
486
|
};
|
package/lib/mini-ralph/status.js
CHANGED
|
@@ -12,6 +12,7 @@ const state = require('./state');
|
|
|
12
12
|
const history = require('./history');
|
|
13
13
|
const context = require('./context');
|
|
14
14
|
const tasks = require('./tasks');
|
|
15
|
+
const errors = require('./errors');
|
|
15
16
|
|
|
16
17
|
/**
|
|
17
18
|
* Render a status dashboard string for the given .ralph/ directory.
|
|
@@ -99,6 +100,19 @@ function render(ralphDir, tasksFile) {
|
|
|
99
100
|
lines.push('-'.repeat(50));
|
|
100
101
|
}
|
|
101
102
|
|
|
103
|
+
// Error history
|
|
104
|
+
const errorContent = errors.read(ralphDir, 3);
|
|
105
|
+
if (errorContent) {
|
|
106
|
+
const entries = errorContent.split(/^---$/m).filter(e => e.trim());
|
|
107
|
+
const count = entries.length;
|
|
108
|
+
const preview = entries[entries.length - 1].substring(0, 200).trim();
|
|
109
|
+
lines.push('');
|
|
110
|
+
lines.push('--- Error History ---');
|
|
111
|
+
lines.push(` Errors: ${count}`);
|
|
112
|
+
lines.push(` Most recent: ${preview}`);
|
|
113
|
+
lines.push('-'.repeat(50));
|
|
114
|
+
}
|
|
115
|
+
|
|
102
116
|
// Struggle indicators
|
|
103
117
|
const struggles = _detectStruggles(recentHistory);
|
|
104
118
|
if (struggles.length > 0) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "spec-and-loop",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.1",
|
|
4
4
|
"description": "OpenSpec + Ralph Loop integration for iterative development with opencode",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"bin": {
|
|
@@ -17,7 +17,8 @@
|
|
|
17
17
|
"lint": "shellcheck scripts/*.sh"
|
|
18
18
|
},
|
|
19
19
|
"dependencies": {
|
|
20
|
-
"@fission-ai/openspec": "1.2.0"
|
|
20
|
+
"@fission-ai/openspec": "1.2.0",
|
|
21
|
+
"spec-and-loop": "^2.0.0"
|
|
21
22
|
},
|
|
22
23
|
"devDependencies": {
|
|
23
24
|
"@types/jest": "^29.5.0",
|
package/scripts/ralph-run.sh
CHANGED
|
@@ -496,6 +496,10 @@ check_tasks_modified() {
|
|
|
496
496
|
return 1
|
|
497
497
|
}
|
|
498
498
|
|
|
499
|
+
# DEPRECATED: The following functions are superseded by lib/mini-ralph/errors.js.
|
|
500
|
+
# Do not add new callers. These will be removed in a future cleanup.
|
|
501
|
+
# See: lib/mini-ralph/errors.js for the current implementation.
|
|
502
|
+
|
|
499
503
|
format_error_entry() {
|
|
500
504
|
local task_id="$1"
|
|
501
505
|
local task_description="$2"
|