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.
- package/.claude/commands/explain.md +114 -0
- package/.claude/commands/idea.md +370 -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/.claude/settings.json +75 -0
- package/.claude/settings.local.json +12 -0
- package/.pre-commit-hooks.yaml +102 -0
- package/LICENSE +21 -0
- package/README.md +214 -0
- package/bin/postinstall.sh +29 -0
- package/bin/ralph.sh +171 -0
- package/bin/thrivekit.sh +24 -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 +206 -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 +140 -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 +82 -0
- package/ralph/api.sh +210 -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 +388 -0
- package/ralph/loop.sh +570 -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 +353 -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 +164 -0
- package/ralph/verify/tests.sh +81 -0
- package/ralph/verify.sh +224 -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,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
|
+
}
|
package/ralph/verify.sh
ADDED
|
@@ -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)
|