agentic-loop 3.4.6 → 3.5.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/ralph/setup.sh CHANGED
@@ -2,6 +2,80 @@
2
2
  # shellcheck shell=bash
3
3
  # setup.sh - Set up agentic-loop in a project
4
4
 
5
+ # Append missing sections from template to existing PROMPT.md
6
+ # Usage: append_prompt_sections <template_file> <target_file>
7
+ append_prompt_sections() {
8
+ local template="$1"
9
+ local target="$2"
10
+ local added=false
11
+
12
+ # Key sections to check and append if missing
13
+ local sections=(
14
+ "### 3. Verify It Actually Works"
15
+ "**Playwright MCP**"
16
+ "**Chrome DevTools MCP**"
17
+ "## Verification Checklist"
18
+ "## Code Quality Standards"
19
+ "## Architecture Rules"
20
+ "## Scalability Rules"
21
+ )
22
+
23
+ for section in "${sections[@]}"; do
24
+ if ! grep -qF "$section" "$target" 2>/dev/null; then
25
+ # Section missing - extract and append it
26
+ case "$section" in
27
+ "### 3. Verify It Actually Works"|"**Playwright MCP**"|"**Chrome DevTools MCP**")
28
+ # Extract the browser verification block
29
+ if ! grep -qF "Playwright MCP" "$target" 2>/dev/null; then
30
+ echo "" >> "$target"
31
+ echo "### 3. Verify It Actually Works" >> "$target"
32
+ echo "" >> "$target"
33
+ echo "**You have browser tools - USE THEM to verify your work:**" >> "$target"
34
+ echo "" >> "$target"
35
+ echo "**Playwright MCP** (testing & automation):" >> "$target"
36
+ echo "- Navigate to URLs and verify page content" >> "$target"
37
+ echo "- Take screenshots to verify UI renders correctly" >> "$target"
38
+ echo "- Click elements and fill forms to test interactions" >> "$target"
39
+ echo "- Get accessibility snapshots for a11y testing" >> "$target"
40
+ echo "" >> "$target"
41
+ echo "**Chrome DevTools MCP** (debugging & inspection):" >> "$target"
42
+ echo "- Inspect DOM elements and check console for errors" >> "$target"
43
+ echo "- Debug network requests and responses" >> "$target"
44
+ echo "- Check element styles and computed properties" >> "$target"
45
+ echo "" >> "$target"
46
+ echo "**Do NOT say you're done until:**" >> "$target"
47
+ echo "- All unit tests pass" >> "$target"
48
+ echo "- You've opened the browser and visually verified the feature works" >> "$target"
49
+ echo "- Console has no errors" >> "$target"
50
+ echo "- Error states are handled gracefully" >> "$target"
51
+ added=true
52
+ break # Don't re-add for the other MCP checks
53
+ fi
54
+ ;;
55
+ "## Verification Checklist")
56
+ echo "" >> "$target"
57
+ echo "## Verification Checklist" >> "$target"
58
+ echo "" >> "$target"
59
+ echo "Before considering any story complete:" >> "$target"
60
+ echo "" >> "$target"
61
+ echo "- [ ] All acceptance criteria are met" >> "$target"
62
+ echo "- [ ] All error handling from story is implemented" >> "$target"
63
+ echo "- [ ] TypeScript/code compiles without errors" >> "$target"
64
+ echo "- [ ] Unit tests written and passing" >> "$target"
65
+ echo "- [ ] **Browser verified** - used MCP tools to visually confirm it works" >> "$target"
66
+ echo "- [ ] No console errors" >> "$target"
67
+ echo "- [ ] Linting passes" >> "$target"
68
+ added=true
69
+ ;;
70
+ esac
71
+ fi
72
+ done
73
+
74
+ if [[ "$added" == "true" ]]; then
75
+ echo " Updated PROMPT.md with new sections"
76
+ fi
77
+ }
78
+
5
79
  ralph_setup() {
6
80
  echo ""
7
81
  echo " _ _ _ _ "
@@ -93,10 +167,15 @@ setup_ralph_dir() {
93
167
  echo " Created .ralph/signs.json"
94
168
  fi
95
169
 
96
- # Create PROMPT.md if missing
97
- if [[ ! -f "PROMPT.md" ]] && [[ -f "$pkg_root/templates/PROMPT.md" ]]; then
98
- cp "$pkg_root/templates/PROMPT.md" "PROMPT.md"
99
- echo " Created PROMPT.md"
170
+ # Create or update PROMPT.md
171
+ if [[ -f "$pkg_root/templates/PROMPT.md" ]]; then
172
+ if [[ ! -f "PROMPT.md" ]]; then
173
+ cp "$pkg_root/templates/PROMPT.md" "PROMPT.md"
174
+ echo " Created PROMPT.md"
175
+ else
176
+ # Append missing sections to existing PROMPT.md
177
+ append_prompt_sections "$pkg_root/templates/PROMPT.md" "PROMPT.md"
178
+ fi
100
179
  fi
101
180
 
102
181
  # Auto-detect project settings
@@ -468,18 +547,12 @@ EOF
468
547
  # Set up GitHub Actions CI/CD
469
548
  setup_github_ci() {
470
549
  local pkg_root="$1"
471
- local template_dir="$pkg_root/templates/github/workflows"
472
550
 
473
551
  # Skip if not a git repo
474
552
  if [[ ! -d ".git" ]]; then
475
553
  return 0
476
554
  fi
477
555
 
478
- # Skip if templates don't exist
479
- if [[ ! -d "$template_dir" ]]; then
480
- return 0
481
- fi
482
-
483
556
  # Skip if already set up
484
557
  if [[ -f ".github/workflows/pr.yml" ]] && [[ -f ".github/workflows/nightly.yml" ]]; then
485
558
  return 0
@@ -493,7 +566,7 @@ setup_github_ci() {
493
566
  read -r -p " Set up GitHub Actions? [Y/n] " response
494
567
 
495
568
  if [[ "$response" =~ ^[Nn]$ ]]; then
496
- echo " Skipped GitHub Actions (run 'ralph ci install' later)"
569
+ echo " Skipped GitHub Actions (run 'npx agentic-loop ci install' later)"
497
570
  return 0
498
571
  fi
499
572
 
@@ -502,15 +575,200 @@ setup_github_ci() {
502
575
  # Create workflows directory
503
576
  mkdir -p .github/workflows
504
577
 
505
- # Install PR workflow
578
+ # Read config values for dynamic generation
579
+ local backend_dir frontend_dir test_cmd
580
+ backend_dir=$(get_config '.directories.backend' "")
581
+ frontend_dir=$(get_config '.directories.frontend' "")
582
+ test_cmd=$(get_config '.checks.testCommand' "")
583
+
584
+ # Generate PR workflow
506
585
  if [[ ! -f ".github/workflows/pr.yml" ]]; then
507
- cp "$template_dir/pr.yml" .github/workflows/pr.yml
586
+ _generate_pr_workflow "$backend_dir" "$frontend_dir"
508
587
  echo " Created .github/workflows/pr.yml (fast PR checks)"
509
588
  fi
510
589
 
511
- # Install nightly workflow
590
+ # Generate nightly workflow
512
591
  if [[ ! -f ".github/workflows/nightly.yml" ]]; then
513
- cp "$template_dir/nightly.yml" .github/workflows/nightly.yml
592
+ _generate_nightly_workflow "$backend_dir" "$frontend_dir" "$test_cmd"
514
593
  echo " Created .github/workflows/nightly.yml (nightly full tests)"
515
594
  fi
516
595
  }
596
+
597
+ # Generate PR workflow based on project structure
598
+ _generate_pr_workflow() {
599
+ local backend_dir="$1"
600
+ local frontend_dir="$2"
601
+
602
+ cat > .github/workflows/pr.yml << 'HEADER'
603
+ # Fast PR checks - lint only, no tests
604
+ name: PR Check
605
+
606
+ on:
607
+ pull_request:
608
+ branches: [main, master]
609
+
610
+ jobs:
611
+ lint:
612
+ runs-on: ubuntu-latest
613
+ steps:
614
+ - uses: actions/checkout@v4
615
+ HEADER
616
+
617
+ # Detect and add Python steps
618
+ if [[ -f "pyproject.toml" ]] || [[ -f "requirements.txt" ]] || [[ -n "$backend_dir" && -f "$backend_dir/pyproject.toml" ]]; then
619
+ local py_dir="${backend_dir:-.}"
620
+ cat >> .github/workflows/pr.yml << EOF
621
+
622
+ - name: Set up Python
623
+ uses: actions/setup-python@v5
624
+ with:
625
+ python-version: '3.11'
626
+
627
+ - name: Install Python dependencies
628
+ run: |
629
+ pip install ruff uv
630
+ cd $py_dir && uv pip install -e . --system 2>/dev/null || pip install -e . 2>/dev/null || true
631
+
632
+ - name: Ruff lint
633
+ run: cd $py_dir && ruff check .
634
+ EOF
635
+ fi
636
+
637
+ # Detect and add Node.js steps
638
+ if [[ -f "package.json" ]] || [[ -n "$frontend_dir" && -f "$frontend_dir/package.json" ]]; then
639
+ local node_dir="${frontend_dir:-.}"
640
+ cat >> .github/workflows/pr.yml << EOF
641
+
642
+ - name: Set up Node.js
643
+ uses: actions/setup-node@v4
644
+ with:
645
+ node-version: '20'
646
+
647
+ - name: Install Node dependencies
648
+ run: cd $node_dir && npm ci
649
+
650
+ - name: Lint
651
+ run: cd $node_dir && npm run lint 2>/dev/null || true
652
+
653
+ - name: TypeScript check
654
+ run: cd $node_dir && npx tsc --noEmit 2>/dev/null || true
655
+
656
+ - name: Build
657
+ run: cd $node_dir && npm run build 2>/dev/null || true
658
+ EOF
659
+ fi
660
+ }
661
+
662
+ # Generate nightly workflow based on project structure
663
+ _generate_nightly_workflow() {
664
+ local backend_dir="$1"
665
+ local frontend_dir="$2"
666
+ local test_cmd="$3"
667
+
668
+ cat > .github/workflows/nightly.yml << 'HEADER'
669
+ # Nightly comprehensive test suite
670
+ name: Nightly Tests
671
+
672
+ on:
673
+ schedule:
674
+ - cron: '0 3 * * *' # 3am UTC daily
675
+ workflow_dispatch:
676
+
677
+ jobs:
678
+ test:
679
+ runs-on: ubuntu-latest
680
+ HEADER
681
+
682
+ # Add services if backend exists (likely needs DB)
683
+ if [[ -n "$backend_dir" ]] || [[ -f "pyproject.toml" ]]; then
684
+ cat >> .github/workflows/nightly.yml << 'EOF'
685
+
686
+ services:
687
+ postgres:
688
+ image: postgres:15
689
+ env:
690
+ POSTGRES_USER: test
691
+ POSTGRES_PASSWORD: test
692
+ POSTGRES_DB: test
693
+ ports:
694
+ - 5432:5432
695
+ options: >-
696
+ --health-cmd pg_isready
697
+ --health-interval 10s
698
+ --health-timeout 5s
699
+ --health-retries 5
700
+
701
+ env:
702
+ DATABASE_URL: postgresql://test:test@localhost:5432/test
703
+ EOF
704
+ fi
705
+
706
+ cat >> .github/workflows/nightly.yml << 'EOF'
707
+
708
+ steps:
709
+ - uses: actions/checkout@v4
710
+ EOF
711
+
712
+ # Add Python setup and tests
713
+ if [[ -f "pyproject.toml" ]] || [[ -n "$backend_dir" && -f "$backend_dir/pyproject.toml" ]]; then
714
+ local py_dir="${backend_dir:-.}"
715
+ local py_test_cmd="${test_cmd:-pytest -v --tb=short}"
716
+
717
+ cat >> .github/workflows/nightly.yml << EOF
718
+
719
+ - name: Set up Python
720
+ uses: actions/setup-python@v5
721
+ with:
722
+ python-version: '3.11'
723
+
724
+ - name: Install Python dependencies
725
+ run: |
726
+ pip install uv
727
+ cd $py_dir && uv pip install -e ".[dev]" --system 2>/dev/null || pip install -e . 2>/dev/null || true
728
+
729
+ - name: Run migrations
730
+ run: cd $py_dir && alembic upgrade head 2>/dev/null || true
731
+ continue-on-error: true
732
+
733
+ - name: Python tests
734
+ run: cd $py_dir && $py_test_cmd
735
+ continue-on-error: true
736
+ EOF
737
+ fi
738
+
739
+ # Add Node.js setup and tests
740
+ if [[ -f "package.json" ]] || [[ -n "$frontend_dir" && -f "$frontend_dir/package.json" ]]; then
741
+ local node_dir="${frontend_dir:-.}"
742
+ cat >> .github/workflows/nightly.yml << EOF
743
+
744
+ - name: Set up Node.js
745
+ uses: actions/setup-node@v4
746
+ with:
747
+ node-version: '20'
748
+
749
+ - name: Install Node dependencies
750
+ run: cd $node_dir && npm ci
751
+
752
+ - name: Node tests
753
+ run: cd $node_dir && npm test 2>/dev/null || true
754
+ continue-on-error: true
755
+ EOF
756
+ fi
757
+
758
+ # Add PRD tests
759
+ cat >> .github/workflows/nightly.yml << 'EOF'
760
+
761
+ - name: Run PRD tests
762
+ if: hashFiles('.ralph/prd.json') != ''
763
+ run: npx agentic-loop test prd 2>/dev/null || true
764
+ continue-on-error: true
765
+
766
+ notify:
767
+ needs: test
768
+ runs-on: ubuntu-latest
769
+ if: failure()
770
+ steps:
771
+ - name: Notify on failure
772
+ run: echo "Nightly tests failed!"
773
+ EOF
774
+ }
@@ -3,18 +3,27 @@
3
3
  # lint.sh - Lint and auto-fix verification module for ralph
4
4
 
5
5
  # Auto-fix lint issues before running checks
6
+ # Usage: run_auto_fix [story_type]
6
7
  run_auto_fix() {
8
+ local story_type="${1:-general}"
7
9
  echo " Auto-fixing lint issues..."
8
10
 
9
- # Python: ruff fix (auto-fix what we can)
10
- if command -v ruff &>/dev/null; then
11
- ruff check --fix . 2>/dev/null || true
11
+ # Python: ruff fix (skip for frontend-only stories)
12
+ if [[ "$story_type" != "frontend" ]]; then
13
+ if command -v ruff &>/dev/null; then
14
+ ruff check --fix . >/dev/null 2>&1 || true
15
+ fi
16
+ fi
17
+
18
+ # Skip JS/TS auto-fix for backend stories
19
+ if [[ "$story_type" == "backend" ]]; then
20
+ return 0
12
21
  fi
13
22
 
14
- # JavaScript/TypeScript: eslint fix (root)
23
+ # JavaScript/TypeScript: eslint fix (root) - suppress all output
15
24
  if [[ -f "package.json" ]] && command -v npx &>/dev/null; then
16
25
  if grep -q '"eslint"' package.json 2>/dev/null || [[ -f ".eslintrc.js" ]] || [[ -f "eslint.config.js" ]]; then
17
- npx eslint --fix . 2>/dev/null || true
26
+ npx eslint --fix . >/dev/null 2>&1 || true
18
27
  fi
19
28
  fi
20
29
 
@@ -25,25 +34,25 @@ run_auto_fix() {
25
34
  while IFS= read -r fe_dir; do
26
35
  [[ -z "$fe_dir" ]] && continue
27
36
  [[ ! -f "$fe_dir/package.json" ]] && continue
28
- # ESLint fix
37
+ # ESLint fix - suppress output
29
38
  if grep -q '"eslint"' "$fe_dir/package.json" 2>/dev/null; then
30
- (cd "$fe_dir" && npx eslint --fix . 2>/dev/null) || true
39
+ (cd "$fe_dir" && npx eslint --fix . >/dev/null 2>&1) || true
31
40
  fi
32
41
 
33
42
  # Next.js lint fix
34
43
  if grep -q '"next"' "$fe_dir/package.json" 2>/dev/null; then
35
- (cd "$fe_dir" && npx next lint --fix 2>/dev/null) || true
44
+ (cd "$fe_dir" && npx next lint --fix >/dev/null 2>&1) || true
36
45
  fi
37
46
 
38
47
  # Prettier fix (common in frontend)
39
48
  if grep -q '"prettier"' "$fe_dir/package.json" 2>/dev/null; then
40
- (cd "$fe_dir" && npx prettier --write . 2>/dev/null) || true
49
+ (cd "$fe_dir" && npx prettier --write . >/dev/null 2>&1) || true
41
50
  fi
42
51
  done <<< "$fe_dirs"
43
52
 
44
53
  # Prettier fix (root - for non-monorepo)
45
54
  if [[ -f "package.json" ]] && grep -q '"prettier"' package.json 2>/dev/null; then
46
- npx prettier --write . 2>/dev/null || true
55
+ npx prettier --write . >/dev/null 2>&1 || true
47
56
  fi
48
57
  }
49
58
 
@@ -461,7 +470,7 @@ run_configured_checks() {
461
470
  local story_type="${1:-general}"
462
471
 
463
472
  # ALWAYS run auto-fix (harmless, just formats code)
464
- run_auto_fix
473
+ run_auto_fix "$story_type"
465
474
 
466
475
  # Lint check - skip irrelevant checks based on story type
467
476
  if check_enabled "lint"; then
@@ -223,6 +223,57 @@ run_unit_tests() {
223
223
  fi
224
224
  }
225
225
 
226
+ # Expand config placeholders in a string
227
+ # Usage: expand_config_vars "curl {config.urls.backend}/api"
228
+ # Expands: {config.urls.backend}, {config.urls.frontend}, {config.directories.*}
229
+ _expand_config_vars() {
230
+ local input="$1"
231
+ local config="$RALPH_DIR/config.json"
232
+
233
+ # No config file, return as-is
234
+ [[ ! -f "$config" ]] && echo "$input" && return
235
+
236
+ local result="$input"
237
+
238
+ # Expand {config.urls.backend}
239
+ if [[ "$result" == *"{config.urls.backend}"* ]]; then
240
+ local backend_url
241
+ backend_url=$(jq -r '.urls.backend // .api.baseUrl // empty' "$config" 2>/dev/null)
242
+ if [[ -n "$backend_url" ]]; then
243
+ result="${result//\{config.urls.backend\}/$backend_url}"
244
+ fi
245
+ fi
246
+
247
+ # Expand {config.urls.frontend}
248
+ if [[ "$result" == *"{config.urls.frontend}"* ]]; then
249
+ local frontend_url
250
+ frontend_url=$(jq -r '.urls.frontend // .testUrlBase // empty' "$config" 2>/dev/null)
251
+ if [[ -n "$frontend_url" ]]; then
252
+ result="${result//\{config.urls.frontend\}/$frontend_url}"
253
+ fi
254
+ fi
255
+
256
+ # Expand {config.directories.backend}
257
+ if [[ "$result" == *"{config.directories.backend}"* ]]; then
258
+ local backend_dir
259
+ backend_dir=$(jq -r '.directories.backend // empty' "$config" 2>/dev/null)
260
+ if [[ -n "$backend_dir" ]]; then
261
+ result="${result//\{config.directories.backend\}/$backend_dir}"
262
+ fi
263
+ fi
264
+
265
+ # Expand {config.directories.frontend}
266
+ if [[ "$result" == *"{config.directories.frontend}"* ]]; then
267
+ local frontend_dir
268
+ frontend_dir=$(jq -r '.directories.frontend // empty' "$config" 2>/dev/null)
269
+ if [[ -n "$frontend_dir" ]]; then
270
+ result="${result//\{config.directories.frontend\}/$frontend_dir}"
271
+ fi
272
+ fi
273
+
274
+ echo "$result"
275
+ }
276
+
226
277
  # Verify PRD acceptance criteria / test steps
227
278
  verify_prd_criteria() {
228
279
  local story="$1"
@@ -247,9 +298,13 @@ verify_prd_criteria() {
247
298
  while IFS= read -r step; do
248
299
  [[ -z "$step" ]] && continue
249
300
 
250
- echo -n " $step... "
301
+ # Expand config placeholders (e.g., {config.urls.backend})
302
+ local expanded_step
303
+ expanded_step=$(_expand_config_vars "$step")
304
+
305
+ echo -n " $expanded_step... "
251
306
 
252
- if safe_exec "$step" "$log_file"; then
307
+ if safe_exec "$expanded_step" "$log_file"; then
253
308
  print_success "passed"
254
309
  else
255
310
  print_error "failed"
@@ -260,7 +315,7 @@ verify_prd_criteria() {
260
315
  # Save failure details for retry context
261
316
  {
262
317
  echo "PRD test step $step_index failed for $story:"
263
- echo " Command: $step"
318
+ echo " Command: $expanded_step"
264
319
  echo " Error output:"
265
320
  tail -30 "$log_file" | sed 's/^/ /'
266
321
  echo ""