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
package/ralph/loop.sh
ADDED
|
@@ -0,0 +1,570 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# shellcheck shell=bash
|
|
3
|
+
# loop.sh - The autonomous development loop
|
|
4
|
+
|
|
5
|
+
run_loop() {
|
|
6
|
+
local max_iterations="$DEFAULT_MAX_ITERATIONS"
|
|
7
|
+
local specific_story=""
|
|
8
|
+
|
|
9
|
+
# Parse arguments
|
|
10
|
+
while [[ $# -gt 0 ]]; do
|
|
11
|
+
case "$1" in
|
|
12
|
+
--max)
|
|
13
|
+
max_iterations="$2"
|
|
14
|
+
shift 2
|
|
15
|
+
;;
|
|
16
|
+
--story)
|
|
17
|
+
specific_story="$2"
|
|
18
|
+
shift 2
|
|
19
|
+
;;
|
|
20
|
+
*)
|
|
21
|
+
shift
|
|
22
|
+
;;
|
|
23
|
+
esac
|
|
24
|
+
done
|
|
25
|
+
|
|
26
|
+
# Validate prerequisites
|
|
27
|
+
check_dependencies
|
|
28
|
+
|
|
29
|
+
if [[ ! -f "$RALPH_DIR/prd.json" ]]; then
|
|
30
|
+
# Check for misplaced PRD in subdirectories
|
|
31
|
+
local found_prd
|
|
32
|
+
found_prd=$(find . -path "./.ralph" -prune -o -name "prd.json" -path "*/.ralph/prd.json" -print 2>/dev/null | head -1)
|
|
33
|
+
|
|
34
|
+
if [[ -n "$found_prd" ]]; then
|
|
35
|
+
print_warning "PRD found in wrong location: $found_prd"
|
|
36
|
+
echo ""
|
|
37
|
+
echo "PRD should be at root: .ralph/prd.json"
|
|
38
|
+
echo ""
|
|
39
|
+
read -r -p "Move it to root? [Y/n] " response
|
|
40
|
+
if [[ "$response" =~ ^[Nn] ]]; then
|
|
41
|
+
echo "Aborted. Move it manually:"
|
|
42
|
+
echo " mv $found_prd .ralph/prd.json"
|
|
43
|
+
exit 1
|
|
44
|
+
fi
|
|
45
|
+
mkdir -p "$RALPH_DIR"
|
|
46
|
+
mv "$found_prd" "$RALPH_DIR/prd.json"
|
|
47
|
+
print_success "Moved PRD to .ralph/prd.json"
|
|
48
|
+
echo ""
|
|
49
|
+
else
|
|
50
|
+
print_error "No PRD found."
|
|
51
|
+
echo ""
|
|
52
|
+
echo "Create one with:"
|
|
53
|
+
echo " /idea 'your feature description' # thorough (recommended)"
|
|
54
|
+
echo " ralph prd 'your feature' # quick"
|
|
55
|
+
echo ""
|
|
56
|
+
exit 1
|
|
57
|
+
fi
|
|
58
|
+
fi
|
|
59
|
+
|
|
60
|
+
if [[ ! -f "$PROMPT_FILE" ]]; then
|
|
61
|
+
print_error "PROMPT.md not found."
|
|
62
|
+
echo ""
|
|
63
|
+
echo "Create it with: ralph init"
|
|
64
|
+
echo ""
|
|
65
|
+
exit 1
|
|
66
|
+
fi
|
|
67
|
+
|
|
68
|
+
# Validate PRD structure
|
|
69
|
+
if ! validate_prd "$RALPH_DIR/prd.json"; then
|
|
70
|
+
return 1
|
|
71
|
+
fi
|
|
72
|
+
|
|
73
|
+
local iteration=0
|
|
74
|
+
local last_story=""
|
|
75
|
+
local consecutive_failures=0
|
|
76
|
+
local max_story_retries=3
|
|
77
|
+
|
|
78
|
+
while [[ $iteration -lt $max_iterations ]]; do
|
|
79
|
+
# Check for stop signal
|
|
80
|
+
if [[ -f "$RALPH_DIR/.stop" ]]; then
|
|
81
|
+
rm -f "$RALPH_DIR/.stop"
|
|
82
|
+
print_warning "Stop signal received. Exiting gracefully."
|
|
83
|
+
local passed failed
|
|
84
|
+
passed=$(jq '[.stories[] | select(.passes==true)] | length' "$RALPH_DIR/prd.json" 2>/dev/null || echo "0")
|
|
85
|
+
failed=$(jq '[.stories[] | select(.passes==false)] | length' "$RALPH_DIR/prd.json" 2>/dev/null || echo "0")
|
|
86
|
+
send_notification "🛑 Ralph stopped: $passed passed, $failed remaining"
|
|
87
|
+
return 0
|
|
88
|
+
fi
|
|
89
|
+
|
|
90
|
+
((iteration++))
|
|
91
|
+
echo ""
|
|
92
|
+
print_info "=== Iteration $iteration/$max_iterations ==="
|
|
93
|
+
echo ""
|
|
94
|
+
|
|
95
|
+
# 1. Get next incomplete story
|
|
96
|
+
local story
|
|
97
|
+
if [[ -n "$specific_story" ]]; then
|
|
98
|
+
story="$specific_story"
|
|
99
|
+
# Verify it exists
|
|
100
|
+
local exists
|
|
101
|
+
exists=$(jq -r --arg id "$story" '.stories[] | select(.id==$id) | .id' "$RALPH_DIR/prd.json" 2>/dev/null)
|
|
102
|
+
if [[ -z "$exists" ]]; then
|
|
103
|
+
print_error "Story $story not found in PRD"
|
|
104
|
+
return 1
|
|
105
|
+
fi
|
|
106
|
+
else
|
|
107
|
+
story=$(jq -r '.stories[] | select(.passes==false) | .id' "$RALPH_DIR/prd.json" 2>/dev/null | head -1)
|
|
108
|
+
fi
|
|
109
|
+
|
|
110
|
+
if [[ -z "$story" ]]; then
|
|
111
|
+
send_notification "✅ Ralph finished: All stories passed!"
|
|
112
|
+
archive_feature
|
|
113
|
+
return 0
|
|
114
|
+
fi
|
|
115
|
+
|
|
116
|
+
# Track repeated failures on same story
|
|
117
|
+
if [[ "$story" == "$last_story" ]]; then
|
|
118
|
+
((consecutive_failures++))
|
|
119
|
+
if [[ $consecutive_failures -ge $max_story_retries ]]; then
|
|
120
|
+
print_warning "$story failed $consecutive_failures times - check failure context above"
|
|
121
|
+
else
|
|
122
|
+
print_warning "Retry $consecutive_failures/$max_story_retries for $story (failure context included)"
|
|
123
|
+
fi
|
|
124
|
+
else
|
|
125
|
+
consecutive_failures=1
|
|
126
|
+
last_story="$story"
|
|
127
|
+
fi
|
|
128
|
+
|
|
129
|
+
# 2. Session startup checklist (Anthropic best practice)
|
|
130
|
+
startup_checklist
|
|
131
|
+
|
|
132
|
+
# 3. Build prompt with current story context (including failure context if any)
|
|
133
|
+
print_info "Preparing prompt for $story..."
|
|
134
|
+
local prompt_file
|
|
135
|
+
prompt_file=$(create_temp_file ".md") || {
|
|
136
|
+
print_error "Failed to create temp file for prompt"
|
|
137
|
+
return 1
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
local failure_context=""
|
|
141
|
+
if [[ -f "$RALPH_DIR/last_failure.txt" ]]; then
|
|
142
|
+
failure_context=$(cat "$RALPH_DIR/last_failure.txt")
|
|
143
|
+
fi
|
|
144
|
+
|
|
145
|
+
# Temporarily disable errexit to capture build_prompt errors
|
|
146
|
+
set +e
|
|
147
|
+
build_prompt "$story" "$failure_context" > "$prompt_file" 2>&1
|
|
148
|
+
local build_status=$?
|
|
149
|
+
set -e
|
|
150
|
+
|
|
151
|
+
if [[ $build_status -ne 0 ]]; then
|
|
152
|
+
print_error "Failed to build prompt (see $prompt_file for errors)"
|
|
153
|
+
cat "$prompt_file" | head -20
|
|
154
|
+
rm -f "$prompt_file"
|
|
155
|
+
return 1
|
|
156
|
+
fi
|
|
157
|
+
|
|
158
|
+
# Save git state before Claude runs (for migration detection)
|
|
159
|
+
local pre_story_sha=""
|
|
160
|
+
if command -v git &>/dev/null && [[ -d ".git" ]]; then
|
|
161
|
+
pre_story_sha=$(git rev-parse HEAD 2>/dev/null || echo "")
|
|
162
|
+
fi
|
|
163
|
+
|
|
164
|
+
# 4. Spawn Claude (fresh context, with timeout)
|
|
165
|
+
# Get story details for banner
|
|
166
|
+
local story_title story_desc story_type story_emoji
|
|
167
|
+
story_title=$(jq -r --arg id "$story" '.stories[] | select(.id==$id) | .title // "Untitled"' "$RALPH_DIR/prd.json")
|
|
168
|
+
story_desc=$(jq -r --arg id "$story" '.stories[] | select(.id==$id) | .description // ""' "$RALPH_DIR/prd.json" | head -c 50)
|
|
169
|
+
story_type=$(jq -r --arg id "$story" '.stories[] | select(.id==$id) | .type // "general"' "$RALPH_DIR/prd.json")
|
|
170
|
+
story_emoji=$(type_emoji "$story_type")
|
|
171
|
+
|
|
172
|
+
# Get progress
|
|
173
|
+
local total_stories passed_stories current_num
|
|
174
|
+
total_stories=$(jq '[.stories[]] | length' "$RALPH_DIR/prd.json")
|
|
175
|
+
passed_stories=$(jq '[.stories[] | select(.passes==true)] | length' "$RALPH_DIR/prd.json")
|
|
176
|
+
current_num=$((passed_stories + 1))
|
|
177
|
+
|
|
178
|
+
# Display dynamic banner
|
|
179
|
+
echo ""
|
|
180
|
+
echo "┌─────────────────────────────────────────────────────────┐"
|
|
181
|
+
printf "│ %s %-14s [%d/%d] %s │\n" "$story_emoji" "$story" "$current_num" "$total_stories" "$(progress_bar $current_num $total_stories)"
|
|
182
|
+
printf "│ %-55s │\n" "$story_title"
|
|
183
|
+
printf "│ %-55s │\n" "${story_desc}..."
|
|
184
|
+
printf "│ Type: %-49s │\n" "$story_type"
|
|
185
|
+
echo "└─────────────────────────────────────────────────────────┘"
|
|
186
|
+
echo ""
|
|
187
|
+
|
|
188
|
+
local timeout_seconds
|
|
189
|
+
timeout_seconds=$(get_config '.maxSessionSeconds' "$DEFAULT_TIMEOUT_SECONDS")
|
|
190
|
+
|
|
191
|
+
# Run Claude with output visible on terminal
|
|
192
|
+
if ! cat "$prompt_file" | run_with_timeout "$timeout_seconds" claude -p --dangerously-skip-permissions --verbose; then
|
|
193
|
+
print_warning "Claude session ended (timeout or error)"
|
|
194
|
+
log_progress "$story" "TIMEOUT" "Claude session ended after ${timeout_seconds}s"
|
|
195
|
+
rm -f "$prompt_file"
|
|
196
|
+
|
|
197
|
+
# If running specific story, exit on failure
|
|
198
|
+
[[ -n "$specific_story" ]] && return 1
|
|
199
|
+
continue
|
|
200
|
+
fi
|
|
201
|
+
|
|
202
|
+
rm -f "$prompt_file"
|
|
203
|
+
|
|
204
|
+
# 5. Run migrations BEFORE verification (tests need DB schema)
|
|
205
|
+
if ! run_migrations_if_needed "$pre_story_sha"; then
|
|
206
|
+
log_progress "$story" "FAILED" "Migration failed"
|
|
207
|
+
save_failure_context "$story" # Include migration error in next prompt
|
|
208
|
+
print_error "Migration failed for $story, will retry with error context..."
|
|
209
|
+
continue
|
|
210
|
+
fi
|
|
211
|
+
|
|
212
|
+
# 6. Run verification pipeline
|
|
213
|
+
echo ""
|
|
214
|
+
if run_verification "$story"; then
|
|
215
|
+
# Mark story as complete
|
|
216
|
+
update_json "$RALPH_DIR/prd.json" \
|
|
217
|
+
--arg id "$story" '(.stories[] | select(.id==$id) | .passes) = true'
|
|
218
|
+
|
|
219
|
+
# Clear failure context on success
|
|
220
|
+
rm -f "$RALPH_DIR/last_failure.txt"
|
|
221
|
+
rm -f "$RALPH_DIR/last_migration_failure.log"
|
|
222
|
+
rm -f "$RALPH_DIR/last_review_failure.json"
|
|
223
|
+
rm -f "$RALPH_DIR/last_test_failure.log"
|
|
224
|
+
rm -f "$RALPH_DIR/last_playwright_failure.log"
|
|
225
|
+
rm -f "$RALPH_DIR/last_browser_failure.json"
|
|
226
|
+
rm -f "$RALPH_DIR/last_precommit_failure.log"
|
|
227
|
+
|
|
228
|
+
# Auto-commit if git is available
|
|
229
|
+
if command -v git &>/dev/null && [[ -d ".git" ]]; then
|
|
230
|
+
local title commit_log commit_success
|
|
231
|
+
title=$(jq -r --arg id "$story" '.stories[] | select(.id==$id) | .title' "$RALPH_DIR/prd.json")
|
|
232
|
+
commit_log=$(mktemp)
|
|
233
|
+
commit_success=false
|
|
234
|
+
|
|
235
|
+
# Try up to 3 times to handle auto-fix chains (some hooks always modify files)
|
|
236
|
+
for attempt in 1 2 3; do
|
|
237
|
+
git add -A
|
|
238
|
+
if git commit -m "feat($story): $title" > "$commit_log" 2>&1; then
|
|
239
|
+
commit_success=true
|
|
240
|
+
break
|
|
241
|
+
fi
|
|
242
|
+
|
|
243
|
+
# Check if failure is due to file modifications (auto-fix)
|
|
244
|
+
if grep -q "files were modified by this hook" "$commit_log" 2>/dev/null; then
|
|
245
|
+
# Check for REAL errors (not just file modifications or warnings)
|
|
246
|
+
if grep -qE "^error:|: error:|Error:|SyntaxError" "$commit_log" 2>/dev/null; then
|
|
247
|
+
# Real errors - stop retrying
|
|
248
|
+
break
|
|
249
|
+
fi
|
|
250
|
+
# ESLint with actual errors (not just warnings)
|
|
251
|
+
if grep -qE "✖ [0-9]+ problems? \([1-9][0-9]* errors?" "$commit_log" 2>/dev/null; then
|
|
252
|
+
break
|
|
253
|
+
fi
|
|
254
|
+
# Only file modifications - retry
|
|
255
|
+
if [[ $attempt -lt 3 ]]; then
|
|
256
|
+
continue
|
|
257
|
+
fi
|
|
258
|
+
# Max attempts with only file mods - try one more commit
|
|
259
|
+
git add -A
|
|
260
|
+
if git commit -m "feat($story): $title" --no-verify > "$commit_log" 2>&1; then
|
|
261
|
+
commit_success=true
|
|
262
|
+
print_warning "(committed with --no-verify due to auto-fix loop)"
|
|
263
|
+
fi
|
|
264
|
+
break
|
|
265
|
+
else
|
|
266
|
+
# Failed for other reason - check if it's a real error
|
|
267
|
+
if ! grep -qE "^error:|: error:|Error:|SyntaxError|✖ [0-9]+ problems? \([1-9]" "$commit_log" 2>/dev/null; then
|
|
268
|
+
# No real errors found - might just be warnings
|
|
269
|
+
# Try committing with --no-verify
|
|
270
|
+
git add -A
|
|
271
|
+
if git commit -m "feat($story): $title" --no-verify > "$commit_log" 2>&1; then
|
|
272
|
+
commit_success=true
|
|
273
|
+
print_warning "(committed with --no-verify - only warnings detected)"
|
|
274
|
+
fi
|
|
275
|
+
fi
|
|
276
|
+
break
|
|
277
|
+
fi
|
|
278
|
+
done
|
|
279
|
+
|
|
280
|
+
if [[ "$commit_success" != "true" ]]; then
|
|
281
|
+
print_warning "Pre-commit hooks failed, needs fixes..."
|
|
282
|
+
cp "$commit_log" "$RALPH_DIR/last_precommit_failure.log"
|
|
283
|
+
rm -f "$commit_log"
|
|
284
|
+
save_failure_context "$story"
|
|
285
|
+
log_progress "$story" "FAILED" "Pre-commit hooks failed"
|
|
286
|
+
continue
|
|
287
|
+
fi
|
|
288
|
+
rm -f "$commit_log"
|
|
289
|
+
fi
|
|
290
|
+
|
|
291
|
+
log_progress "$story" "COMPLETED"
|
|
292
|
+
print_success "Story $story completed!"
|
|
293
|
+
|
|
294
|
+
# If running specific story, we're done
|
|
295
|
+
[[ -n "$specific_story" ]] && return 0
|
|
296
|
+
else
|
|
297
|
+
log_progress "$story" "FAILED" "Verification failed, will retry"
|
|
298
|
+
print_warning "Verification failed for $story, iterating..."
|
|
299
|
+
|
|
300
|
+
# If running specific story, exit on failure
|
|
301
|
+
[[ -n "$specific_story" ]] && return 1
|
|
302
|
+
fi
|
|
303
|
+
|
|
304
|
+
sleep "$ITERATION_DELAY_SECONDS" # Brief pause between iterations
|
|
305
|
+
done
|
|
306
|
+
|
|
307
|
+
print_warning "Max iterations ($max_iterations) reached"
|
|
308
|
+
local passed failed
|
|
309
|
+
passed=$(jq '[.stories[] | select(.passes==true)] | length' "$RALPH_DIR/prd.json" 2>/dev/null || echo "0")
|
|
310
|
+
failed=$(jq '[.stories[] | select(.passes==false)] | length' "$RALPH_DIR/prd.json" 2>/dev/null || echo "0")
|
|
311
|
+
send_notification "⚠️ Ralph stopped: $passed passed, $failed remaining (max iterations reached)"
|
|
312
|
+
return 1
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
# Display startup checklist (Anthropic best practice)
|
|
316
|
+
startup_checklist() {
|
|
317
|
+
echo "--- Startup Checklist ---"
|
|
318
|
+
echo "Working directory: $(pwd)"
|
|
319
|
+
echo ""
|
|
320
|
+
|
|
321
|
+
echo "Recent progress:"
|
|
322
|
+
if [[ -f "$RALPH_DIR/progress.txt" ]]; then
|
|
323
|
+
tail -"$MAX_PROGRESS_LINES" "$RALPH_DIR/progress.txt" | sed 's/^/ /'
|
|
324
|
+
else
|
|
325
|
+
echo " (no progress yet)"
|
|
326
|
+
fi
|
|
327
|
+
echo ""
|
|
328
|
+
|
|
329
|
+
echo "Stories:"
|
|
330
|
+
jq -r '.stories[] | " \(.id): \(.title) [\(if .passes then "DONE" else "TODO" end)]"' "$RALPH_DIR/prd.json" 2>/dev/null || echo " (none)"
|
|
331
|
+
echo ""
|
|
332
|
+
|
|
333
|
+
if command -v git &>/dev/null && [[ -d ".git" ]]; then
|
|
334
|
+
echo "Git status:"
|
|
335
|
+
git status --short | head -"$MAX_GIT_STATUS_LINES" | sed 's/^/ /'
|
|
336
|
+
echo ""
|
|
337
|
+
fi
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
# Helper: Inject story details into prompt
|
|
341
|
+
_inject_story_context() {
|
|
342
|
+
local story_json="$1"
|
|
343
|
+
|
|
344
|
+
echo ""
|
|
345
|
+
echo "---"
|
|
346
|
+
echo ""
|
|
347
|
+
echo "## Current Story"
|
|
348
|
+
echo ""
|
|
349
|
+
echo '```json'
|
|
350
|
+
echo "$story_json"
|
|
351
|
+
echo '```'
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
# Helper: Inject file guidance into prompt
|
|
355
|
+
_inject_file_guidance() {
|
|
356
|
+
local story_json="$1"
|
|
357
|
+
|
|
358
|
+
local has_files
|
|
359
|
+
has_files=$(echo "$story_json" | jq -r '.files // empty' 2>/dev/null)
|
|
360
|
+
[[ -z "$has_files" ]] && return
|
|
361
|
+
|
|
362
|
+
echo ""
|
|
363
|
+
echo "### File Guidance for This Story"
|
|
364
|
+
echo ""
|
|
365
|
+
echo "**Create these files:**"
|
|
366
|
+
echo "$story_json" | jq -r '.files.create[]? // empty' | sed 's/^/- /'
|
|
367
|
+
echo ""
|
|
368
|
+
echo "**Modify these files:**"
|
|
369
|
+
echo "$story_json" | jq -r '.files.modify[]? // empty' | sed 's/^/- /'
|
|
370
|
+
echo ""
|
|
371
|
+
echo "**Reuse/import from:**"
|
|
372
|
+
echo "$story_json" | jq -r '.files.reuse[]? // empty' | sed 's/^/- /'
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
# Helper: Inject scalability guidance for story
|
|
376
|
+
_inject_story_scale() {
|
|
377
|
+
local story_json="$1"
|
|
378
|
+
|
|
379
|
+
local has_scale
|
|
380
|
+
has_scale=$(echo "$story_json" | jq -r '.scale // empty' 2>/dev/null)
|
|
381
|
+
[[ -z "$has_scale" ]] && return
|
|
382
|
+
|
|
383
|
+
echo ""
|
|
384
|
+
echo "### Scalability Requirements for This Story"
|
|
385
|
+
echo ""
|
|
386
|
+
echo "$story_json" | jq -r '.scale | to_entries[] | "- **\(.key):** \(.value)"' 2>/dev/null
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
# Helper: Inject styleguide reference for frontend stories
|
|
390
|
+
_inject_styleguide() {
|
|
391
|
+
local story_json="$1"
|
|
392
|
+
|
|
393
|
+
local story_type
|
|
394
|
+
story_type=$(echo "$story_json" | jq -r '.type // "frontend"' 2>/dev/null)
|
|
395
|
+
local styleguide_path
|
|
396
|
+
styleguide_path=$(get_config '.styleguide' "")
|
|
397
|
+
|
|
398
|
+
if [[ "$story_type" == "frontend" && -n "$styleguide_path" && -f "$styleguide_path" ]]; then
|
|
399
|
+
echo ""
|
|
400
|
+
echo "### Styleguide"
|
|
401
|
+
echo ""
|
|
402
|
+
echo "**FIRST:** Read the project styleguide at \`$styleguide_path\` before implementing."
|
|
403
|
+
echo "Use existing components, colors, and patterns from the styleguide."
|
|
404
|
+
fi
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
# Helper: Inject feature-level context
|
|
408
|
+
_inject_feature_context() {
|
|
409
|
+
echo ""
|
|
410
|
+
echo "## Feature Context"
|
|
411
|
+
echo ""
|
|
412
|
+
echo '```json'
|
|
413
|
+
jq '{feature: .feature, metadata: .metadata}' "$RALPH_DIR/prd.json"
|
|
414
|
+
echo '```'
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
# Helper: Inject scalability requirements
|
|
418
|
+
_inject_scalability() {
|
|
419
|
+
local has_scalability
|
|
420
|
+
has_scalability=$(jq -r '.scalability // empty' "$RALPH_DIR/prd.json" 2>/dev/null)
|
|
421
|
+
[[ -z "$has_scalability" ]] && return
|
|
422
|
+
|
|
423
|
+
echo ""
|
|
424
|
+
echo "## Scalability Requirements"
|
|
425
|
+
echo ""
|
|
426
|
+
echo "**IMPORTANT:** Follow these scalability rules."
|
|
427
|
+
echo ""
|
|
428
|
+
echo '```json'
|
|
429
|
+
jq '.scalability' "$RALPH_DIR/prd.json"
|
|
430
|
+
echo '```'
|
|
431
|
+
echo ""
|
|
432
|
+
echo "### Key Rules:"
|
|
433
|
+
echo "- Always paginate list endpoints (never return unbounded arrays)"
|
|
434
|
+
echo "- Avoid N+1 queries - eager load relationships"
|
|
435
|
+
echo "- Add database indexes for frequently queried fields"
|
|
436
|
+
echo "- Implement caching strategy as specified"
|
|
437
|
+
echo "- Add rate limiting to public endpoints"
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
# Helper: Inject architecture guidelines
|
|
441
|
+
_inject_architecture() {
|
|
442
|
+
local has_architecture
|
|
443
|
+
has_architecture=$(jq -r '.architecture // empty' "$RALPH_DIR/prd.json" 2>/dev/null)
|
|
444
|
+
[[ -z "$has_architecture" ]] && return
|
|
445
|
+
|
|
446
|
+
echo ""
|
|
447
|
+
echo "## Architecture Guidelines"
|
|
448
|
+
echo ""
|
|
449
|
+
echo "**IMPORTANT:** Follow these architecture rules strictly."
|
|
450
|
+
echo ""
|
|
451
|
+
echo '```json'
|
|
452
|
+
jq '.architecture' "$RALPH_DIR/prd.json"
|
|
453
|
+
echo '```'
|
|
454
|
+
echo ""
|
|
455
|
+
echo "### Key Rules:"
|
|
456
|
+
echo "- Put files in the specified directories"
|
|
457
|
+
echo "- Reuse existing components listed in 'patterns.reuse'"
|
|
458
|
+
echo "- Do NOT create anything in 'doNotCreate'"
|
|
459
|
+
echo "- Keep files under $(jq -r '.architecture.principles.maxFileLines // 300' "$RALPH_DIR/prd.json") lines"
|
|
460
|
+
echo "- Scripts go in scripts/, docs go in docs/"
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
# Helper: Inject failure context from previous iteration
|
|
464
|
+
_inject_failure_context() {
|
|
465
|
+
local failure_context="$1"
|
|
466
|
+
[[ -z "$failure_context" ]] && return
|
|
467
|
+
|
|
468
|
+
echo ""
|
|
469
|
+
echo "## Previous Iteration Failed"
|
|
470
|
+
echo ""
|
|
471
|
+
echo "**IMPORTANT:** The previous attempt at this story failed verification. Review the errors below and fix them."
|
|
472
|
+
echo ""
|
|
473
|
+
echo '```'
|
|
474
|
+
echo "$failure_context"
|
|
475
|
+
echo '```'
|
|
476
|
+
echo ""
|
|
477
|
+
echo "### What to do:"
|
|
478
|
+
echo "1. Read the error messages carefully"
|
|
479
|
+
echo "2. Identify the root cause"
|
|
480
|
+
echo "3. Fix the issue (do not just retry the same approach)"
|
|
481
|
+
echo "4. Run verification again"
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
# Helper: Inject signs (learned patterns)
|
|
485
|
+
_inject_signs() {
|
|
486
|
+
echo ""
|
|
487
|
+
echo "## Signs (Learned Patterns)"
|
|
488
|
+
echo ""
|
|
489
|
+
echo "Apply these lessons from previous sessions:"
|
|
490
|
+
echo ""
|
|
491
|
+
if [[ -f "$RALPH_DIR/signs.json" ]]; then
|
|
492
|
+
jq -r '.signs[] | "- [\(.category)] \(.pattern)"' "$RALPH_DIR/signs.json" 2>/dev/null || echo "(none yet)"
|
|
493
|
+
else
|
|
494
|
+
echo "(none yet)"
|
|
495
|
+
fi
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
# Helper: Inject developer DNA
|
|
499
|
+
_inject_developer_dna() {
|
|
500
|
+
[[ ! -f "$HOME/.claude/DNA.md" ]] && return
|
|
501
|
+
|
|
502
|
+
echo ""
|
|
503
|
+
echo "## Developer DNA"
|
|
504
|
+
echo ""
|
|
505
|
+
echo "The developer has these working preferences:"
|
|
506
|
+
echo ""
|
|
507
|
+
cat "$HOME/.claude/DNA.md"
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
# Build the prompt with story context injected
|
|
511
|
+
build_prompt() {
|
|
512
|
+
local story="$1"
|
|
513
|
+
local failure_context="${2:-}"
|
|
514
|
+
|
|
515
|
+
# Read base PROMPT.md
|
|
516
|
+
cat "$PROMPT_FILE"
|
|
517
|
+
|
|
518
|
+
# Get story JSON once
|
|
519
|
+
local story_json
|
|
520
|
+
story_json=$(jq --arg id "$story" '.stories[] | select(.id==$id)' "$RALPH_DIR/prd.json")
|
|
521
|
+
|
|
522
|
+
# Inject all sections
|
|
523
|
+
_inject_story_context "$story_json"
|
|
524
|
+
_inject_file_guidance "$story_json"
|
|
525
|
+
_inject_story_scale "$story_json"
|
|
526
|
+
_inject_styleguide "$story_json"
|
|
527
|
+
_inject_feature_context
|
|
528
|
+
_inject_scalability
|
|
529
|
+
_inject_architecture
|
|
530
|
+
_inject_failure_context "$failure_context"
|
|
531
|
+
_inject_signs
|
|
532
|
+
_inject_developer_dna
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
# Mark feature as complete (keep PRD for appending new stories)
|
|
536
|
+
archive_feature() {
|
|
537
|
+
local feature_name
|
|
538
|
+
feature_name=$(jq -r '.feature.name' "$RALPH_DIR/prd.json")
|
|
539
|
+
|
|
540
|
+
print_success "Feature '$feature_name' complete!"
|
|
541
|
+
|
|
542
|
+
# Update status to complete (don't archive - user may want to append stories)
|
|
543
|
+
update_json "$RALPH_DIR/prd.json" '.feature.status = "complete"'
|
|
544
|
+
|
|
545
|
+
# Final commit if git available
|
|
546
|
+
if command -v git &>/dev/null && [[ -d ".git" ]]; then
|
|
547
|
+
git add -A
|
|
548
|
+
if ! git commit -m "feat: complete $feature_name" 2>/dev/null; then
|
|
549
|
+
# Retry after pre-commit auto-fixes
|
|
550
|
+
git add -A
|
|
551
|
+
if ! git commit -m "feat: complete $feature_name" 2>/dev/null; then
|
|
552
|
+
# Check if it's "nothing to commit" vs real error
|
|
553
|
+
if git diff --cached --quiet 2>/dev/null; then
|
|
554
|
+
echo " (no changes to commit)"
|
|
555
|
+
else
|
|
556
|
+
print_warning "Final commit failed - check git status"
|
|
557
|
+
fi
|
|
558
|
+
fi
|
|
559
|
+
fi
|
|
560
|
+
fi
|
|
561
|
+
|
|
562
|
+
log_progress "FEATURE" "COMPLETE" "$feature_name"
|
|
563
|
+
|
|
564
|
+
echo ""
|
|
565
|
+
echo "All stories passed! PRD kept at: $RALPH_DIR/prd.json"
|
|
566
|
+
echo ""
|
|
567
|
+
echo "Next:"
|
|
568
|
+
echo " /idea 'new feature' # Add more stories (will append)"
|
|
569
|
+
echo " ralph status # See completed stories"
|
|
570
|
+
}
|