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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agentic-loop",
3
- "version": "3.18.0",
3
+ "version": "3.18.2",
4
4
  "description": "Autonomous AI coding loop - PRD-driven development with Claude Code",
5
5
  "author": "Allie Jones <allie@allthrive.ai>",
6
6
  "license": "MIT",
@@ -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 - suggest DB reset
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 reset"
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 " SUGGESTED FIX (don't retry code - fix the schema):"
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: Reset test database, don't just retry code"
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 '```'
@@ -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 cnt_migration_prereq=0 cnt_naming_convention=0 cnt_bare_pytest=0
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
@@ -26,7 +26,7 @@
26
26
  "dev": "mix phx.server",
27
27
  "install": "mix deps.get",
28
28
  "seed": "mix run priv/repo/seeds.exs",
29
- "resetDb": "mix ecto.reset"
29
+ "migrate": "mix ecto.migrate"
30
30
  },
31
31
 
32
32
  "migrations": {
@@ -32,7 +32,7 @@
32
32
  "typecheck": "uv run mypy src/",
33
33
  "test": "uv run pytest",
34
34
  "seed": "",
35
- "resetDb": ""
35
+ "migrate": ""
36
36
  },
37
37
 
38
38
  "checks": {
@@ -28,7 +28,7 @@
28
28
  "devBackend": "python manage.py runserver",
29
29
  "install": "npm install && pip install -r requirements.txt",
30
30
  "seed": "",
31
- "resetDb": ""
31
+ "migrate": ""
32
32
  },
33
33
 
34
34
  "migrations": {
@@ -26,7 +26,7 @@
26
26
  "dev": "go run .",
27
27
  "install": "go mod download",
28
28
  "seed": "",
29
- "resetDb": ""
29
+ "migrate": ""
30
30
  },
31
31
 
32
32
  "migrations": {
@@ -26,7 +26,7 @@
26
26
  "dev": "",
27
27
  "install": "",
28
28
  "seed": "",
29
- "resetDb": ""
29
+ "migrate": ""
30
30
  },
31
31
 
32
32
  "migrations": {
@@ -26,7 +26,7 @@
26
26
  "dev": "npm run dev",
27
27
  "install": "npm install",
28
28
  "seed": "",
29
- "resetDb": ""
29
+ "migrate": ""
30
30
  },
31
31
 
32
32
  "migrations": {
@@ -26,7 +26,7 @@
26
26
  "dev": "uvicorn main:app --reload",
27
27
  "install": "pip install -r requirements.txt",
28
28
  "seed": "",
29
- "resetDb": ""
29
+ "migrate": ""
30
30
  },
31
31
 
32
32
  "migrations": {
@@ -26,7 +26,7 @@
26
26
  "dev": "cargo run",
27
27
  "install": "cargo build",
28
28
  "seed": "",
29
- "resetDb": ""
29
+ "migrate": ""
30
30
  },
31
31
 
32
32
  "migrations": {