thrivekit 2.0.0

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.
Files changed (164) hide show
  1. package/.claude/commands/explain.md +114 -0
  2. package/.claude/commands/idea.md +370 -0
  3. package/.claude/commands/my-dna.md +122 -0
  4. package/.claude/commands/prd.md +286 -0
  5. package/.claude/commands/review.md +167 -0
  6. package/.claude/commands/sign.md +32 -0
  7. package/.claude/commands/styleguide.md +450 -0
  8. package/.claude/commands/tour.md +301 -0
  9. package/.claude/commands/vibe-check.md +116 -0
  10. package/.claude/commands/vibe-help.md +47 -0
  11. package/.claude/commands/vibe-list.md +203 -0
  12. package/.claude/settings.json +75 -0
  13. package/.claude/settings.local.json +12 -0
  14. package/.pre-commit-hooks.yaml +102 -0
  15. package/LICENSE +21 -0
  16. package/README.md +214 -0
  17. package/bin/postinstall.sh +29 -0
  18. package/bin/ralph.sh +171 -0
  19. package/bin/thrivekit.sh +24 -0
  20. package/bin/vibe-check.js +19 -0
  21. package/dist/checks/check-any-types.d.ts +6 -0
  22. package/dist/checks/check-any-types.d.ts.map +1 -0
  23. package/dist/checks/check-any-types.js +73 -0
  24. package/dist/checks/check-any-types.js.map +1 -0
  25. package/dist/checks/check-commented-code.d.ts +6 -0
  26. package/dist/checks/check-commented-code.d.ts.map +1 -0
  27. package/dist/checks/check-commented-code.js +81 -0
  28. package/dist/checks/check-commented-code.js.map +1 -0
  29. package/dist/checks/check-console-error.d.ts +6 -0
  30. package/dist/checks/check-console-error.d.ts.map +1 -0
  31. package/dist/checks/check-console-error.js +41 -0
  32. package/dist/checks/check-console-error.js.map +1 -0
  33. package/dist/checks/check-debug-statements.d.ts +6 -0
  34. package/dist/checks/check-debug-statements.d.ts.map +1 -0
  35. package/dist/checks/check-debug-statements.js +120 -0
  36. package/dist/checks/check-debug-statements.js.map +1 -0
  37. package/dist/checks/check-deep-nesting.d.ts +6 -0
  38. package/dist/checks/check-deep-nesting.d.ts.map +1 -0
  39. package/dist/checks/check-deep-nesting.js +116 -0
  40. package/dist/checks/check-deep-nesting.js.map +1 -0
  41. package/dist/checks/check-docker-platform.d.ts +6 -0
  42. package/dist/checks/check-docker-platform.d.ts.map +1 -0
  43. package/dist/checks/check-docker-platform.js +42 -0
  44. package/dist/checks/check-docker-platform.js.map +1 -0
  45. package/dist/checks/check-dry-violations.d.ts +6 -0
  46. package/dist/checks/check-dry-violations.d.ts.map +1 -0
  47. package/dist/checks/check-dry-violations.js +124 -0
  48. package/dist/checks/check-dry-violations.js.map +1 -0
  49. package/dist/checks/check-empty-catch.d.ts +6 -0
  50. package/dist/checks/check-empty-catch.d.ts.map +1 -0
  51. package/dist/checks/check-empty-catch.js +111 -0
  52. package/dist/checks/check-empty-catch.js.map +1 -0
  53. package/dist/checks/check-function-length.d.ts +6 -0
  54. package/dist/checks/check-function-length.d.ts.map +1 -0
  55. package/dist/checks/check-function-length.js +152 -0
  56. package/dist/checks/check-function-length.js.map +1 -0
  57. package/dist/checks/check-hardcoded-ai-models.d.ts +10 -0
  58. package/dist/checks/check-hardcoded-ai-models.d.ts.map +1 -0
  59. package/dist/checks/check-hardcoded-ai-models.js +102 -0
  60. package/dist/checks/check-hardcoded-ai-models.js.map +1 -0
  61. package/dist/checks/check-hardcoded-urls.d.ts +6 -0
  62. package/dist/checks/check-hardcoded-urls.d.ts.map +1 -0
  63. package/dist/checks/check-hardcoded-urls.js +124 -0
  64. package/dist/checks/check-hardcoded-urls.js.map +1 -0
  65. package/dist/checks/check-magic-numbers.d.ts +6 -0
  66. package/dist/checks/check-magic-numbers.d.ts.map +1 -0
  67. package/dist/checks/check-magic-numbers.js +116 -0
  68. package/dist/checks/check-magic-numbers.js.map +1 -0
  69. package/dist/checks/check-secrets.d.ts +6 -0
  70. package/dist/checks/check-secrets.d.ts.map +1 -0
  71. package/dist/checks/check-secrets.js +138 -0
  72. package/dist/checks/check-secrets.js.map +1 -0
  73. package/dist/checks/check-snake-case-ts.d.ts +6 -0
  74. package/dist/checks/check-snake-case-ts.d.ts.map +1 -0
  75. package/dist/checks/check-snake-case-ts.js +78 -0
  76. package/dist/checks/check-snake-case-ts.js.map +1 -0
  77. package/dist/checks/check-todo-fixme.d.ts +6 -0
  78. package/dist/checks/check-todo-fixme.d.ts.map +1 -0
  79. package/dist/checks/check-todo-fixme.js +41 -0
  80. package/dist/checks/check-todo-fixme.js.map +1 -0
  81. package/dist/checks/check-unsafe-html.d.ts +6 -0
  82. package/dist/checks/check-unsafe-html.d.ts.map +1 -0
  83. package/dist/checks/check-unsafe-html.js +101 -0
  84. package/dist/checks/check-unsafe-html.js.map +1 -0
  85. package/dist/checks/index.d.ts +30 -0
  86. package/dist/checks/index.d.ts.map +1 -0
  87. package/dist/checks/index.js +57 -0
  88. package/dist/checks/index.js.map +1 -0
  89. package/dist/cli.d.ts +13 -0
  90. package/dist/cli.d.ts.map +1 -0
  91. package/dist/cli.js +206 -0
  92. package/dist/cli.js.map +1 -0
  93. package/dist/index.d.ts +9 -0
  94. package/dist/index.d.ts.map +1 -0
  95. package/dist/index.js +10 -0
  96. package/dist/index.js.map +1 -0
  97. package/dist/utils/file-reader.d.ts +24 -0
  98. package/dist/utils/file-reader.d.ts.map +1 -0
  99. package/dist/utils/file-reader.js +140 -0
  100. package/dist/utils/file-reader.js.map +1 -0
  101. package/dist/utils/patterns.d.ts +27 -0
  102. package/dist/utils/patterns.d.ts.map +1 -0
  103. package/dist/utils/patterns.js +84 -0
  104. package/dist/utils/patterns.js.map +1 -0
  105. package/dist/utils/reporters.d.ts +21 -0
  106. package/dist/utils/reporters.d.ts.map +1 -0
  107. package/dist/utils/reporters.js +115 -0
  108. package/dist/utils/reporters.js.map +1 -0
  109. package/dist/utils/types.d.ts +71 -0
  110. package/dist/utils/types.d.ts.map +1 -0
  111. package/dist/utils/types.js +5 -0
  112. package/dist/utils/types.js.map +1 -0
  113. package/package.json +82 -0
  114. package/ralph/api.sh +210 -0
  115. package/ralph/backup.sh +838 -0
  116. package/ralph/browser-verify/README.md +135 -0
  117. package/ralph/browser-verify/verify.ts +450 -0
  118. package/ralph/checks/check-fastapi-responses.py +155 -0
  119. package/ralph/hooks/hooks-config.json +72 -0
  120. package/ralph/hooks/inject-context.sh +44 -0
  121. package/ralph/hooks/install.sh +207 -0
  122. package/ralph/hooks/log-tools.sh +45 -0
  123. package/ralph/hooks/protect-prd.sh +27 -0
  124. package/ralph/hooks/save-learnings.sh +36 -0
  125. package/ralph/hooks/warn-debug.sh +54 -0
  126. package/ralph/hooks/warn-empty-catch.sh +63 -0
  127. package/ralph/hooks/warn-secrets.sh +89 -0
  128. package/ralph/hooks/warn-urls.sh +77 -0
  129. package/ralph/init.sh +388 -0
  130. package/ralph/loop.sh +570 -0
  131. package/ralph/playwright.sh +238 -0
  132. package/ralph/prd.sh +295 -0
  133. package/ralph/setup/feature-tour.sh +155 -0
  134. package/ralph/setup/quick-setup.sh +239 -0
  135. package/ralph/setup/tutorial.sh +159 -0
  136. package/ralph/setup/ui.sh +136 -0
  137. package/ralph/setup.sh +353 -0
  138. package/ralph/signs.sh +150 -0
  139. package/ralph/utils.sh +682 -0
  140. package/ralph/verify/browser.sh +324 -0
  141. package/ralph/verify/lint.sh +363 -0
  142. package/ralph/verify/review.sh +164 -0
  143. package/ralph/verify/tests.sh +81 -0
  144. package/ralph/verify.sh +224 -0
  145. package/templates/PROMPT.md +235 -0
  146. package/templates/config/fullstack.json +86 -0
  147. package/templates/config/go.json +81 -0
  148. package/templates/config/minimal.json +76 -0
  149. package/templates/config/node.json +81 -0
  150. package/templates/config/python.json +81 -0
  151. package/templates/config/rust.json +81 -0
  152. package/templates/examples/CLAUDE-django.md +174 -0
  153. package/templates/examples/CLAUDE-fastapi.md +270 -0
  154. package/templates/examples/CLAUDE-fastmcp.md +352 -0
  155. package/templates/examples/CLAUDE-fullstack.md +256 -0
  156. package/templates/examples/CLAUDE-node.md +246 -0
  157. package/templates/examples/CLAUDE-react.md +138 -0
  158. package/templates/optional/cursorrules.template +147 -0
  159. package/templates/optional/eslint.config.js +34 -0
  160. package/templates/optional/lint-staged.config.js +34 -0
  161. package/templates/optional/ruff.toml +125 -0
  162. package/templates/optional/vibe-check.yml +116 -0
  163. package/templates/optional/vscode-settings.json +127 -0
  164. package/templates/signs.json +46 -0
@@ -0,0 +1,164 @@
1
+ #!/usr/bin/env bash
2
+ # shellcheck shell=bash
3
+ # review.sh - Code review verification module for ralph
4
+
5
+ # Run code review on changes
6
+ run_code_review() {
7
+ local story="$1"
8
+
9
+ # Check if code review is enabled in config
10
+ local review_enabled
11
+ review_enabled=$(get_config '.verification.codeReviewEnabled' "true")
12
+ if [[ "$review_enabled" == "false" ]]; then
13
+ echo " (code review disabled in config, skipping)"
14
+ return 0
15
+ fi
16
+
17
+ # Check if git is available
18
+ if ! command -v git &>/dev/null || [[ ! -d ".git" ]]; then
19
+ echo " (no git repository, skipping)"
20
+ return 0
21
+ fi
22
+
23
+ # Get the diff of uncommitted changes (limit size to prevent memory issues)
24
+ local diff
25
+ local max_diff_lines=2000
26
+ diff=$(git diff HEAD 2>/dev/null | head -n "$max_diff_lines")
27
+
28
+ if [[ -z "$diff" ]]; then
29
+ # No uncommitted changes, check staged
30
+ diff=$(git diff --cached 2>/dev/null | head -n "$max_diff_lines")
31
+ fi
32
+
33
+ if [[ -z "$diff" ]]; then
34
+ echo " (no changes to review)"
35
+ return 0
36
+ fi
37
+
38
+ # Check if diff was truncated
39
+ local full_diff_lines
40
+ full_diff_lines=$(git diff HEAD 2>/dev/null | wc -l)
41
+ if [[ "$full_diff_lines" -gt "$max_diff_lines" ]]; then
42
+ echo " (diff truncated from $full_diff_lines to $max_diff_lines lines)"
43
+ fi
44
+
45
+ # Get story context for the review
46
+ local story_json
47
+ story_json=$(jq --arg id "$story" '.stories[] | select(.id==$id)' "$RALPH_DIR/prd.json" 2>/dev/null)
48
+
49
+ # Build the code review prompt
50
+ local prompt
51
+ prompt=$(cat <<EOF
52
+ You are a senior code reviewer. Review this diff for a story implementation.
53
+
54
+ ## Story Context
55
+ \`\`\`json
56
+ $story_json
57
+ \`\`\`
58
+
59
+ ## Code Diff
60
+ \`\`\`diff
61
+ $diff
62
+ \`\`\`
63
+
64
+ ## Review Checklist
65
+
66
+ Check for these issues:
67
+
68
+ 1. **Security** - SQL injection, XSS, command injection, hardcoded secrets, OWASP top 10
69
+ 2. **Error handling** - Missing try/catch, unhandled promise rejections, silent failures
70
+ 3. **Edge cases** - Null/undefined checks, empty arrays, boundary conditions
71
+ 4. **Code quality** - Unused variables, dead code, overly complex logic
72
+ 5. **Performance** - N+1 queries, unnecessary re-renders, memory leaks
73
+ 6. **Scalability** - Unbounded queries? Missing pagination? Missing indexes? No caching strategy?
74
+ 7. **Accessibility** - Missing ARIA labels, keyboard navigation, color contrast (if frontend)
75
+ 8. **Story compliance** - Does the code actually implement what the story requires?
76
+ 9. **Architecture** - Files in correct directories? Reusing existing components? File size < 300 lines?
77
+ 10. **No duplication** - Creating something that already exists? Reinventing utilities?
78
+
79
+ ## Response Format
80
+
81
+ Respond with ONLY a JSON object:
82
+ {
83
+ "pass": true/false,
84
+ "issues": [
85
+ {
86
+ "severity": "critical|warning|info",
87
+ "category": "security|error-handling|edge-case|quality|performance|scalability|a11y|architecture|compliance",
88
+ "file": "path/to/file",
89
+ "line": 123,
90
+ "message": "Description of the issue",
91
+ "suggestion": "How to fix it"
92
+ }
93
+ ],
94
+ "summary": "Brief overall assessment"
95
+ }
96
+
97
+ Only fail (pass: false) for critical or multiple warning-level issues.
98
+ EOF
99
+ )
100
+
101
+ echo " Reviewing changes..."
102
+
103
+ local result
104
+ # Timeout for code review (defined in utils.sh)
105
+ result=$(echo "$prompt" | run_with_timeout "$CODE_REVIEW_TIMEOUT_SECONDS" claude -p --dangerously-skip-permissions 2>/dev/null) || {
106
+ print_warning " Code review skipped (Claude unavailable or timed out)"
107
+ return 0
108
+ }
109
+
110
+ # Save review result
111
+ mkdir -p "$RALPH_DIR/reviews"
112
+ echo "$result" > "$RALPH_DIR/reviews/${story}-review.json"
113
+
114
+ # Extract JSON from markdown code blocks if present
115
+ local json_result
116
+ if echo "$result" | grep -q '```json'; then
117
+ json_result=$(echo "$result" | sed -n '/```json/,/```/p' | sed '1d;$d')
118
+ elif echo "$result" | grep -q '```'; then
119
+ json_result=$(echo "$result" | sed -n '/```/,/```/p' | sed '1d;$d')
120
+ else
121
+ json_result="$result"
122
+ fi
123
+
124
+ # Check if result is valid JSON
125
+ if ! echo "$json_result" | jq -e . >/dev/null 2>&1; then
126
+ print_warning " Code review returned invalid response, skipping"
127
+ return 0
128
+ fi
129
+
130
+ local passed
131
+ passed=$(echo "$json_result" | jq -r '.pass // true' 2>/dev/null)
132
+
133
+ # Handle empty/null result
134
+ if [[ -z "$passed" || "$passed" == "null" ]]; then
135
+ print_warning " Code review inconclusive, continuing"
136
+ return 0
137
+ fi
138
+
139
+ if [[ "$passed" == "true" ]]; then
140
+ print_success "passed"
141
+
142
+ # Show any warnings/info even on pass
143
+ local warnings
144
+ warnings=$(echo "$json_result" | jq -r '.issues[] | select(.severity != "critical") | " [\(.severity)] \(.message)"' 2>/dev/null)
145
+ if [[ -n "$warnings" ]]; then
146
+ echo " Notes:"
147
+ echo "$warnings"
148
+ fi
149
+ return 0
150
+ else
151
+ print_error "failed"
152
+ echo ""
153
+
154
+ # Show all issues
155
+ echo " Issues found:"
156
+ echo "$json_result" | jq -r '.issues[] | " [\(.severity)] \(.category): \(.message)"' 2>/dev/null
157
+ echo ""
158
+ echo " Summary: $(echo "$json_result" | jq -r '.summary // "Review failed"' 2>/dev/null)"
159
+
160
+ # Save for failure context
161
+ echo "$json_result" > "$RALPH_DIR/last_review_failure.json"
162
+ return 1
163
+ fi
164
+ }
@@ -0,0 +1,81 @@
1
+ #!/usr/bin/env bash
2
+ # shellcheck shell=bash
3
+ # tests.sh - Test verification module for ralph
4
+
5
+ # Run unit tests
6
+ run_unit_tests() {
7
+ local log_file
8
+ log_file=$(create_temp_file ".log") || return 1
9
+
10
+ # Try common test commands
11
+ local test_cmd
12
+ test_cmd=$(get_config '.checks.test' "")
13
+
14
+ if [[ -z "$test_cmd" ]]; then
15
+ # Auto-detect test command
16
+ if [[ -f "package.json" ]] && grep -q '"test"' package.json; then
17
+ test_cmd="npm test"
18
+ elif [[ -f "pytest.ini" ]] || [[ -f "pyproject.toml" ]]; then
19
+ test_cmd="pytest"
20
+ elif [[ -f "Cargo.toml" ]]; then
21
+ test_cmd="cargo test"
22
+ elif [[ -f "go.mod" ]]; then
23
+ test_cmd="go test ./..."
24
+ else
25
+ echo " (no test command found, skipping)"
26
+ return 0
27
+ fi
28
+ fi
29
+
30
+ echo -n " Running: $test_cmd... "
31
+
32
+ if safe_exec "$test_cmd" "$log_file"; then
33
+ print_success "passed"
34
+ rm -f "$log_file"
35
+ return 0
36
+ else
37
+ print_error "failed"
38
+ echo ""
39
+ echo " Output (last $MAX_LOG_LINES lines):"
40
+ tail -"$MAX_LOG_LINES" "$log_file" | sed 's/^/ /'
41
+ cp "$log_file" "$RALPH_DIR/last_test_failure.log"
42
+ rm -f "$log_file"
43
+ return 1
44
+ fi
45
+ }
46
+
47
+ # Verify PRD acceptance criteria / test steps
48
+ verify_prd_criteria() {
49
+ local story="$1"
50
+
51
+ local test_steps
52
+ test_steps=$(jq -r --arg id "$story" '.stories[] | select(.id==$id) | .testSteps[]?' "$RALPH_DIR/prd.json" 2>/dev/null)
53
+
54
+ if [[ -z "$test_steps" ]]; then
55
+ echo " (no testSteps defined)"
56
+ return 0
57
+ fi
58
+
59
+ local failed=0
60
+ local log_file
61
+ log_file=$(create_temp_file ".log") || return 1
62
+
63
+ while IFS= read -r step; do
64
+ [[ -z "$step" ]] && continue
65
+
66
+ echo -n " $step... "
67
+
68
+ if safe_exec "$step" "$log_file"; then
69
+ print_success "passed"
70
+ else
71
+ print_error "failed"
72
+ echo ""
73
+ echo " Output:"
74
+ tail -"$MAX_OUTPUT_PREVIEW_LINES" "$log_file" | sed 's/^/ /'
75
+ failed=1
76
+ fi
77
+ done <<< "$test_steps"
78
+
79
+ rm -f "$log_file"
80
+ return $failed
81
+ }
@@ -0,0 +1,224 @@
1
+ #!/usr/bin/env bash
2
+ # shellcheck shell=bash
3
+ # verify.sh - Full UAT verification pipeline for ralph
4
+ #
5
+ # This file orchestrates the verification pipeline by sourcing modular components:
6
+ # - verify/review.sh - Code review logic
7
+ # - verify/lint.sh - Auto-fix + lint checks
8
+ # - verify/tests.sh - Unit tests + PRD criteria
9
+ # - verify/browser.sh - Browser validation
10
+
11
+ # Validate required source files exist before sourcing
12
+ if [[ ! -f "$RALPH_LIB/playwright.sh" ]]; then
13
+ echo "Error: Missing $RALPH_LIB/playwright.sh" >&2
14
+ exit 1
15
+ fi
16
+ if [[ ! -f "$RALPH_LIB/api.sh" ]]; then
17
+ echo "Error: Missing $RALPH_LIB/api.sh" >&2
18
+ exit 1
19
+ fi
20
+
21
+ # Source verification modules
22
+ source "$RALPH_LIB/playwright.sh"
23
+ source "$RALPH_LIB/api.sh"
24
+
25
+ # Determine the directory where this script lives
26
+ VERIFY_DIR="${RALPH_LIB:-$(dirname "${BASH_SOURCE[0]}")}"
27
+
28
+ # Source modular verification components
29
+ source "$VERIFY_DIR/verify/review.sh"
30
+ source "$VERIFY_DIR/verify/lint.sh"
31
+ source "$VERIFY_DIR/verify/tests.sh"
32
+ source "$VERIFY_DIR/verify/browser.sh"
33
+
34
+ run_verification() {
35
+ local story="$1"
36
+
37
+ echo ""
38
+ print_info "=== Verification: $story ==="
39
+ echo ""
40
+
41
+ # Determine story type
42
+ local story_type
43
+ story_type=$(jq -r --arg id "$story" '.stories[] | select(.id==$id) | .type // "frontend"' "$RALPH_DIR/prd.json" 2>/dev/null)
44
+
45
+ local has_test_url
46
+ has_test_url=$(jq -r --arg id "$story" '.stories[] | select(.id==$id) | .testUrl // empty' "$RALPH_DIR/prd.json" 2>/dev/null)
47
+
48
+ local has_api_endpoints
49
+ has_api_endpoints=$(jq -r --arg id "$story" '.stories[] | select(.id==$id) | .apiEndpoints[0] // empty' "$RALPH_DIR/prd.json" 2>/dev/null)
50
+
51
+ # Auto-detect type if not specified
52
+ if [[ -n "$has_api_endpoints" && -z "$has_test_url" ]]; then
53
+ story_type="backend"
54
+ fi
55
+
56
+ local failed=0
57
+
58
+ # ========================================
59
+ # STEP 1: Code review (catch issues before running tests)
60
+ # ========================================
61
+ echo " [1/6] Running code review..."
62
+ if ! run_code_review "$story"; then
63
+ failed=1
64
+ fi
65
+
66
+ # ========================================
67
+ # STEP 2: Run configured checks (lint, build, etc.)
68
+ # ========================================
69
+ if [[ $failed -eq 0 ]]; then
70
+ echo ""
71
+ echo " [2/6] Running configured checks..."
72
+ if ! run_configured_checks; then
73
+ failed=1
74
+ fi
75
+ fi
76
+
77
+ # ========================================
78
+ # STEP 3: Run unit tests
79
+ # ========================================
80
+ if [[ $failed -eq 0 ]]; then
81
+ echo ""
82
+ echo " [3/6] Running unit tests..."
83
+ if ! run_unit_tests; then
84
+ failed=1
85
+ fi
86
+ fi
87
+
88
+ # ========================================
89
+ # STEP 4: Run Playwright tests (frontend) or API tests (backend)
90
+ # ========================================
91
+ if [[ $failed -eq 0 ]]; then
92
+ echo ""
93
+ if [[ "$story_type" == "backend" ]]; then
94
+ echo " [4/6] Running API tests..."
95
+ if ! run_api_validation "$story"; then
96
+ failed=1
97
+ elif ! run_api_error_tests "$story"; then
98
+ # Only run error tests if validation passed
99
+ failed=1
100
+ fi
101
+ else
102
+ echo " [4/6] Running Playwright tests..."
103
+ if ! run_playwright_tests "$story"; then
104
+ failed=1
105
+ fi
106
+ fi
107
+ fi
108
+
109
+ # ========================================
110
+ # STEP 5: Run browser validation (frontend) or API validation (backend)
111
+ # ========================================
112
+ if [[ $failed -eq 0 ]]; then
113
+ echo ""
114
+ if [[ "$story_type" == "backend" ]]; then
115
+ echo " [5/6] Running API validation..."
116
+ if ! run_api_tests "$story"; then
117
+ failed=1
118
+ fi
119
+ else
120
+ echo " [5/6] Running browser validation..."
121
+ if ! run_browser_validation "$story"; then
122
+ failed=1
123
+ fi
124
+ fi
125
+ fi
126
+
127
+ # ========================================
128
+ # STEP 6: Run PRD test steps
129
+ # ========================================
130
+ if [[ $failed -eq 0 ]]; then
131
+ echo ""
132
+ echo " [6/6] Running PRD test steps..."
133
+ if ! verify_prd_criteria "$story"; then
134
+ failed=1
135
+ fi
136
+ fi
137
+
138
+ # ========================================
139
+ # Final result
140
+ # ========================================
141
+ echo ""
142
+ if [[ $failed -eq 0 ]]; then
143
+ print_success "=== All verification passed ==="
144
+ return 0
145
+ else
146
+ print_error "=== Verification failed ==="
147
+ # Save failure context for next iteration
148
+ save_failure_context "$story"
149
+ return 1
150
+ fi
151
+ }
152
+
153
+ # Save failure context for next iteration
154
+ save_failure_context() {
155
+ local story="$1"
156
+
157
+ local context_file="$RALPH_DIR/last_failure.txt"
158
+
159
+ {
160
+ echo "=== Failure Context for $story ==="
161
+ echo "Timestamp: $(date -Iseconds 2>/dev/null || date)"
162
+ echo ""
163
+
164
+ if [[ -f "$RALPH_DIR/last_migration_failure.log" ]]; then
165
+ echo "--- Migration Failure ---"
166
+ echo "Database migrations failed. Fix the migration or the code causing it:"
167
+ tail -50 "$RALPH_DIR/last_migration_failure.log"
168
+ echo ""
169
+ fi
170
+
171
+ if [[ -f "$RALPH_DIR/last_review_failure.json" ]]; then
172
+ echo "--- Code Review Failure ---"
173
+ echo "Issues found by code review:"
174
+ jq -r '.issues[] | "- [\(.severity)] \(.category): \(.message)\n File: \(.file // "unknown"):\(.line // "?")\n Fix: \(.suggestion // "See above")"' "$RALPH_DIR/last_review_failure.json" 2>/dev/null
175
+ echo ""
176
+ fi
177
+
178
+ if [[ -f "$RALPH_DIR/last_test_failure.log" ]]; then
179
+ echo "--- Test Failure ---"
180
+ tail -50 "$RALPH_DIR/last_test_failure.log"
181
+ echo ""
182
+ fi
183
+
184
+ if [[ -f "$RALPH_DIR/last_playwright_failure.log" ]]; then
185
+ echo "--- Playwright Failure ---"
186
+ tail -50 "$RALPH_DIR/last_playwright_failure.log"
187
+ echo ""
188
+ fi
189
+
190
+ if [[ -f "$RALPH_DIR/last_browser_failure.json" ]]; then
191
+ echo "--- Browser Validation Failure ---"
192
+ jq -r '"Errors: " + (.errors | join(", "))' "$RALPH_DIR/last_browser_failure.json" 2>/dev/null
193
+ jq -r '"Console errors: " + (.consoleErrors | join(", "))' "$RALPH_DIR/last_browser_failure.json" 2>/dev/null
194
+ jq -r '"Missing elements: " + (.elementsMissing | join(", "))' "$RALPH_DIR/last_browser_failure.json" 2>/dev/null
195
+ echo ""
196
+ fi
197
+
198
+ if [[ -f "$RALPH_DIR/last_precommit_failure.log" ]]; then
199
+ echo "--- Pre-commit / Lint Failure ---"
200
+ echo "Fix these errors before the story can be completed:"
201
+ echo ""
202
+ # Extract actual error lines (not warnings-only or file modification messages)
203
+ grep -E "^error:|: error:|Error:|SyntaxError|✖ [0-9]+ problems|^[^:]+:[0-9]+:[0-9]+: [EF][0-9]+" "$RALPH_DIR/last_precommit_failure.log" | head -30
204
+ # If no errors shown, show the full log tail
205
+ if ! grep -qE "^error:|: error:|Error:|SyntaxError|✖ [0-9]+ problems" "$RALPH_DIR/last_precommit_failure.log"; then
206
+ echo "(Full output):"
207
+ tail -40 "$RALPH_DIR/last_precommit_failure.log"
208
+ fi
209
+ echo ""
210
+ fi
211
+
212
+ if [[ -f "$RALPH_DIR/last_fastapi_response_check.log" ]]; then
213
+ echo "--- FastAPI Response Model Failure ---"
214
+ echo "Add Pydantic response_model to these endpoints for proper Swagger docs:"
215
+ echo ""
216
+ cat "$RALPH_DIR/last_fastapi_response_check.log"
217
+ echo ""
218
+ echo "Fix by adding response_model parameter or return type annotation:"
219
+ echo ' @router.get("/items", response_model=list[ItemSchema])'
220
+ echo " async def get_items() -> list[ItemSchema]:"
221
+ echo ""
222
+ fi
223
+ } > "$context_file"
224
+ }
@@ -0,0 +1,235 @@
1
+ # Development Session
2
+
3
+ You are an autonomous coding agent working on a feature using the Ralph workflow.
4
+
5
+ ## Session Startup Checklist
6
+
7
+ Before writing any code, verify:
8
+ 1. Run `pwd` to confirm you're in the correct directory
9
+ 2. Read `.ralph/progress.txt` for recent session history
10
+ 3. Run `git status` to check for uncommitted work
11
+ 4. Review the current story details below
12
+
13
+ ## Your Task
14
+
15
+ For each story, you must:
16
+
17
+ ### 1. Write Tests First
18
+
19
+ **For frontend stories:**
20
+ - Write a Playwright test that validates the acceptance criteria
21
+ - Include tests for error handling (API fails, validation errors)
22
+ - Include tests for empty/loading states
23
+ - Include accessibility checks (axe-core)
24
+ - Include mobile viewport test (375px)
25
+
26
+ **For backend stories:**
27
+ - Write unit tests for the business logic
28
+ - Write API tests that validate all endpoints
29
+ - Test error responses (400, 401, 500)
30
+ - Test validation rules
31
+
32
+ ### 2. Implement the Feature
33
+
34
+ - Write code to make all tests pass
35
+ - Follow existing patterns in the codebase
36
+ - Handle ALL error cases defined in the story
37
+ - Implement loading states for async operations
38
+
39
+ ### 3. Verify It Actually Works
40
+
41
+ **Do NOT say you're done until:**
42
+ - All unit tests pass
43
+ - All Playwright tests pass
44
+ - You've opened the browser via MCP and visually verified
45
+ - Console has no errors
46
+ - It works on mobile (375px viewport)
47
+ - Error states are handled gracefully
48
+
49
+ ## Rules
50
+
51
+ 1. **Focus**: Implement ONLY the current story. Do not work on other stories.
52
+ 2. **Test first**: Write failing tests before implementation when possible.
53
+ 3. **Test frequently**: Run tests after each significant change.
54
+ 4. **Error handling is required**: Every story defines error cases - implement them all.
55
+ 5. **Verification**: Never complete until browser validation passes.
56
+ 6. **NEVER edit prd.json**: Do NOT modify `.ralph/prd.json`. Ralph handles story completion automatically after verification. You only write code and tests.
57
+ 7. **Update notes**: After completing work, log what you did in `.ralph/progress.txt` including files created/modified and key decisions made. This helps the next session.
58
+
59
+ ## Verification Checklist
60
+
61
+ Before considering any story complete:
62
+
63
+ ### Code
64
+ - [ ] All acceptance criteria are met
65
+ - [ ] All error handling from story is implemented
66
+ - [ ] Loading states implemented (if frontend)
67
+ - [ ] Validation implemented (if backend)
68
+ - [ ] TypeScript compiles without errors
69
+
70
+ ### Tests
71
+ - [ ] Unit tests written and passing
72
+ - [ ] Playwright test written and passing (frontend)
73
+ - [ ] API tests written and passing (backend)
74
+ - [ ] Error cases tested
75
+ - [ ] Edge cases tested (empty state, etc.)
76
+
77
+ ### Browser/API Validation
78
+ - [ ] Browser check passes (frontend) - no console errors
79
+ - [ ] Mobile viewport works (375px)
80
+ - [ ] Accessibility passes (can Tab through, focus visible)
81
+ - [ ] API returns correct responses (backend)
82
+
83
+ ### Documentation
84
+ - [ ] Updated `.ralph/progress.txt` with files created/modified
85
+ - [ ] Noted any key decisions or context for next story
86
+
87
+ ### Quality
88
+ - [ ] Linting passes
89
+ - [ ] Existing tests still pass
90
+
91
+ ## If Verification Fails
92
+
93
+ If any check fails:
94
+ 1. Read the error message carefully
95
+ 2. Fix the issue
96
+ 3. Re-run verification
97
+ 4. Iterate until ALL checks pass
98
+
99
+ Do NOT give up. Keep iterating until it works.
100
+
101
+ ## If Blocked
102
+
103
+ If you encounter a blocker you cannot resolve:
104
+ 1. Document the issue in `.ralph/progress.txt`
105
+ 2. Note what you tried and why it didn't work
106
+ 3. Suggest potential solutions for the next session
107
+ 4. Do NOT mark the story as passing
108
+
109
+ ## Code Quality Standards
110
+
111
+ ### Core Principles
112
+ - **Readability First**: Code is read more than written. Prioritize clarity.
113
+ - **KISS**: Keep it simple. Avoid over-engineering.
114
+ - **DRY**: Don't repeat yourself. Extract reusable logic.
115
+ - **YAGNI**: Don't build features you don't need yet.
116
+
117
+ ### Naming Conventions
118
+ - Variables: descriptive camelCase (`userProfile`, `isLoading`, `marketSearchQuery`)
119
+ - Functions: verb-noun pattern (`fetchUserData`, `validateInput`, `handleSubmit`)
120
+ - Components: PascalCase (`UserProfile`, `MarketCard`)
121
+ - Constants: SCREAMING_SNAKE_CASE (`MAX_RETRIES`, `API_BASE_URL`)
122
+
123
+ ### Immutability (CRITICAL)
124
+ Always use spread operators. Never mutate directly:
125
+ ```typescript
126
+ // ❌ Bad - mutation
127
+ user.name = 'new name';
128
+ items.push(newItem);
129
+
130
+ // ✅ Good - immutable
131
+ const updatedUser = { ...user, name: 'new name' };
132
+ const updatedItems = [...items, newItem];
133
+ ```
134
+
135
+ ### Error Handling
136
+ Every async operation needs proper error handling:
137
+ ```typescript
138
+ // ✅ Good
139
+ try {
140
+ const data = await fetchData();
141
+ return { success: true, data };
142
+ } catch (error) {
143
+ console.error('Failed to fetch data:', error);
144
+ return { success: false, error: error.message };
145
+ }
146
+ ```
147
+
148
+ ### Type Safety
149
+ - Use TypeScript interfaces for all data shapes
150
+ - Never use `any` - use `unknown` if type is truly unknown
151
+ - Define return types for functions
152
+
153
+ ### Functions
154
+ - Max 50 lines per function (split if longer)
155
+ - Single responsibility - one function does one thing
156
+ - Early returns for guard clauses
157
+
158
+ ### React Specific
159
+ - Functional components with typed props
160
+ - Custom hooks for reusable stateful logic
161
+ - Use `prev =>` for state updates that depend on previous state
162
+ - Avoid excessive ternaries - extract to variables or early returns
163
+
164
+ ### General
165
+ - Follow existing code patterns in the codebase
166
+ - Handle ALL error cases defined in the story
167
+ - Implement loading states for async operations
168
+ - Use meaningful variable and function names
169
+ - Add data-testid attributes for Playwright
170
+
171
+ ## Architecture Rules
172
+
173
+ - **Put files in the right place**: Follow the directories specified in the PRD
174
+ - **Reuse existing code**: Check for existing components/utils before creating new ones
175
+ - **Don't duplicate**: If something exists, import and use it
176
+ - **Max 300 lines per file**: Split large files into smaller, focused modules
177
+ - **Scripts in scripts/**: Shell scripts and CLI tools go in scripts/ or bin/
178
+ - **Docs in docs/**: Documentation files go in docs/
179
+ - **Single responsibility**: Each file/function does one thing well
180
+
181
+ ## Scalability Rules
182
+
183
+ For list/query endpoints:
184
+ - **Always paginate**: Never return unbounded arrays
185
+ - **Use cursor-based pagination**: When specified in the PRD
186
+ - **Add database indexes**: For frequently queried fields
187
+ - **Implement caching**: As specified in the PRD (TTL, invalidation)
188
+ - **Eager load relationships**: To avoid N+1 queries
189
+
190
+ For all endpoints:
191
+ - **Rate limit public endpoints**: As specified in the PRD
192
+ - **Set sensible limits**: Max page size, max request body size
193
+ - **Batch operations**: Use bulk inserts when creating many records
194
+
195
+ ## AI/LLM Configuration
196
+
197
+ **NEVER hardcode AI model names, API keys, or endpoints.** Always use environment variables or settings.
198
+
199
+ ```python
200
+ # ❌ Bad - hardcoded model
201
+ model = "gpt-4"
202
+ client = OpenAI(api_key="sk-...")
203
+
204
+ # ✅ Good - from environment/settings
205
+ model = os.environ.get("OPENAI_MODEL", "gpt-4")
206
+ client = OpenAI() # Uses OPENAI_API_KEY env var
207
+ ```
208
+
209
+ ```python
210
+ # ❌ Bad - hardcoded in code
211
+ response = openai.chat.completions.create(
212
+ model="gpt-4-turbo",
213
+ max_tokens=4096,
214
+ )
215
+
216
+ # ✅ Good - from settings/config
217
+ from django.conf import settings
218
+ response = openai.chat.completions.create(
219
+ model=settings.AI_MODEL,
220
+ max_tokens=settings.AI_MAX_TOKENS,
221
+ )
222
+ ```
223
+
224
+ If the project has an AI gateway or wrapper, use it:
225
+ ```python
226
+ # ✅ Best - use project's AI abstraction
227
+ from myapp.ai import get_completion
228
+ response = get_completion(prompt)
229
+ ```
230
+
231
+ ---
232
+
233
+ ## Current Story
234
+
235
+ (Story details will be injected below by ralph.sh)