thrivekit 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (164) hide show
  1. package/.claude/commands/explain.md +114 -0
  2. package/.claude/commands/idea.md +370 -0
  3. package/.claude/commands/my-dna.md +122 -0
  4. package/.claude/commands/prd.md +286 -0
  5. package/.claude/commands/review.md +167 -0
  6. package/.claude/commands/sign.md +32 -0
  7. package/.claude/commands/styleguide.md +450 -0
  8. package/.claude/commands/tour.md +301 -0
  9. package/.claude/commands/vibe-check.md +116 -0
  10. package/.claude/commands/vibe-help.md +47 -0
  11. package/.claude/commands/vibe-list.md +203 -0
  12. package/.claude/settings.json +75 -0
  13. package/.claude/settings.local.json +12 -0
  14. package/.pre-commit-hooks.yaml +102 -0
  15. package/LICENSE +21 -0
  16. package/README.md +214 -0
  17. package/bin/postinstall.sh +29 -0
  18. package/bin/ralph.sh +171 -0
  19. package/bin/thrivekit.sh +24 -0
  20. package/bin/vibe-check.js +19 -0
  21. package/dist/checks/check-any-types.d.ts +6 -0
  22. package/dist/checks/check-any-types.d.ts.map +1 -0
  23. package/dist/checks/check-any-types.js +73 -0
  24. package/dist/checks/check-any-types.js.map +1 -0
  25. package/dist/checks/check-commented-code.d.ts +6 -0
  26. package/dist/checks/check-commented-code.d.ts.map +1 -0
  27. package/dist/checks/check-commented-code.js +81 -0
  28. package/dist/checks/check-commented-code.js.map +1 -0
  29. package/dist/checks/check-console-error.d.ts +6 -0
  30. package/dist/checks/check-console-error.d.ts.map +1 -0
  31. package/dist/checks/check-console-error.js +41 -0
  32. package/dist/checks/check-console-error.js.map +1 -0
  33. package/dist/checks/check-debug-statements.d.ts +6 -0
  34. package/dist/checks/check-debug-statements.d.ts.map +1 -0
  35. package/dist/checks/check-debug-statements.js +120 -0
  36. package/dist/checks/check-debug-statements.js.map +1 -0
  37. package/dist/checks/check-deep-nesting.d.ts +6 -0
  38. package/dist/checks/check-deep-nesting.d.ts.map +1 -0
  39. package/dist/checks/check-deep-nesting.js +116 -0
  40. package/dist/checks/check-deep-nesting.js.map +1 -0
  41. package/dist/checks/check-docker-platform.d.ts +6 -0
  42. package/dist/checks/check-docker-platform.d.ts.map +1 -0
  43. package/dist/checks/check-docker-platform.js +42 -0
  44. package/dist/checks/check-docker-platform.js.map +1 -0
  45. package/dist/checks/check-dry-violations.d.ts +6 -0
  46. package/dist/checks/check-dry-violations.d.ts.map +1 -0
  47. package/dist/checks/check-dry-violations.js +124 -0
  48. package/dist/checks/check-dry-violations.js.map +1 -0
  49. package/dist/checks/check-empty-catch.d.ts +6 -0
  50. package/dist/checks/check-empty-catch.d.ts.map +1 -0
  51. package/dist/checks/check-empty-catch.js +111 -0
  52. package/dist/checks/check-empty-catch.js.map +1 -0
  53. package/dist/checks/check-function-length.d.ts +6 -0
  54. package/dist/checks/check-function-length.d.ts.map +1 -0
  55. package/dist/checks/check-function-length.js +152 -0
  56. package/dist/checks/check-function-length.js.map +1 -0
  57. package/dist/checks/check-hardcoded-ai-models.d.ts +10 -0
  58. package/dist/checks/check-hardcoded-ai-models.d.ts.map +1 -0
  59. package/dist/checks/check-hardcoded-ai-models.js +102 -0
  60. package/dist/checks/check-hardcoded-ai-models.js.map +1 -0
  61. package/dist/checks/check-hardcoded-urls.d.ts +6 -0
  62. package/dist/checks/check-hardcoded-urls.d.ts.map +1 -0
  63. package/dist/checks/check-hardcoded-urls.js +124 -0
  64. package/dist/checks/check-hardcoded-urls.js.map +1 -0
  65. package/dist/checks/check-magic-numbers.d.ts +6 -0
  66. package/dist/checks/check-magic-numbers.d.ts.map +1 -0
  67. package/dist/checks/check-magic-numbers.js +116 -0
  68. package/dist/checks/check-magic-numbers.js.map +1 -0
  69. package/dist/checks/check-secrets.d.ts +6 -0
  70. package/dist/checks/check-secrets.d.ts.map +1 -0
  71. package/dist/checks/check-secrets.js +138 -0
  72. package/dist/checks/check-secrets.js.map +1 -0
  73. package/dist/checks/check-snake-case-ts.d.ts +6 -0
  74. package/dist/checks/check-snake-case-ts.d.ts.map +1 -0
  75. package/dist/checks/check-snake-case-ts.js +78 -0
  76. package/dist/checks/check-snake-case-ts.js.map +1 -0
  77. package/dist/checks/check-todo-fixme.d.ts +6 -0
  78. package/dist/checks/check-todo-fixme.d.ts.map +1 -0
  79. package/dist/checks/check-todo-fixme.js +41 -0
  80. package/dist/checks/check-todo-fixme.js.map +1 -0
  81. package/dist/checks/check-unsafe-html.d.ts +6 -0
  82. package/dist/checks/check-unsafe-html.d.ts.map +1 -0
  83. package/dist/checks/check-unsafe-html.js +101 -0
  84. package/dist/checks/check-unsafe-html.js.map +1 -0
  85. package/dist/checks/index.d.ts +30 -0
  86. package/dist/checks/index.d.ts.map +1 -0
  87. package/dist/checks/index.js +57 -0
  88. package/dist/checks/index.js.map +1 -0
  89. package/dist/cli.d.ts +13 -0
  90. package/dist/cli.d.ts.map +1 -0
  91. package/dist/cli.js +206 -0
  92. package/dist/cli.js.map +1 -0
  93. package/dist/index.d.ts +9 -0
  94. package/dist/index.d.ts.map +1 -0
  95. package/dist/index.js +10 -0
  96. package/dist/index.js.map +1 -0
  97. package/dist/utils/file-reader.d.ts +24 -0
  98. package/dist/utils/file-reader.d.ts.map +1 -0
  99. package/dist/utils/file-reader.js +140 -0
  100. package/dist/utils/file-reader.js.map +1 -0
  101. package/dist/utils/patterns.d.ts +27 -0
  102. package/dist/utils/patterns.d.ts.map +1 -0
  103. package/dist/utils/patterns.js +84 -0
  104. package/dist/utils/patterns.js.map +1 -0
  105. package/dist/utils/reporters.d.ts +21 -0
  106. package/dist/utils/reporters.d.ts.map +1 -0
  107. package/dist/utils/reporters.js +115 -0
  108. package/dist/utils/reporters.js.map +1 -0
  109. package/dist/utils/types.d.ts +71 -0
  110. package/dist/utils/types.d.ts.map +1 -0
  111. package/dist/utils/types.js +5 -0
  112. package/dist/utils/types.js.map +1 -0
  113. package/package.json +82 -0
  114. package/ralph/api.sh +210 -0
  115. package/ralph/backup.sh +838 -0
  116. package/ralph/browser-verify/README.md +135 -0
  117. package/ralph/browser-verify/verify.ts +450 -0
  118. package/ralph/checks/check-fastapi-responses.py +155 -0
  119. package/ralph/hooks/hooks-config.json +72 -0
  120. package/ralph/hooks/inject-context.sh +44 -0
  121. package/ralph/hooks/install.sh +207 -0
  122. package/ralph/hooks/log-tools.sh +45 -0
  123. package/ralph/hooks/protect-prd.sh +27 -0
  124. package/ralph/hooks/save-learnings.sh +36 -0
  125. package/ralph/hooks/warn-debug.sh +54 -0
  126. package/ralph/hooks/warn-empty-catch.sh +63 -0
  127. package/ralph/hooks/warn-secrets.sh +89 -0
  128. package/ralph/hooks/warn-urls.sh +77 -0
  129. package/ralph/init.sh +388 -0
  130. package/ralph/loop.sh +570 -0
  131. package/ralph/playwright.sh +238 -0
  132. package/ralph/prd.sh +295 -0
  133. package/ralph/setup/feature-tour.sh +155 -0
  134. package/ralph/setup/quick-setup.sh +239 -0
  135. package/ralph/setup/tutorial.sh +159 -0
  136. package/ralph/setup/ui.sh +136 -0
  137. package/ralph/setup.sh +353 -0
  138. package/ralph/signs.sh +150 -0
  139. package/ralph/utils.sh +682 -0
  140. package/ralph/verify/browser.sh +324 -0
  141. package/ralph/verify/lint.sh +363 -0
  142. package/ralph/verify/review.sh +164 -0
  143. package/ralph/verify/tests.sh +81 -0
  144. package/ralph/verify.sh +224 -0
  145. package/templates/PROMPT.md +235 -0
  146. package/templates/config/fullstack.json +86 -0
  147. package/templates/config/go.json +81 -0
  148. package/templates/config/minimal.json +76 -0
  149. package/templates/config/node.json +81 -0
  150. package/templates/config/python.json +81 -0
  151. package/templates/config/rust.json +81 -0
  152. package/templates/examples/CLAUDE-django.md +174 -0
  153. package/templates/examples/CLAUDE-fastapi.md +270 -0
  154. package/templates/examples/CLAUDE-fastmcp.md +352 -0
  155. package/templates/examples/CLAUDE-fullstack.md +256 -0
  156. package/templates/examples/CLAUDE-node.md +246 -0
  157. package/templates/examples/CLAUDE-react.md +138 -0
  158. package/templates/optional/cursorrules.template +147 -0
  159. package/templates/optional/eslint.config.js +34 -0
  160. package/templates/optional/lint-staged.config.js +34 -0
  161. package/templates/optional/ruff.toml +125 -0
  162. package/templates/optional/vibe-check.yml +116 -0
  163. package/templates/optional/vscode-settings.json +127 -0
  164. package/templates/signs.json +46 -0
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
+ }