agentic-loop 1.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.
- package/.claude/commands/explain.md +114 -0
- package/.claude/commands/idea.md +398 -0
- package/.claude/commands/my-dna.md +122 -0
- package/.claude/commands/prd.md +286 -0
- package/.claude/commands/review.md +167 -0
- package/.claude/commands/sign.md +32 -0
- package/.claude/commands/styleguide.md +450 -0
- package/.claude/commands/tour.md +301 -0
- package/.claude/commands/vibe-check.md +116 -0
- package/.claude/commands/vibe-help.md +47 -0
- package/.claude/commands/vibe-list.md +203 -0
- package/.pre-commit-hooks.yaml +102 -0
- package/LICENSE +21 -0
- package/README.md +238 -0
- package/bin/agentic-loop.sh +24 -0
- package/bin/postinstall.sh +29 -0
- package/bin/ralph.sh +171 -0
- package/bin/vibe-check.js +19 -0
- package/dist/checks/check-any-types.d.ts +6 -0
- package/dist/checks/check-any-types.d.ts.map +1 -0
- package/dist/checks/check-any-types.js +73 -0
- package/dist/checks/check-any-types.js.map +1 -0
- package/dist/checks/check-commented-code.d.ts +6 -0
- package/dist/checks/check-commented-code.d.ts.map +1 -0
- package/dist/checks/check-commented-code.js +81 -0
- package/dist/checks/check-commented-code.js.map +1 -0
- package/dist/checks/check-console-error.d.ts +6 -0
- package/dist/checks/check-console-error.d.ts.map +1 -0
- package/dist/checks/check-console-error.js +41 -0
- package/dist/checks/check-console-error.js.map +1 -0
- package/dist/checks/check-debug-statements.d.ts +6 -0
- package/dist/checks/check-debug-statements.d.ts.map +1 -0
- package/dist/checks/check-debug-statements.js +120 -0
- package/dist/checks/check-debug-statements.js.map +1 -0
- package/dist/checks/check-deep-nesting.d.ts +6 -0
- package/dist/checks/check-deep-nesting.d.ts.map +1 -0
- package/dist/checks/check-deep-nesting.js +116 -0
- package/dist/checks/check-deep-nesting.js.map +1 -0
- package/dist/checks/check-docker-platform.d.ts +6 -0
- package/dist/checks/check-docker-platform.d.ts.map +1 -0
- package/dist/checks/check-docker-platform.js +42 -0
- package/dist/checks/check-docker-platform.js.map +1 -0
- package/dist/checks/check-dry-violations.d.ts +6 -0
- package/dist/checks/check-dry-violations.d.ts.map +1 -0
- package/dist/checks/check-dry-violations.js +124 -0
- package/dist/checks/check-dry-violations.js.map +1 -0
- package/dist/checks/check-empty-catch.d.ts +6 -0
- package/dist/checks/check-empty-catch.d.ts.map +1 -0
- package/dist/checks/check-empty-catch.js +111 -0
- package/dist/checks/check-empty-catch.js.map +1 -0
- package/dist/checks/check-function-length.d.ts +6 -0
- package/dist/checks/check-function-length.d.ts.map +1 -0
- package/dist/checks/check-function-length.js +152 -0
- package/dist/checks/check-function-length.js.map +1 -0
- package/dist/checks/check-hardcoded-ai-models.d.ts +10 -0
- package/dist/checks/check-hardcoded-ai-models.d.ts.map +1 -0
- package/dist/checks/check-hardcoded-ai-models.js +102 -0
- package/dist/checks/check-hardcoded-ai-models.js.map +1 -0
- package/dist/checks/check-hardcoded-urls.d.ts +6 -0
- package/dist/checks/check-hardcoded-urls.d.ts.map +1 -0
- package/dist/checks/check-hardcoded-urls.js +124 -0
- package/dist/checks/check-hardcoded-urls.js.map +1 -0
- package/dist/checks/check-magic-numbers.d.ts +6 -0
- package/dist/checks/check-magic-numbers.d.ts.map +1 -0
- package/dist/checks/check-magic-numbers.js +116 -0
- package/dist/checks/check-magic-numbers.js.map +1 -0
- package/dist/checks/check-secrets.d.ts +6 -0
- package/dist/checks/check-secrets.d.ts.map +1 -0
- package/dist/checks/check-secrets.js +138 -0
- package/dist/checks/check-secrets.js.map +1 -0
- package/dist/checks/check-snake-case-ts.d.ts +6 -0
- package/dist/checks/check-snake-case-ts.d.ts.map +1 -0
- package/dist/checks/check-snake-case-ts.js +78 -0
- package/dist/checks/check-snake-case-ts.js.map +1 -0
- package/dist/checks/check-todo-fixme.d.ts +6 -0
- package/dist/checks/check-todo-fixme.d.ts.map +1 -0
- package/dist/checks/check-todo-fixme.js +41 -0
- package/dist/checks/check-todo-fixme.js.map +1 -0
- package/dist/checks/check-unsafe-html.d.ts +6 -0
- package/dist/checks/check-unsafe-html.d.ts.map +1 -0
- package/dist/checks/check-unsafe-html.js +101 -0
- package/dist/checks/check-unsafe-html.js.map +1 -0
- package/dist/checks/index.d.ts +30 -0
- package/dist/checks/index.d.ts.map +1 -0
- package/dist/checks/index.js +57 -0
- package/dist/checks/index.js.map +1 -0
- package/dist/cli.d.ts +13 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +208 -0
- package/dist/cli.js.map +1 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +10 -0
- package/dist/index.js.map +1 -0
- package/dist/utils/file-reader.d.ts +24 -0
- package/dist/utils/file-reader.d.ts.map +1 -0
- package/dist/utils/file-reader.js +146 -0
- package/dist/utils/file-reader.js.map +1 -0
- package/dist/utils/patterns.d.ts +27 -0
- package/dist/utils/patterns.d.ts.map +1 -0
- package/dist/utils/patterns.js +84 -0
- package/dist/utils/patterns.js.map +1 -0
- package/dist/utils/reporters.d.ts +21 -0
- package/dist/utils/reporters.d.ts.map +1 -0
- package/dist/utils/reporters.js +115 -0
- package/dist/utils/reporters.js.map +1 -0
- package/dist/utils/types.d.ts +71 -0
- package/dist/utils/types.d.ts.map +1 -0
- package/dist/utils/types.js +5 -0
- package/dist/utils/types.js.map +1 -0
- package/package.json +83 -0
- package/ralph/api.sh +216 -0
- package/ralph/backup.sh +838 -0
- package/ralph/browser-verify/README.md +135 -0
- package/ralph/browser-verify/verify.ts +450 -0
- package/ralph/checks/check-fastapi-responses.py +155 -0
- package/ralph/hooks/hooks-config.json +72 -0
- package/ralph/hooks/inject-context.sh +44 -0
- package/ralph/hooks/install.sh +207 -0
- package/ralph/hooks/log-tools.sh +45 -0
- package/ralph/hooks/protect-prd.sh +27 -0
- package/ralph/hooks/save-learnings.sh +36 -0
- package/ralph/hooks/warn-debug.sh +54 -0
- package/ralph/hooks/warn-empty-catch.sh +63 -0
- package/ralph/hooks/warn-secrets.sh +89 -0
- package/ralph/hooks/warn-urls.sh +77 -0
- package/ralph/init.sh +515 -0
- package/ralph/loop.sh +730 -0
- package/ralph/playwright.sh +238 -0
- package/ralph/prd.sh +295 -0
- package/ralph/setup/feature-tour.sh +155 -0
- package/ralph/setup/quick-setup.sh +239 -0
- package/ralph/setup/tutorial.sh +159 -0
- package/ralph/setup/ui.sh +136 -0
- package/ralph/setup.sh +401 -0
- package/ralph/signs.sh +150 -0
- package/ralph/utils.sh +682 -0
- package/ralph/verify/browser.sh +324 -0
- package/ralph/verify/lint.sh +363 -0
- package/ralph/verify/review.sh +152 -0
- package/ralph/verify/tests.sh +81 -0
- package/ralph/verify.sh +268 -0
- package/templates/PROMPT.md +235 -0
- package/templates/config/fullstack.json +86 -0
- package/templates/config/go.json +81 -0
- package/templates/config/minimal.json +76 -0
- package/templates/config/node.json +81 -0
- package/templates/config/python.json +81 -0
- package/templates/config/rust.json +81 -0
- package/templates/examples/CLAUDE-django.md +174 -0
- package/templates/examples/CLAUDE-fastapi.md +270 -0
- package/templates/examples/CLAUDE-fastmcp.md +352 -0
- package/templates/examples/CLAUDE-fullstack.md +256 -0
- package/templates/examples/CLAUDE-node.md +246 -0
- package/templates/examples/CLAUDE-react.md +138 -0
- package/templates/optional/cursorrules.template +147 -0
- package/templates/optional/eslint.config.js +34 -0
- package/templates/optional/lint-staged.config.js +34 -0
- package/templates/optional/ruff.toml +125 -0
- package/templates/optional/vibe-check.yml +116 -0
- package/templates/optional/vscode-settings.json +127 -0
- package/templates/signs.json +46 -0
|
@@ -0,0 +1,152 @@
|
|
|
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
|
+
IMPORTANT: Output ONLY raw JSON, no markdown formatting, no code blocks, no explanation.
|
|
82
|
+
|
|
83
|
+
{"pass": true/false, "issues": [{"severity": "critical|warning|info", "category": "security|error-handling|edge-case|quality|performance|scalability|a11y|architecture|compliance", "file": "path/to/file", "line": 123, "message": "Description", "suggestion": "Fix"}], "summary": "Brief assessment"}
|
|
84
|
+
|
|
85
|
+
Only fail (pass: false) for critical or multiple warning-level issues.
|
|
86
|
+
EOF
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
echo " Reviewing changes..."
|
|
90
|
+
|
|
91
|
+
local result
|
|
92
|
+
# Timeout for code review (defined in utils.sh)
|
|
93
|
+
result=$(echo "$prompt" | run_with_timeout "$CODE_REVIEW_TIMEOUT_SECONDS" claude -p --dangerously-skip-permissions 2>/dev/null) || {
|
|
94
|
+
print_warning " Code review skipped (Claude unavailable or timed out)"
|
|
95
|
+
return 0
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
# Save review result
|
|
99
|
+
mkdir -p "$RALPH_DIR/reviews"
|
|
100
|
+
echo "$result" > "$RALPH_DIR/reviews/${story}-review.json"
|
|
101
|
+
|
|
102
|
+
# Extract JSON from markdown code blocks if present
|
|
103
|
+
local json_result
|
|
104
|
+
if echo "$result" | grep -q '```json'; then
|
|
105
|
+
json_result=$(echo "$result" | sed -n '/```json/,/```/p' | sed '1d;$d')
|
|
106
|
+
elif echo "$result" | grep -q '```'; then
|
|
107
|
+
json_result=$(echo "$result" | sed -n '/```/,/```/p' | sed '1d;$d')
|
|
108
|
+
else
|
|
109
|
+
json_result="$result"
|
|
110
|
+
fi
|
|
111
|
+
|
|
112
|
+
# Check if result is valid JSON
|
|
113
|
+
if ! echo "$json_result" | jq -e . >/dev/null 2>&1; then
|
|
114
|
+
print_warning " Code review returned invalid response, skipping"
|
|
115
|
+
return 0
|
|
116
|
+
fi
|
|
117
|
+
|
|
118
|
+
local passed
|
|
119
|
+
passed=$(echo "$json_result" | jq -r '.pass // true' 2>/dev/null)
|
|
120
|
+
|
|
121
|
+
# Handle empty/null result
|
|
122
|
+
if [[ -z "$passed" || "$passed" == "null" ]]; then
|
|
123
|
+
print_warning " Code review inconclusive, continuing"
|
|
124
|
+
return 0
|
|
125
|
+
fi
|
|
126
|
+
|
|
127
|
+
if [[ "$passed" == "true" ]]; then
|
|
128
|
+
print_success "passed"
|
|
129
|
+
|
|
130
|
+
# Show any warnings/info even on pass
|
|
131
|
+
local warnings
|
|
132
|
+
warnings=$(echo "$json_result" | jq -r '.issues[] | select(.severity != "critical") | " [\(.severity)] \(.message)"' 2>/dev/null)
|
|
133
|
+
if [[ -n "$warnings" ]]; then
|
|
134
|
+
echo " Notes:"
|
|
135
|
+
echo "$warnings"
|
|
136
|
+
fi
|
|
137
|
+
return 0
|
|
138
|
+
else
|
|
139
|
+
print_error "failed"
|
|
140
|
+
echo ""
|
|
141
|
+
|
|
142
|
+
# Show all issues
|
|
143
|
+
echo " Issues found:"
|
|
144
|
+
echo "$json_result" | jq -r '.issues[] | " [\(.severity)] \(.category): \(.message)"' 2>/dev/null
|
|
145
|
+
echo ""
|
|
146
|
+
echo " Summary: $(echo "$json_result" | jq -r '.summary // "Review failed"' 2>/dev/null)"
|
|
147
|
+
|
|
148
|
+
# Save for failure context
|
|
149
|
+
echo "$json_result" > "$RALPH_DIR/last_review_failure.json"
|
|
150
|
+
return 1
|
|
151
|
+
fi
|
|
152
|
+
}
|
|
@@ -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
|
+
}
|
package/ralph/verify.sh
ADDED
|
@@ -0,0 +1,268 @@
|
|
|
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
|
+
# Clear old failure logs (so smart-skip logic uses fresh state)
|
|
42
|
+
rm -f "$RALPH_DIR/last_precommit_failure.log" \
|
|
43
|
+
"$RALPH_DIR/last_test_failure.log" \
|
|
44
|
+
"$RALPH_DIR/last_review_failure.json" 2>/dev/null
|
|
45
|
+
|
|
46
|
+
# Check for fast mode
|
|
47
|
+
local fast_mode="${RALPH_FAST_MODE:-false}"
|
|
48
|
+
if [[ "$fast_mode" == "true" ]]; then
|
|
49
|
+
echo " (fast mode - skipping code review)"
|
|
50
|
+
fi
|
|
51
|
+
|
|
52
|
+
# Determine story type (single jq call for all story info)
|
|
53
|
+
local story_json
|
|
54
|
+
story_json=$(jq --arg id "$story" '.stories[] | select(.id==$id)' "$RALPH_DIR/prd.json" 2>/dev/null)
|
|
55
|
+
|
|
56
|
+
local story_type has_test_url has_api_endpoints
|
|
57
|
+
story_type=$(echo "$story_json" | jq -r '.type // "frontend"')
|
|
58
|
+
has_test_url=$(echo "$story_json" | jq -r '.testUrl // empty')
|
|
59
|
+
has_api_endpoints=$(echo "$story_json" | jq -r '.apiEndpoints[0] // empty')
|
|
60
|
+
|
|
61
|
+
# Auto-detect type if not specified
|
|
62
|
+
if [[ -n "$has_api_endpoints" && -z "$has_test_url" ]]; then
|
|
63
|
+
story_type="backend"
|
|
64
|
+
fi
|
|
65
|
+
|
|
66
|
+
local failed=0
|
|
67
|
+
local lint_failed=0
|
|
68
|
+
local test_failed=0
|
|
69
|
+
|
|
70
|
+
# ========================================
|
|
71
|
+
# STEP 1: Code review (skip in fast mode or if last failure was lint/test)
|
|
72
|
+
# ========================================
|
|
73
|
+
local skip_review=false
|
|
74
|
+
if [[ "$fast_mode" == "true" ]]; then
|
|
75
|
+
skip_review=true
|
|
76
|
+
elif [[ -f "$RALPH_DIR/last_precommit_failure.log" ]] || [[ -f "$RALPH_DIR/last_test_failure.log" ]]; then
|
|
77
|
+
# Skip review if last failure was lint/test - review won't help
|
|
78
|
+
skip_review=true
|
|
79
|
+
echo " [1/5] Skipping code review (last failure was lint/test)"
|
|
80
|
+
fi
|
|
81
|
+
|
|
82
|
+
if [[ "$skip_review" == "false" ]]; then
|
|
83
|
+
echo " [1/5] Running code review..."
|
|
84
|
+
if ! run_code_review "$story"; then
|
|
85
|
+
failed=1
|
|
86
|
+
fi
|
|
87
|
+
fi
|
|
88
|
+
|
|
89
|
+
# ========================================
|
|
90
|
+
# STEP 2+3: Run lint and tests IN PARALLEL
|
|
91
|
+
# ========================================
|
|
92
|
+
if [[ $failed -eq 0 ]]; then
|
|
93
|
+
echo ""
|
|
94
|
+
echo " [2/5] Running lint + tests (parallel)..."
|
|
95
|
+
|
|
96
|
+
# Create temp files for results
|
|
97
|
+
local lint_log test_log
|
|
98
|
+
lint_log=$(mktemp)
|
|
99
|
+
test_log=$(mktemp)
|
|
100
|
+
|
|
101
|
+
# Run lint in background
|
|
102
|
+
(run_configured_checks > "$lint_log" 2>&1; echo $? > "${lint_log}.exit") &
|
|
103
|
+
local lint_pid=$!
|
|
104
|
+
|
|
105
|
+
# Run tests in background
|
|
106
|
+
(run_unit_tests > "$test_log" 2>&1; echo $? > "${test_log}.exit") &
|
|
107
|
+
local test_pid=$!
|
|
108
|
+
|
|
109
|
+
# Wait for both
|
|
110
|
+
wait $lint_pid 2>/dev/null
|
|
111
|
+
wait $test_pid 2>/dev/null
|
|
112
|
+
|
|
113
|
+
# Check results
|
|
114
|
+
lint_failed=$(cat "${lint_log}.exit" 2>/dev/null || echo "1")
|
|
115
|
+
test_failed=$(cat "${test_log}.exit" 2>/dev/null || echo "1")
|
|
116
|
+
|
|
117
|
+
# Show lint output
|
|
118
|
+
echo " Lint:"
|
|
119
|
+
cat "$lint_log" | sed 's/^/ /'
|
|
120
|
+
|
|
121
|
+
# Show test output
|
|
122
|
+
echo " Tests:"
|
|
123
|
+
cat "$test_log" | sed 's/^/ /'
|
|
124
|
+
|
|
125
|
+
# Cleanup
|
|
126
|
+
rm -f "$lint_log" "${lint_log}.exit" "$test_log" "${test_log}.exit"
|
|
127
|
+
|
|
128
|
+
if [[ "$lint_failed" != "0" ]] || [[ "$test_failed" != "0" ]]; then
|
|
129
|
+
failed=1
|
|
130
|
+
fi
|
|
131
|
+
fi
|
|
132
|
+
|
|
133
|
+
# ========================================
|
|
134
|
+
# STEP 3: Run Playwright tests (frontend) or API tests (backend)
|
|
135
|
+
# ========================================
|
|
136
|
+
if [[ $failed -eq 0 ]]; then
|
|
137
|
+
echo ""
|
|
138
|
+
if [[ "$story_type" == "backend" ]]; then
|
|
139
|
+
echo " [3/5] Running API tests..."
|
|
140
|
+
if ! run_api_validation "$story"; then
|
|
141
|
+
failed=1
|
|
142
|
+
elif ! run_api_error_tests "$story"; then
|
|
143
|
+
failed=1
|
|
144
|
+
fi
|
|
145
|
+
else
|
|
146
|
+
echo " [3/5] Running Playwright tests..."
|
|
147
|
+
if ! run_playwright_tests "$story"; then
|
|
148
|
+
failed=1
|
|
149
|
+
fi
|
|
150
|
+
fi
|
|
151
|
+
fi
|
|
152
|
+
|
|
153
|
+
# ========================================
|
|
154
|
+
# STEP 4: Run browser validation (frontend) or API validation (backend)
|
|
155
|
+
# ========================================
|
|
156
|
+
if [[ $failed -eq 0 ]]; then
|
|
157
|
+
echo ""
|
|
158
|
+
if [[ "$story_type" == "backend" ]]; then
|
|
159
|
+
echo " [4/5] Running API validation..."
|
|
160
|
+
if ! run_api_tests "$story"; then
|
|
161
|
+
failed=1
|
|
162
|
+
fi
|
|
163
|
+
else
|
|
164
|
+
echo " [4/5] Running browser validation..."
|
|
165
|
+
if ! run_browser_validation "$story"; then
|
|
166
|
+
failed=1
|
|
167
|
+
fi
|
|
168
|
+
fi
|
|
169
|
+
fi
|
|
170
|
+
|
|
171
|
+
# ========================================
|
|
172
|
+
# STEP 5: Run PRD test steps
|
|
173
|
+
# ========================================
|
|
174
|
+
if [[ $failed -eq 0 ]]; then
|
|
175
|
+
echo ""
|
|
176
|
+
echo " [5/5] Running PRD test steps..."
|
|
177
|
+
if ! verify_prd_criteria "$story"; then
|
|
178
|
+
failed=1
|
|
179
|
+
fi
|
|
180
|
+
fi
|
|
181
|
+
|
|
182
|
+
# ========================================
|
|
183
|
+
# Final result
|
|
184
|
+
# ========================================
|
|
185
|
+
echo ""
|
|
186
|
+
if [[ $failed -eq 0 ]]; then
|
|
187
|
+
print_success "=== All verification passed ==="
|
|
188
|
+
return 0
|
|
189
|
+
else
|
|
190
|
+
print_error "=== Verification failed ==="
|
|
191
|
+
# Save failure context for next iteration
|
|
192
|
+
save_failure_context "$story"
|
|
193
|
+
return 1
|
|
194
|
+
fi
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
# Save failure context for next iteration
|
|
198
|
+
save_failure_context() {
|
|
199
|
+
local story="$1"
|
|
200
|
+
|
|
201
|
+
local context_file="$RALPH_DIR/last_failure.txt"
|
|
202
|
+
|
|
203
|
+
{
|
|
204
|
+
echo "=== Failure Context for $story ==="
|
|
205
|
+
echo "Timestamp: $(date -Iseconds 2>/dev/null || date)"
|
|
206
|
+
echo ""
|
|
207
|
+
|
|
208
|
+
if [[ -f "$RALPH_DIR/last_migration_failure.log" ]]; then
|
|
209
|
+
echo "--- Migration Failure ---"
|
|
210
|
+
echo "Database migrations failed. Fix the migration or the code causing it:"
|
|
211
|
+
tail -50 "$RALPH_DIR/last_migration_failure.log"
|
|
212
|
+
echo ""
|
|
213
|
+
fi
|
|
214
|
+
|
|
215
|
+
if [[ -f "$RALPH_DIR/last_review_failure.json" ]]; then
|
|
216
|
+
echo "--- Code Review Failure ---"
|
|
217
|
+
echo "Issues found by code review:"
|
|
218
|
+
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
|
|
219
|
+
echo ""
|
|
220
|
+
fi
|
|
221
|
+
|
|
222
|
+
if [[ -f "$RALPH_DIR/last_test_failure.log" ]]; then
|
|
223
|
+
echo "--- Test Failure ---"
|
|
224
|
+
tail -50 "$RALPH_DIR/last_test_failure.log"
|
|
225
|
+
echo ""
|
|
226
|
+
fi
|
|
227
|
+
|
|
228
|
+
if [[ -f "$RALPH_DIR/last_playwright_failure.log" ]]; then
|
|
229
|
+
echo "--- Playwright Failure ---"
|
|
230
|
+
tail -50 "$RALPH_DIR/last_playwright_failure.log"
|
|
231
|
+
echo ""
|
|
232
|
+
fi
|
|
233
|
+
|
|
234
|
+
if [[ -f "$RALPH_DIR/last_browser_failure.json" ]]; then
|
|
235
|
+
echo "--- Browser Validation Failure ---"
|
|
236
|
+
jq -r '"Errors: " + (.errors | join(", "))' "$RALPH_DIR/last_browser_failure.json" 2>/dev/null
|
|
237
|
+
jq -r '"Console errors: " + (.consoleErrors | join(", "))' "$RALPH_DIR/last_browser_failure.json" 2>/dev/null
|
|
238
|
+
jq -r '"Missing elements: " + (.elementsMissing | join(", "))' "$RALPH_DIR/last_browser_failure.json" 2>/dev/null
|
|
239
|
+
echo ""
|
|
240
|
+
fi
|
|
241
|
+
|
|
242
|
+
if [[ -f "$RALPH_DIR/last_precommit_failure.log" ]]; then
|
|
243
|
+
echo "--- Pre-commit / Lint Failure ---"
|
|
244
|
+
echo "Fix these errors before the story can be completed:"
|
|
245
|
+
echo ""
|
|
246
|
+
# Extract actual error lines (not warnings-only or file modification messages)
|
|
247
|
+
grep -E "^error:|: error:|Error:|SyntaxError|✖ [0-9]+ problems|^[^:]+:[0-9]+:[0-9]+: [EF][0-9]+" "$RALPH_DIR/last_precommit_failure.log" | head -30
|
|
248
|
+
# If no errors shown, show the full log tail
|
|
249
|
+
if ! grep -qE "^error:|: error:|Error:|SyntaxError|✖ [0-9]+ problems" "$RALPH_DIR/last_precommit_failure.log"; then
|
|
250
|
+
echo "(Full output):"
|
|
251
|
+
tail -40 "$RALPH_DIR/last_precommit_failure.log"
|
|
252
|
+
fi
|
|
253
|
+
echo ""
|
|
254
|
+
fi
|
|
255
|
+
|
|
256
|
+
if [[ -f "$RALPH_DIR/last_fastapi_response_check.log" ]]; then
|
|
257
|
+
echo "--- FastAPI Response Model Failure ---"
|
|
258
|
+
echo "Add Pydantic response_model to these endpoints for proper Swagger docs:"
|
|
259
|
+
echo ""
|
|
260
|
+
cat "$RALPH_DIR/last_fastapi_response_check.log"
|
|
261
|
+
echo ""
|
|
262
|
+
echo "Fix by adding response_model parameter or return type annotation:"
|
|
263
|
+
echo ' @router.get("/items", response_model=list[ItemSchema])'
|
|
264
|
+
echo " async def get_items() -> list[ItemSchema]:"
|
|
265
|
+
echo ""
|
|
266
|
+
fi
|
|
267
|
+
} > "$context_file"
|
|
268
|
+
}
|