agentic-loop 3.18.0 → 3.18.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/package.json +1 -1
- package/ralph/code-check.sh +4 -15
- package/ralph/loop.sh +57 -0
- package/ralph/prd-check.sh +1 -43
- package/templates/config/elixir.json +1 -1
- package/templates/config/fastmcp.json +1 -1
- package/templates/config/fullstack.json +1 -1
- package/templates/config/go.json +1 -1
- package/templates/config/minimal.json +1 -1
- package/templates/config/node.json +1 -1
- package/templates/config/python.json +1 -1
- package/templates/config/rust.json +1 -1
package/package.json
CHANGED
package/ralph/code-check.sh
CHANGED
|
@@ -247,7 +247,7 @@ _detect_structural_errors() {
|
|
|
247
247
|
local error_content
|
|
248
248
|
error_content=$(cat "$context_file")
|
|
249
249
|
|
|
250
|
-
# Schema/column errors -
|
|
250
|
+
# Schema/column errors - detect and flag for Claude context
|
|
251
251
|
# Only show if not already detected (avoid duplicate markers on retry)
|
|
252
252
|
if echo "$error_content" | grep -qiE "(column.*does not exist|relation.*does not exist|no such column|unknown column|undefined column)" && \
|
|
253
253
|
! grep -q ">>> STRUCTURAL ISSUE: Database schema mismatch" "$context_file" 2>/dev/null; then
|
|
@@ -256,28 +256,17 @@ _detect_structural_errors() {
|
|
|
256
256
|
echo ""
|
|
257
257
|
echo " The test database is missing columns/tables that the code expects."
|
|
258
258
|
echo " This usually happens when:"
|
|
259
|
-
echo " - Migrations were added but test DB wasn't
|
|
259
|
+
echo " - Migrations were added but test DB wasn't updated"
|
|
260
260
|
echo " - Models were modified without running migrations"
|
|
261
261
|
echo ""
|
|
262
|
-
echo "
|
|
263
|
-
local reset_cmd
|
|
264
|
-
reset_cmd=$(get_config '.commands.resetDb' "")
|
|
265
|
-
if [[ -n "$reset_cmd" ]]; then
|
|
266
|
-
echo " $reset_cmd"
|
|
267
|
-
else
|
|
268
|
-
echo " # Add to .ralph/config.json:"
|
|
269
|
-
echo " {\"commands\": {\"resetDb\": \"npm run db:reset:test\"}}"
|
|
270
|
-
echo ""
|
|
271
|
-
echo " # Or run manually:"
|
|
272
|
-
echo " dropdb test_db && createdb test_db && alembic upgrade head"
|
|
273
|
-
fi
|
|
262
|
+
echo " Run pending migrations to fix the schema."
|
|
274
263
|
echo ""
|
|
275
264
|
|
|
276
265
|
# Append suggestion to failure context for Claude
|
|
277
266
|
{
|
|
278
267
|
echo ""
|
|
279
268
|
echo ">>> STRUCTURAL ISSUE: Database schema mismatch"
|
|
280
|
-
echo ">>> ACTION NEEDED:
|
|
269
|
+
echo ">>> ACTION NEEDED: Run pending migrations to update the schema"
|
|
281
270
|
echo ">>> This is NOT a code bug - the test DB is missing schema changes"
|
|
282
271
|
} >> "$context_file"
|
|
283
272
|
fi
|
package/ralph/loop.sh
CHANGED
|
@@ -391,6 +391,10 @@ PATTERN: <pattern>"
|
|
|
391
391
|
}
|
|
392
392
|
|
|
393
393
|
run_loop() {
|
|
394
|
+
# Trap Ctrl+C so it stops the entire loop, not just the current child process.
|
|
395
|
+
# Without this, SIGINT only kills the pipeline (claude|tee) and the while loop continues.
|
|
396
|
+
trap 'echo ""; print_warning "Ctrl+C received — stopping loop..."; trap - INT; kill -INT $$' INT
|
|
397
|
+
|
|
394
398
|
local max_iterations="$DEFAULT_MAX_ITERATIONS"
|
|
395
399
|
local specific_story=""
|
|
396
400
|
local fast_mode=false
|
|
@@ -950,6 +954,36 @@ startup_checklist() {
|
|
|
950
954
|
fi
|
|
951
955
|
}
|
|
952
956
|
|
|
957
|
+
# Helper: Check if files listed in a story's files.create/files.modify already exist on disk
|
|
958
|
+
# Returns newline-separated list of existing files (empty string if none)
|
|
959
|
+
_check_story_files_exist() {
|
|
960
|
+
local story_id="$1"
|
|
961
|
+
local prd_file="$RALPH_DIR/prd.json"
|
|
962
|
+
[[ ! -f "$prd_file" ]] && return
|
|
963
|
+
|
|
964
|
+
local file_list
|
|
965
|
+
file_list=$(jq -r --arg id "$story_id" '
|
|
966
|
+
.stories[] | select(.id == $id) |
|
|
967
|
+
((.files.create // []) + (.files.modify // [])) | .[]
|
|
968
|
+
' "$prd_file" 2>/dev/null) || return
|
|
969
|
+
|
|
970
|
+
[[ -z "$file_list" ]] && return
|
|
971
|
+
|
|
972
|
+
local existing=""
|
|
973
|
+
while IFS= read -r f; do
|
|
974
|
+
[[ -z "$f" ]] && continue
|
|
975
|
+
if [[ -f "$f" ]]; then
|
|
976
|
+
if [[ -z "$existing" ]]; then
|
|
977
|
+
existing="$f"
|
|
978
|
+
else
|
|
979
|
+
existing="$existing"$'\n'"$f"
|
|
980
|
+
fi
|
|
981
|
+
fi
|
|
982
|
+
done <<< "$file_list"
|
|
983
|
+
|
|
984
|
+
[[ -n "$existing" ]] && echo "$existing"
|
|
985
|
+
}
|
|
986
|
+
|
|
953
987
|
# Helper: Build delta prompt for continuing session
|
|
954
988
|
# Minimal context - just story ID + any failure info
|
|
955
989
|
_build_delta_prompt() {
|
|
@@ -964,6 +998,15 @@ _build_delta_prompt() {
|
|
|
964
998
|
if [[ -n "$failure_context" ]]; then
|
|
965
999
|
echo "## Retry: Fix the errors below"
|
|
966
1000
|
echo ""
|
|
1001
|
+
|
|
1002
|
+
# Check if story files already exist — if so, skip re-implementation
|
|
1003
|
+
local existing_files
|
|
1004
|
+
existing_files=$(_check_story_files_exist "$story")
|
|
1005
|
+
if [[ -n "$existing_files" ]]; then
|
|
1006
|
+
echo "**The code is ALREADY WRITTEN.** Do NOT rewrite. Fix ONLY the errors below, then verify."
|
|
1007
|
+
echo ""
|
|
1008
|
+
fi
|
|
1009
|
+
|
|
967
1010
|
echo "Read \`.ralph/last_failure.txt\` for full error details."
|
|
968
1011
|
echo ""
|
|
969
1012
|
echo '```'
|
|
@@ -1039,6 +1082,20 @@ build_prompt() {
|
|
|
1039
1082
|
echo ""
|
|
1040
1083
|
echo "## Previous Iteration Failed"
|
|
1041
1084
|
echo ""
|
|
1085
|
+
|
|
1086
|
+
# Check if story files already exist — if so, skip re-implementation
|
|
1087
|
+
local existing_files
|
|
1088
|
+
existing_files=$(_check_story_files_exist "$story")
|
|
1089
|
+
if [[ -n "$existing_files" ]]; then
|
|
1090
|
+
echo "**IMPORTANT: The code for this story is ALREADY WRITTEN.** These files exist:"
|
|
1091
|
+
echo '```'
|
|
1092
|
+
echo "$existing_files"
|
|
1093
|
+
echo '```'
|
|
1094
|
+
echo "Do NOT rewrite or re-implement. Read the existing code, then fix ONLY the"
|
|
1095
|
+
echo "specific errors below. Go straight to verification after fixing."
|
|
1096
|
+
echo ""
|
|
1097
|
+
fi
|
|
1098
|
+
|
|
1042
1099
|
echo "Read \`.ralph/last_failure.txt\` for details. Key error:"
|
|
1043
1100
|
echo ""
|
|
1044
1101
|
echo '```'
|
package/ralph/prd-check.sh
CHANGED
|
@@ -46,10 +46,6 @@
|
|
|
46
46
|
# LIST ENDPOINTS (get all, index):
|
|
47
47
|
# - Has pagination criteria (limit, page params)
|
|
48
48
|
#
|
|
49
|
-
# MIGRATION STORIES (alembic, migrations, models):
|
|
50
|
-
# - Has prerequisites array with DB reset command
|
|
51
|
-
# - Prevents infinite retries on schema mismatch errors
|
|
52
|
-
#
|
|
53
49
|
# CUSTOM CHECKS (.ralph/checks/prd/):
|
|
54
50
|
# - User-provided scripts that receive story JSON on stdin
|
|
55
51
|
# - Output issue descriptions to stdout (one per line)
|
|
@@ -69,7 +65,6 @@
|
|
|
69
65
|
# - Missing mcp on frontend → ["playwright", "devtools"]
|
|
70
66
|
# - Bare pytest → prefixed with detected runner (uv/poetry/pipenv)
|
|
71
67
|
# - Missing camelCase note → standard text appended to .notes
|
|
72
|
-
# - Missing migration prerequisites → template prerequisite array
|
|
73
68
|
# - Server-only testSteps → offline fallback appended
|
|
74
69
|
#
|
|
75
70
|
# Tier 2 — Parallel Claude subagents (one per story, concurrent):
|
|
@@ -344,7 +339,7 @@ _validate_and_fix_stories() {
|
|
|
344
339
|
local cnt_no_tests=0 cnt_backend_curl=0 cnt_backend_contract=0
|
|
345
340
|
local cnt_frontend_tsc=0 cnt_frontend_url=0 cnt_frontend_context=0 cnt_frontend_mcp=0
|
|
346
341
|
local cnt_auth_security=0 cnt_list_pagination=0 cnt_prose_steps=0
|
|
347
|
-
local
|
|
342
|
+
local cnt_naming_convention=0 cnt_bare_pytest=0
|
|
348
343
|
local cnt_server_only=0
|
|
349
344
|
local cnt_custom=0
|
|
350
345
|
|
|
@@ -466,19 +461,6 @@ _validate_and_fix_stories() {
|
|
|
466
461
|
fi
|
|
467
462
|
fi
|
|
468
463
|
|
|
469
|
-
# Check 6: Migration stories need DB prerequisites
|
|
470
|
-
# If story creates migration files or modifies models, it needs resetDb prerequisite
|
|
471
|
-
local story_files
|
|
472
|
-
story_files=$(jq -r --arg id "$story_id" '.stories[] | select(.id==$id) | (.files.create // []) + (.files.modify // []) | join(" ")' "$prd_file")
|
|
473
|
-
if echo "$story_files" | grep -qiE "(alembic/versions|migrations/|\.migration\.|models\.py|models/|schema\.)"; then
|
|
474
|
-
local has_prereq
|
|
475
|
-
has_prereq=$(jq -r --arg id "$story_id" '.stories[] | select(.id==$id) | .prerequisites // [] | length' "$prd_file")
|
|
476
|
-
if [[ "$has_prereq" == "0" ]]; then
|
|
477
|
-
story_issues+="migration story needs prerequisites (DB reset), "
|
|
478
|
-
cnt_migration_prereq=$((cnt_migration_prereq + 1))
|
|
479
|
-
fi
|
|
480
|
-
fi
|
|
481
|
-
|
|
482
464
|
# Check 7: Frontend stories consuming APIs need naming convention notes
|
|
483
465
|
# If story is frontend/general AND mentions API/fetch/axios, ensure notes include camelCase guidance
|
|
484
466
|
if [[ "$story_type" == "frontend" || "$story_type" == "general" ]]; then
|
|
@@ -563,7 +545,6 @@ _validate_and_fix_stories() {
|
|
|
563
545
|
[[ $cnt_frontend_mcp -gt 0 ]] && echo " ${cnt_frontend_mcp}x frontend: add mcp browser tools"
|
|
564
546
|
[[ $cnt_auth_security -gt 0 ]] && echo " ${cnt_auth_security}x auth: add security criteria"
|
|
565
547
|
[[ $cnt_list_pagination -gt 0 ]] && echo " ${cnt_list_pagination}x list: add pagination"
|
|
566
|
-
[[ $cnt_migration_prereq -gt 0 ]] && echo " ${cnt_migration_prereq}x migration: add prerequisites (DB reset)"
|
|
567
548
|
[[ $cnt_naming_convention -gt 0 ]] && echo " ${cnt_naming_convention}x API consumer: add camelCase transformation note"
|
|
568
549
|
[[ $cnt_bare_pytest -gt 0 ]] && echo " ${cnt_bare_pytest}x use 'uv run pytest' not bare 'pytest'"
|
|
569
550
|
[[ $cnt_server_only -gt 0 ]] && echo " ${cnt_server_only}x all testSteps need live server (add offline fallback)"
|
|
@@ -740,18 +721,6 @@ _apply_mechanical_fixes() {
|
|
|
740
721
|
fi
|
|
741
722
|
fi
|
|
742
723
|
|
|
743
|
-
# Fix: Migration story missing prerequisites
|
|
744
|
-
local story_files
|
|
745
|
-
story_files=$(jq -r --arg id "$story_id" '.stories[] | select(.id==$id) | (.files.create // []) + (.files.modify // []) | join(" ")' "$prd_file")
|
|
746
|
-
if echo "$story_files" | grep -qiE "(alembic/versions|migrations/|\.migration\.|models\.py|models/|schema\.)"; then
|
|
747
|
-
local has_prereq
|
|
748
|
-
has_prereq=$(jq -r --arg id "$story_id" '.stories[] | select(.id==$id) | .prerequisites // [] | length' "$prd_file")
|
|
749
|
-
if [[ "$has_prereq" == "0" ]]; then
|
|
750
|
-
update_json "$prd_file" --arg id "$story_id" \
|
|
751
|
-
'(.stories[] | select(.id==$id) | .prerequisites) = [{"name": "Reset test DB", "command": "npm run db:reset:test", "when": "schema changes"}]' && fixed=$((fixed + 1))
|
|
752
|
-
fi
|
|
753
|
-
fi
|
|
754
|
-
|
|
755
724
|
# Fix: All testSteps are server-dependent → append offline test step
|
|
756
725
|
local test_steps
|
|
757
726
|
test_steps=$(jq -r --arg id "$story_id" '.stories[] | select(.id==$id) | .testSteps // [] | join(" ")' "$prd_file")
|
|
@@ -1005,17 +974,6 @@ validate_stories_quick() {
|
|
|
1005
974
|
fi
|
|
1006
975
|
fi
|
|
1007
976
|
|
|
1008
|
-
# Check 6: Migration stories need prerequisites
|
|
1009
|
-
local story_files
|
|
1010
|
-
story_files=$(jq -r --arg id "$story_id" '.stories[] | select(.id==$id) | (.files.create // []) + (.files.modify // []) | join(" ")' "$prd_file")
|
|
1011
|
-
if echo "$story_files" | grep -qiE "(alembic/versions|migrations/|\.migration\.|models\.py|models/|schema\.)"; then
|
|
1012
|
-
local has_prereq
|
|
1013
|
-
has_prereq=$(jq -r --arg id "$story_id" '.stories[] | select(.id==$id) | .prerequisites // [] | length' "$prd_file")
|
|
1014
|
-
if [[ "$has_prereq" == "0" ]]; then
|
|
1015
|
-
issues+="$story_id: migration needs prerequisites, "
|
|
1016
|
-
fi
|
|
1017
|
-
fi
|
|
1018
|
-
|
|
1019
977
|
# Check 7: Frontend/general stories consuming APIs need naming convention notes
|
|
1020
978
|
if [[ "$story_type" == "frontend" || "$story_type" == "general" ]]; then
|
|
1021
979
|
local story_desc
|
package/templates/config/go.json
CHANGED