agentic-loop 3.4.7 → 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
+ }
@@ -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 ""