anvil-dev-framework 0.1.6

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 (190) hide show
  1. package/README.md +719 -0
  2. package/VERSION +1 -0
  3. package/docs/ANVIL-REPO-IMPLEMENTATION-PLAN.md +441 -0
  4. package/docs/FIRST-SKILL-TUTORIAL.md +408 -0
  5. package/docs/INSTALLATION-RETRO-NOTES.md +458 -0
  6. package/docs/INSTALLATION.md +984 -0
  7. package/docs/anvil-hud.md +469 -0
  8. package/docs/anvil-init.md +255 -0
  9. package/docs/anvil-state.md +210 -0
  10. package/docs/boris-cherny-ralph-wiggum-insights.md +608 -0
  11. package/docs/command-reference.md +2022 -0
  12. package/docs/hooks-tts.md +368 -0
  13. package/docs/implementation-guide.md +810 -0
  14. package/docs/linear-github-integration.md +247 -0
  15. package/docs/local-issues.md +677 -0
  16. package/docs/patterns/README.md +419 -0
  17. package/docs/planning-responsibilities.md +139 -0
  18. package/docs/session-workflow.md +573 -0
  19. package/docs/simplification-plan-template.md +297 -0
  20. package/docs/simplification-principles.md +129 -0
  21. package/docs/specifications/CCS-RALPH-INTEGRATION-DESIGN.md +633 -0
  22. package/docs/specifications/CCS-RESEARCH-REPORT.md +169 -0
  23. package/docs/specifications/PLAN-ANV-verification-ralph-wiggum.md +403 -0
  24. package/docs/specifications/PLAN-parallel-tracks-anvil-memory-ccs.md +494 -0
  25. package/docs/specifications/SPEC-ANV-VRW/component-01-verify.md +208 -0
  26. package/docs/specifications/SPEC-ANV-VRW/component-02-stop-gate.md +226 -0
  27. package/docs/specifications/SPEC-ANV-VRW/component-03-posttooluse.md +209 -0
  28. package/docs/specifications/SPEC-ANV-VRW/component-04-ralph-wiggum.md +604 -0
  29. package/docs/specifications/SPEC-ANV-VRW/component-05-atomic-actions.md +311 -0
  30. package/docs/specifications/SPEC-ANV-VRW/component-06-verify-subagent.md +264 -0
  31. package/docs/specifications/SPEC-ANV-VRW/component-07-claude-md.md +363 -0
  32. package/docs/specifications/SPEC-ANV-VRW/index.md +182 -0
  33. package/docs/specifications/SPEC-ANV-anvil-memory.md +573 -0
  34. package/docs/specifications/SPEC-ANV-context-checkpoints.md +781 -0
  35. package/docs/specifications/SPEC-ANV-verification-ralph-wiggum.md +789 -0
  36. package/docs/sync.md +122 -0
  37. package/global/CLAUDE.md +140 -0
  38. package/global/agents/verify-app.md +164 -0
  39. package/global/commands/anvil-settings.md +527 -0
  40. package/global/commands/anvil-sync.md +121 -0
  41. package/global/commands/change.md +197 -0
  42. package/global/commands/clarify.md +252 -0
  43. package/global/commands/cleanup.md +292 -0
  44. package/global/commands/commit-push-pr.md +207 -0
  45. package/global/commands/decay-review.md +127 -0
  46. package/global/commands/discover.md +158 -0
  47. package/global/commands/doc-coverage.md +122 -0
  48. package/global/commands/evidence.md +307 -0
  49. package/global/commands/explore.md +121 -0
  50. package/global/commands/force-exit.md +135 -0
  51. package/global/commands/handoff.md +191 -0
  52. package/global/commands/healthcheck.md +302 -0
  53. package/global/commands/hud.md +84 -0
  54. package/global/commands/insights.md +319 -0
  55. package/global/commands/linear-setup.md +184 -0
  56. package/global/commands/lint-fix.md +198 -0
  57. package/global/commands/orient.md +510 -0
  58. package/global/commands/plan.md +228 -0
  59. package/global/commands/ralph.md +346 -0
  60. package/global/commands/ready.md +182 -0
  61. package/global/commands/release.md +305 -0
  62. package/global/commands/retro.md +96 -0
  63. package/global/commands/shard.md +166 -0
  64. package/global/commands/spec.md +227 -0
  65. package/global/commands/sprint.md +184 -0
  66. package/global/commands/tasks.md +228 -0
  67. package/global/commands/test-and-commit.md +151 -0
  68. package/global/commands/validate.md +132 -0
  69. package/global/commands/verify.md +251 -0
  70. package/global/commands/weekly-review.md +156 -0
  71. package/global/hooks/__pycache__/ralph_context_monitor.cpython-314.pyc +0 -0
  72. package/global/hooks/__pycache__/statusline_agent_sync.cpython-314.pyc +0 -0
  73. package/global/hooks/anvil_memory_observe.ts +322 -0
  74. package/global/hooks/anvil_memory_session.ts +166 -0
  75. package/global/hooks/anvil_memory_stop.ts +187 -0
  76. package/global/hooks/parse_transcript.py +116 -0
  77. package/global/hooks/post_merge_cleanup.sh +132 -0
  78. package/global/hooks/post_tool_format.sh +215 -0
  79. package/global/hooks/ralph_context_monitor.py +240 -0
  80. package/global/hooks/ralph_stop.sh +502 -0
  81. package/global/hooks/statusline.sh +1110 -0
  82. package/global/hooks/statusline_agent_sync.py +224 -0
  83. package/global/hooks/stop_gate.sh +250 -0
  84. package/global/lib/.claude/anvil-state.json +21 -0
  85. package/global/lib/__pycache__/agent_registry.cpython-314.pyc +0 -0
  86. package/global/lib/__pycache__/claim_service.cpython-314.pyc +0 -0
  87. package/global/lib/__pycache__/coderabbit_service.cpython-314.pyc +0 -0
  88. package/global/lib/__pycache__/config_service.cpython-314.pyc +0 -0
  89. package/global/lib/__pycache__/coordination_service.cpython-314.pyc +0 -0
  90. package/global/lib/__pycache__/doc_coverage_service.cpython-314.pyc +0 -0
  91. package/global/lib/__pycache__/gate_logger.cpython-314.pyc +0 -0
  92. package/global/lib/__pycache__/github_service.cpython-314.pyc +0 -0
  93. package/global/lib/__pycache__/hygiene_service.cpython-314.pyc +0 -0
  94. package/global/lib/__pycache__/issue_models.cpython-314.pyc +0 -0
  95. package/global/lib/__pycache__/issue_provider.cpython-314.pyc +0 -0
  96. package/global/lib/__pycache__/linear_data_service.cpython-314.pyc +0 -0
  97. package/global/lib/__pycache__/linear_provider.cpython-314.pyc +0 -0
  98. package/global/lib/__pycache__/local_provider.cpython-314.pyc +0 -0
  99. package/global/lib/__pycache__/quality_service.cpython-314.pyc +0 -0
  100. package/global/lib/__pycache__/ralph_state.cpython-314.pyc +0 -0
  101. package/global/lib/__pycache__/state_manager.cpython-314.pyc +0 -0
  102. package/global/lib/__pycache__/transcript_parser.cpython-314.pyc +0 -0
  103. package/global/lib/__pycache__/verification_runner.cpython-314.pyc +0 -0
  104. package/global/lib/__pycache__/verify_iteration.cpython-314.pyc +0 -0
  105. package/global/lib/__pycache__/verify_subagent.cpython-314.pyc +0 -0
  106. package/global/lib/agent_registry.py +995 -0
  107. package/global/lib/anvil-state.sh +435 -0
  108. package/global/lib/claim_service.py +515 -0
  109. package/global/lib/coderabbit_service.py +314 -0
  110. package/global/lib/config_service.py +423 -0
  111. package/global/lib/coordination_service.py +331 -0
  112. package/global/lib/doc_coverage_service.py +1305 -0
  113. package/global/lib/gate_logger.py +316 -0
  114. package/global/lib/github_service.py +310 -0
  115. package/global/lib/handoff_generator.py +775 -0
  116. package/global/lib/hygiene_service.py +712 -0
  117. package/global/lib/issue_models.py +257 -0
  118. package/global/lib/issue_provider.py +339 -0
  119. package/global/lib/linear_data_service.py +210 -0
  120. package/global/lib/linear_provider.py +987 -0
  121. package/global/lib/linear_provider.py.backup +671 -0
  122. package/global/lib/local_provider.py +486 -0
  123. package/global/lib/orient_fast.py +457 -0
  124. package/global/lib/quality_service.py +470 -0
  125. package/global/lib/ralph_prompt_generator.py +563 -0
  126. package/global/lib/ralph_state.py +1202 -0
  127. package/global/lib/state_manager.py +417 -0
  128. package/global/lib/transcript_parser.py +597 -0
  129. package/global/lib/verification_runner.py +557 -0
  130. package/global/lib/verify_iteration.py +490 -0
  131. package/global/lib/verify_subagent.py +250 -0
  132. package/global/skills/README.md +155 -0
  133. package/global/skills/quality-gates/SKILL.md +252 -0
  134. package/global/skills/skill-template/SKILL.md +109 -0
  135. package/global/skills/testing-strategies/SKILL.md +337 -0
  136. package/global/templates/CHANGE-template.md +105 -0
  137. package/global/templates/HANDOFF-template.md +63 -0
  138. package/global/templates/PLAN-template.md +111 -0
  139. package/global/templates/SPEC-template.md +93 -0
  140. package/global/templates/ralph/PROMPT.md.template +89 -0
  141. package/global/templates/ralph/fix_plan.md.template +31 -0
  142. package/global/templates/ralph/progress.txt.template +23 -0
  143. package/global/tests/__pycache__/test_doc_coverage.cpython-314.pyc +0 -0
  144. package/global/tests/test_doc_coverage.py +520 -0
  145. package/global/tests/test_issue_models.py +299 -0
  146. package/global/tests/test_local_provider.py +323 -0
  147. package/global/tools/README.md +178 -0
  148. package/global/tools/__pycache__/anvil-hud.cpython-314.pyc +0 -0
  149. package/global/tools/anvil-hud.py +3622 -0
  150. package/global/tools/anvil-hud.py.bak +3318 -0
  151. package/global/tools/anvil-issue.py +432 -0
  152. package/global/tools/anvil-memory/CLAUDE.md +49 -0
  153. package/global/tools/anvil-memory/README.md +42 -0
  154. package/global/tools/anvil-memory/bun.lock +25 -0
  155. package/global/tools/anvil-memory/bunfig.toml +9 -0
  156. package/global/tools/anvil-memory/package.json +23 -0
  157. package/global/tools/anvil-memory/src/__tests__/ccs/context-monitor.test.ts +535 -0
  158. package/global/tools/anvil-memory/src/__tests__/ccs/edge-cases.test.ts +645 -0
  159. package/global/tools/anvil-memory/src/__tests__/ccs/fixtures.ts +363 -0
  160. package/global/tools/anvil-memory/src/__tests__/ccs/index.ts +8 -0
  161. package/global/tools/anvil-memory/src/__tests__/ccs/integration.test.ts +417 -0
  162. package/global/tools/anvil-memory/src/__tests__/ccs/prompt-generator.test.ts +571 -0
  163. package/global/tools/anvil-memory/src/__tests__/ccs/ralph-stop.test.ts +440 -0
  164. package/global/tools/anvil-memory/src/__tests__/ccs/test-utils.ts +252 -0
  165. package/global/tools/anvil-memory/src/__tests__/commands.test.ts +657 -0
  166. package/global/tools/anvil-memory/src/__tests__/db.test.ts +641 -0
  167. package/global/tools/anvil-memory/src/__tests__/hooks.test.ts +272 -0
  168. package/global/tools/anvil-memory/src/__tests__/performance.test.ts +427 -0
  169. package/global/tools/anvil-memory/src/__tests__/test-utils.ts +113 -0
  170. package/global/tools/anvil-memory/src/commands/checkpoint.ts +197 -0
  171. package/global/tools/anvil-memory/src/commands/get.ts +115 -0
  172. package/global/tools/anvil-memory/src/commands/init.ts +94 -0
  173. package/global/tools/anvil-memory/src/commands/observe.ts +163 -0
  174. package/global/tools/anvil-memory/src/commands/search.ts +112 -0
  175. package/global/tools/anvil-memory/src/db.ts +638 -0
  176. package/global/tools/anvil-memory/src/index.ts +205 -0
  177. package/global/tools/anvil-memory/src/types.ts +122 -0
  178. package/global/tools/anvil-memory/tsconfig.json +29 -0
  179. package/global/tools/ralph-loop.sh +359 -0
  180. package/package.json +45 -0
  181. package/scripts/anvil +822 -0
  182. package/scripts/extract_patterns.py +222 -0
  183. package/scripts/init-project.sh +541 -0
  184. package/scripts/install.sh +229 -0
  185. package/scripts/postinstall.js +41 -0
  186. package/scripts/rollback.sh +188 -0
  187. package/scripts/sync.sh +623 -0
  188. package/scripts/test-statusline.sh +248 -0
  189. package/scripts/update_claude_md.py +224 -0
  190. package/scripts/verify.sh +255 -0
@@ -0,0 +1,502 @@
1
+ #!/bin/bash
2
+ # =============================================================================
3
+ # ralph_stop.sh - Ralph Wiggum Stop Hook with Circuit Breaker (ANV-160)
4
+ # =============================================================================
5
+ #
6
+ # Stop hook for Ralph Wiggum autonomous execution mode.
7
+ # Blocks exit until completion promise is detected or safety limits reached.
8
+ #
9
+ # Usage: Called automatically by Claude Code on Stop events during Ralph mode
10
+ #
11
+ # Environment Variables:
12
+ # RALPH_MAX_ITERATIONS - Max iterations (default: 50)
13
+ # RALPH_COMPLETION_PROMISE - Completion text to detect (default: COMPLETE)
14
+ # RALPH_STATE_FILE - State file path (default: .claude/ralph-state.json)
15
+ # RALPH_ENABLE_LOGGING - Set to "true" to enable logging
16
+ #
17
+ # Exit Codes:
18
+ # 0 - Allow exit (complete, fatal error, or safety limit)
19
+ # 1 - Block exit and restart (continue iteration)
20
+ #
21
+ # DEPENDENCY: jq (apt install jq / brew install jq)
22
+ # WARNING: Windows/Git Bash users must install jq separately or use WSL
23
+ #
24
+
25
+ set -euo pipefail
26
+
27
+ # =============================================================================
28
+ # Configuration
29
+ # =============================================================================
30
+
31
+ MAX_ITERATIONS="${RALPH_MAX_ITERATIONS:-50}"
32
+ COMPLETION_PROMISE="${RALPH_COMPLETION_PROMISE:-COMPLETE}"
33
+ STATE_FILE="${RALPH_STATE_FILE:-.claude/ralph-state.json}"
34
+ ENABLE_LOGGING="${RALPH_ENABLE_LOGGING:-false}"
35
+ LOG_FILE=".claude/logs/ralph.log"
36
+ PROGRESS_FILE="progress.txt"
37
+
38
+ # Circuit breaker thresholds
39
+ NO_CHANGE_THRESHOLD=3
40
+ REPEATED_ERROR_THRESHOLD=5
41
+
42
+ # =============================================================================
43
+ # Logging
44
+ # =============================================================================
45
+
46
+ log_event() {
47
+ local level="$1"
48
+ local message="$2"
49
+
50
+ if [[ "$ENABLE_LOGGING" == "true" ]]; then
51
+ local timestamp
52
+ timestamp=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
53
+ mkdir -p "$(dirname "$LOG_FILE")"
54
+ echo "[$timestamp] [$level] $message" >> "$LOG_FILE"
55
+ fi
56
+
57
+ # Also output to stderr for visibility
58
+ case "$level" in
59
+ ERROR) echo "❌ Ralph: $message" >&2 ;;
60
+ WARN) echo "⚠️ Ralph: $message" >&2 ;;
61
+ INFO) echo "🔄 Ralph: $message" >&2 ;;
62
+ OK) echo "✅ Ralph: $message" >&2 ;;
63
+ esac
64
+ }
65
+
66
+ # =============================================================================
67
+ # State Management
68
+ # =============================================================================
69
+
70
+ init_state() {
71
+ if [[ ! -f "$STATE_FILE" ]]; then
72
+ mkdir -p "$(dirname "$STATE_FILE")"
73
+ cat > "$STATE_FILE" << 'INIT_STATE'
74
+ {
75
+ "iteration": 0,
76
+ "started_at": "",
77
+ "no_change_count": 0,
78
+ "last_diff_hash": "",
79
+ "error_hashes": [],
80
+ "status": "running"
81
+ }
82
+ INIT_STATE
83
+ # Set started_at timestamp
84
+ local timestamp
85
+ timestamp=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
86
+ jq --arg ts "$timestamp" '.started_at = $ts' "$STATE_FILE" > tmp.$$ && mv tmp.$$ "$STATE_FILE"
87
+ fi
88
+ }
89
+
90
+ read_state() {
91
+ local key="$1"
92
+ local default="${2:-}"
93
+ jq -r ".$key // \"$default\"" "$STATE_FILE" 2>/dev/null || echo "$default"
94
+ }
95
+
96
+ update_state() {
97
+ local key="$1"
98
+ local value="$2"
99
+
100
+ if [[ "$value" =~ ^[0-9]+$ ]]; then
101
+ # Numeric value
102
+ jq --argjson v "$value" ".$key = \$v" "$STATE_FILE" > tmp.$$ && mv tmp.$$ "$STATE_FILE"
103
+ else
104
+ # String value
105
+ jq --arg v "$value" ".$key = \$v" "$STATE_FILE" > tmp.$$ && mv tmp.$$ "$STATE_FILE"
106
+ fi
107
+ }
108
+
109
+ cleanup_state() {
110
+ if [[ -f "$STATE_FILE" ]]; then
111
+ rm -f "$STATE_FILE"
112
+ fi
113
+ }
114
+
115
+ # =============================================================================
116
+ # Circuit Breaker Detection
117
+ # =============================================================================
118
+
119
+ get_current_diff_hash() {
120
+ # Hash of current git diff to detect if changes were made
121
+ git diff --stat 2>/dev/null | md5sum 2>/dev/null | cut -d' ' -f1 || echo "no-git"
122
+ }
123
+
124
+ check_no_change_circuit() {
125
+ local current_hash
126
+ current_hash=$(get_current_diff_hash)
127
+ local last_hash
128
+ last_hash=$(read_state "last_diff_hash" "")
129
+
130
+ if [[ "$current_hash" == "$last_hash" && -n "$last_hash" ]]; then
131
+ local no_change_count
132
+ no_change_count=$(read_state "no_change_count" "0")
133
+ no_change_count=$((no_change_count + 1))
134
+ update_state "no_change_count" "$no_change_count"
135
+
136
+ if [[ $no_change_count -ge $NO_CHANGE_THRESHOLD ]]; then
137
+ log_event "ERROR" "Circuit breaker: $NO_CHANGE_THRESHOLD iterations with no file changes"
138
+ return 1
139
+ else
140
+ log_event "WARN" "No file changes detected (${no_change_count}/${NO_CHANGE_THRESHOLD})"
141
+ fi
142
+ else
143
+ update_state "no_change_count" "0"
144
+ update_state "last_diff_hash" "$current_hash"
145
+ fi
146
+
147
+ return 0
148
+ }
149
+
150
+ # =============================================================================
151
+ # Linear Integration (ANV-213)
152
+ # =============================================================================
153
+
154
+ report_linear_progress() {
155
+ # Report Linear sync progress to progress.txt at iteration boundaries.
156
+ #
157
+ # NOTE: The actual Linear API sync happens in ralph_state.py when
158
+ # mark_subtask_complete() is called - it internally calls sync_to_linear().
159
+ # This function reads the sync status from state and reports it to progress.txt.
160
+
161
+ if [[ ! -f "$STATE_FILE" ]]; then
162
+ return 0
163
+ fi
164
+
165
+ # Check if Linear integration is enabled
166
+ local linear_enabled
167
+ linear_enabled=$(jq -r '.linear_integration.enabled // false' "$STATE_FILE" 2>/dev/null || echo "false")
168
+
169
+ if [[ "$linear_enabled" != "true" ]]; then
170
+ return 0 # Not a Linear session
171
+ fi
172
+
173
+ local no_sync
174
+ no_sync=$(jq -r '.linear_integration.no_sync // false' "$STATE_FILE" 2>/dev/null || echo "false")
175
+
176
+ if [[ "$no_sync" == "true" ]]; then
177
+ log_event "INFO" "Linear sync disabled for this session"
178
+ return 0
179
+ fi
180
+
181
+ # Get sync info from state (set by ralph_state.py sync_to_linear)
182
+ local last_sync
183
+ last_sync=$(jq -r '.linear_integration.last_sync // ""' "$STATE_FILE" 2>/dev/null || echo "")
184
+
185
+ if [[ -n "$last_sync" ]]; then
186
+ # Append sync info to progress.txt
187
+ if [[ -f "$PROGRESS_FILE" ]]; then
188
+ local completed
189
+ completed=$(jq -r '[.linear_integration.subtasks[] | select(.status == "completed")] | length' "$STATE_FILE" 2>/dev/null || echo "0")
190
+ local total
191
+ total=$(jq -r '.linear_integration.subtasks | length' "$STATE_FILE" 2>/dev/null || echo "0")
192
+
193
+ # Get the most recently completed subtask
194
+ local last_completed
195
+ last_completed=$(jq -r '[.linear_integration.subtasks[] | select(.status == "completed")] | sort_by(.completed_at) | last | .identifier // ""' "$STATE_FILE" 2>/dev/null || echo "")
196
+
197
+ if [[ -n "$last_completed" ]]; then
198
+ echo "" >> "$PROGRESS_FILE"
199
+ echo "[Linear] Synced $last_completed to Done ($completed/$total completed)" >> "$PROGRESS_FILE"
200
+ log_event "INFO" "Synced $last_completed to Done in Linear"
201
+ fi
202
+ fi
203
+ fi
204
+
205
+ return 0
206
+ }
207
+
208
+ # =============================================================================
209
+ # Git Checkpointing
210
+ # =============================================================================
211
+
212
+ git_checkpoint() {
213
+ local iteration="$1"
214
+
215
+ # Only checkpoint if there are changes
216
+ if ! git diff --quiet 2>/dev/null || ! git diff --cached --quiet 2>/dev/null; then
217
+ git add -A 2>/dev/null || true
218
+ git commit -m "ralph: checkpoint iteration $iteration" --no-verify 2>/dev/null || true
219
+ log_event "INFO" "Git checkpoint created for iteration $iteration"
220
+ fi
221
+ }
222
+
223
+ # =============================================================================
224
+ # CCS Checkpoint Handling (ANV-200)
225
+ # =============================================================================
226
+
227
+ check_ccs_checkpoint() {
228
+ # Check if CCS context checkpoint was triggered
229
+ local checkpoint_active
230
+ checkpoint_active=$(jq -r '.context_checkpoint.active // false' "$STATE_FILE" 2>/dev/null)
231
+ if [[ "$checkpoint_active" == "true" ]]; then
232
+ return 0
233
+ fi
234
+ return 1
235
+ }
236
+
237
+ handle_ccs_checkpoint() {
238
+ log_event "INFO" "CCS checkpoint detected - preparing resume context"
239
+ local level percent handoff_file current_item
240
+ level=$(jq -r '.context_checkpoint.level // "L2"' "$STATE_FILE")
241
+ percent=$(jq -r '.context_checkpoint.percent_at_checkpoint // 0' "$STATE_FILE")
242
+ handoff_file=$(jq -r '.context_checkpoint.handoff_file // ""' "$STATE_FILE")
243
+ current_item=$(jq -r '.context_checkpoint.current_todo_item // ""' "$STATE_FILE")
244
+ regenerate_prompt_with_checkpoint "$handoff_file" "$current_item" "$level" "$percent"
245
+ jq '.context_checkpoint.active = false' "$STATE_FILE" > tmp.$$ && mv tmp.$$ "$STATE_FILE"
246
+ log_event "OK" "Resume context prepared (L${level} at ${percent}%)"
247
+ }
248
+
249
+ regenerate_prompt_with_checkpoint() {
250
+ local handoff_file="$1"
251
+ local current_item="$2"
252
+ local level="$3"
253
+ local percent="$4"
254
+ local prompt_file="PROMPT.md"
255
+
256
+ # Use the Python prompt generator (ANV-201) for enhanced resume templates
257
+ local script_dir
258
+ script_dir="$(dirname "$0")/../lib"
259
+
260
+ if [[ -f "$script_dir/ralph_prompt_generator.py" ]]; then
261
+ # Use Python generator with full state context
262
+ python3 "$script_dir/ralph_prompt_generator.py" \
263
+ --mode ralph \
264
+ --state "$STATE_FILE" \
265
+ --output "$prompt_file" 2>/dev/null
266
+
267
+ if [[ $? -eq 0 ]]; then
268
+ log_event "INFO" "Generated resume prompt via Python generator: $prompt_file"
269
+ return 0
270
+ fi
271
+ # Fall back to inline template if Python fails
272
+ log_event "WARN" "Python generator failed, using fallback template"
273
+ fi
274
+
275
+ # Fallback: Inline template (original ANV-200 implementation)
276
+ local timestamp
277
+ timestamp=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
278
+ local todo_items
279
+ todo_items=$(jq -r '.todo_items // [] | .[]' "$STATE_FILE" 2>/dev/null | head -10)
280
+ local iteration
281
+ iteration=$(jq -r '.iteration // 0' "$STATE_FILE")
282
+ local task_name
283
+ task_name=$(jq -r '.task_name // "Unknown Task"' "$STATE_FILE")
284
+
285
+ cat > "$prompt_file" << RESUME_PROMPT
286
+ # Ralph Autonomous Session Resume
287
+
288
+ > **Context Checkpoint Recovery**
289
+ > Generated at $timestamp
290
+ > Previous session hit L${level} threshold (${percent}% context)
291
+
292
+ ---
293
+
294
+ ## Previous Session Summary
295
+
296
+ **Task**: $task_name
297
+ **Iteration**: $iteration
298
+ **Checkpoint Level**: L${level}
299
+ **Context at Checkpoint**: ${percent}%
300
+
301
+ ---
302
+
303
+ ## Handoff Document
304
+
305
+ The previous session created a detailed handoff document with full context:
306
+
307
+ \`\`\`
308
+ $handoff_file
309
+ \`\`\`
310
+
311
+ **IMPORTANT**: Read this file first to understand the full context of where work left off.
312
+
313
+ ---
314
+
315
+ ## Current Task Context
316
+
317
+ ### Current Item (In Progress)
318
+
319
+ **Task**: $current_item
320
+
321
+ ### Remaining Work
322
+
323
+ \`\`\`
324
+ $todo_items
325
+ \`\`\`
326
+
327
+ ---
328
+
329
+ ## Resume Instructions
330
+
331
+ **CRITICAL**: This is a continuation session. Follow these rules:
332
+
333
+ 1. **DO NOT restart from the beginning** - Work has already been done
334
+ 2. **Read the handoff document first** - Contains full context
335
+ 3. **Continue from the current item** - Pick up exactly where left off
336
+ 4. **Complete current task before moving on** - Don't skip items
337
+ 5. **Signal completion with \`<promise>COMPLETE</promise>\`** when done
338
+
339
+ ---
340
+
341
+ *This prompt was auto-generated by ralph_stop.sh checkpoint handling (ANV-200/ANV-201)*
342
+ RESUME_PROMPT
343
+ log_event "INFO" "Generated resume prompt (fallback): $prompt_file"
344
+ }
345
+
346
+ # =============================================================================
347
+ # Transcript Analysis
348
+ # =============================================================================
349
+
350
+ check_completion_promise() {
351
+ # Check if the Claude transcript contains the completion promise
352
+ # CLAUDE_TRANSCRIPT is set by Claude Code with the session output
353
+
354
+ local transcript="${CLAUDE_TRANSCRIPT:-}"
355
+
356
+ if [[ -z "$transcript" ]]; then
357
+ # No transcript available, check if we can read from stdin or a file
358
+ return 1
359
+ fi
360
+
361
+ if echo "$transcript" | grep -q "<promise>$COMPLETION_PROMISE</promise>"; then
362
+ return 0
363
+ fi
364
+
365
+ return 1
366
+ }
367
+
368
+ check_fatal_error() {
369
+ local transcript="${CLAUDE_TRANSCRIPT:-}"
370
+
371
+ if [[ -z "$transcript" ]]; then
372
+ return 1
373
+ fi
374
+
375
+ if echo "$transcript" | grep -q "<fatal>"; then
376
+ return 0
377
+ fi
378
+
379
+ return 1
380
+ }
381
+
382
+ check_stuck_signals() {
383
+ local transcript="${CLAUDE_TRANSCRIPT:-}"
384
+
385
+ if [[ -z "$transcript" ]]; then
386
+ return 1
387
+ fi
388
+
389
+ # Check for stuck/blocked language
390
+ if echo "$transcript" | grep -qiE "(I'm stuck|cannot proceed|blocked by|unresolvable)"; then
391
+ return 0
392
+ fi
393
+
394
+ return 1
395
+ }
396
+
397
+ # =============================================================================
398
+ # Main Logic
399
+ # =============================================================================
400
+
401
+ main() {
402
+ # Check if Ralph mode is active
403
+ if [[ ! -f "$STATE_FILE" ]]; then
404
+ # Not in Ralph mode, don't interfere
405
+ exit 0
406
+ fi
407
+
408
+ init_state
409
+
410
+ # Read and increment iteration
411
+ local iteration
412
+ iteration=$(read_state "iteration" "0")
413
+ iteration=$((iteration + 1))
414
+ update_state "iteration" "$iteration"
415
+
416
+ log_event "INFO" "Iteration $iteration starting"
417
+
418
+ # ==========================================================================
419
+ # CCS Check: Context checkpoint triggered (ANV-200)
420
+ # ==========================================================================
421
+ if check_ccs_checkpoint; then
422
+ handle_ccs_checkpoint
423
+ git_checkpoint "$iteration"
424
+ exit 1 # Restart loop with checkpoint context
425
+ fi
426
+
427
+ # ==========================================================================
428
+ # Safety Check 1: Max iterations
429
+ # ==========================================================================
430
+ if [[ $iteration -ge $MAX_ITERATIONS ]]; then
431
+ log_event "WARN" "Maximum iterations ($MAX_ITERATIONS) reached"
432
+ update_state "status" "max_iterations"
433
+ cleanup_state
434
+ exit 0 # Allow exit
435
+ fi
436
+
437
+ # ==========================================================================
438
+ # Check 2: Completion promise detected
439
+ # ==========================================================================
440
+ if check_completion_promise; then
441
+ log_event "OK" "Task complete after $iteration iterations! Promise detected."
442
+ update_state "status" "completed"
443
+ cleanup_state
444
+ exit 0 # Allow exit
445
+ fi
446
+
447
+ # ==========================================================================
448
+ # Check 3: Fatal error detected
449
+ # ==========================================================================
450
+ if check_fatal_error; then
451
+ log_event "ERROR" "Fatal error detected - stopping loop"
452
+ update_state "status" "fatal_error"
453
+ cleanup_state
454
+ exit 0 # Allow exit
455
+ fi
456
+
457
+ # ==========================================================================
458
+ # Check 4: Stuck signals detected
459
+ # ==========================================================================
460
+ if check_stuck_signals; then
461
+ log_event "WARN" "Stuck signals detected - may need manual intervention"
462
+ # Don't exit yet, but log warning
463
+ fi
464
+
465
+ # ==========================================================================
466
+ # Check 5: Circuit breaker - no changes
467
+ # ==========================================================================
468
+ if ! check_no_change_circuit; then
469
+ update_state "status" "circuit_breaker"
470
+ cleanup_state
471
+ exit 0 # Allow exit
472
+ fi
473
+
474
+ # ==========================================================================
475
+ # Report Linear progress at iteration boundary (ANV-213)
476
+ # ==========================================================================
477
+ report_linear_progress
478
+
479
+ # ==========================================================================
480
+ # Git checkpoint before restart
481
+ # ==========================================================================
482
+ git_checkpoint "$iteration"
483
+
484
+ # ==========================================================================
485
+ # Continue loop
486
+ # ==========================================================================
487
+ log_event "INFO" "Iteration $iteration incomplete - restarting..."
488
+ exit 1 # Block exit, trigger restart
489
+ }
490
+
491
+ # =============================================================================
492
+ # Entry Point
493
+ # =============================================================================
494
+
495
+ # Check for jq dependency
496
+ if ! command -v jq &> /dev/null; then
497
+ echo "❌ Ralph requires jq for JSON processing" >&2
498
+ echo " Install: apt install jq (Linux) or brew install jq (macOS)" >&2
499
+ exit 0 # Allow exit rather than blocking
500
+ fi
501
+
502
+ main "$@"