@the-bearded-bear/claude-craft 3.0.3-next.d0d2746 → 3.1.0-next.a356bbd

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.
@@ -0,0 +1,238 @@
1
+ #!/bin/bash
2
+ # =============================================================================
3
+ # Ralph Wiggum - Git Checkpointing Module
4
+ # Creates git checkpoints for recovery and history tracking
5
+ # =============================================================================
6
+
7
+ # Checkpointing configuration
8
+ CP_ENABLED="${CP_ENABLED:-true}"
9
+ CP_ASYNC="${CP_ASYNC:-true}"
10
+ CP_BRANCH_PREFIX="${CP_BRANCH_PREFIX:-ralph/}"
11
+ CP_COMMIT_TEMPLATE="${CP_COMMIT_TEMPLATE:-checkpoint: Ralph iteration {iteration}}"
12
+
13
+ # =============================================================================
14
+ # Initialization
15
+ # =============================================================================
16
+
17
+ init_checkpointing() {
18
+ # Check if git is available
19
+ if ! command -v git &> /dev/null; then
20
+ CP_ENABLED=false
21
+ print_verbose "Git not found, checkpointing disabled"
22
+ return 1
23
+ fi
24
+
25
+ # Check if we're in a git repository
26
+ if ! git rev-parse --git-dir &> /dev/null; then
27
+ CP_ENABLED=false
28
+ print_verbose "Not in a git repository, checkpointing disabled"
29
+ return 1
30
+ fi
31
+
32
+ # Load config if available
33
+ if [[ -n "$CONFIG_FILE" && -f "$CONFIG_FILE" ]] && command -v yq &> /dev/null; then
34
+ local enabled=$(yq e '.checkpointing.enabled // ""' "$CONFIG_FILE" 2>/dev/null)
35
+ [[ "$enabled" == "false" ]] && CP_ENABLED=false
36
+
37
+ local async=$(yq e '.checkpointing.async // ""' "$CONFIG_FILE" 2>/dev/null)
38
+ [[ "$async" == "false" ]] && CP_ASYNC=false
39
+
40
+ local prefix=$(yq e '.checkpointing.branch_prefix // ""' "$CONFIG_FILE" 2>/dev/null)
41
+ [[ -n "$prefix" ]] && CP_BRANCH_PREFIX="$prefix"
42
+
43
+ local template=$(yq e '.checkpointing.commit_message_template // ""' "$CONFIG_FILE" 2>/dev/null)
44
+ [[ -n "$template" ]] && CP_COMMIT_TEMPLATE="$template"
45
+ fi
46
+
47
+ print_verbose "Checkpointing initialized:"
48
+ print_verbose " - Enabled: $CP_ENABLED"
49
+ print_verbose " - Async: $CP_ASYNC"
50
+ print_verbose " - Branch prefix: $CP_BRANCH_PREFIX"
51
+
52
+ return 0
53
+ }
54
+
55
+ # =============================================================================
56
+ # Create Checkpoint
57
+ # =============================================================================
58
+
59
+ create_checkpoint() {
60
+ local session_id="$1"
61
+ local iteration="$2"
62
+
63
+ if [[ "$CP_ENABLED" != "true" ]]; then
64
+ return 0
65
+ fi
66
+
67
+ # Check for changes to commit
68
+ if [[ -z "$(git status --porcelain 2>/dev/null)" ]]; then
69
+ print_verbose "No changes to checkpoint"
70
+ return 0
71
+ fi
72
+
73
+ # Generate commit message
74
+ local commit_msg="${CP_COMMIT_TEMPLATE/\{iteration\}/$iteration}"
75
+ commit_msg="${commit_msg/\{session_id\}/$session_id}"
76
+
77
+ if [[ "$CP_ASYNC" == "true" ]]; then
78
+ # Run checkpoint in background
79
+ _create_checkpoint_async "$session_id" "$iteration" "$commit_msg" &
80
+ print_verbose "${MSG_CHECKPOINT_CREATING} (async)"
81
+ else
82
+ # Run checkpoint synchronously
83
+ _create_checkpoint_sync "$session_id" "$iteration" "$commit_msg"
84
+ fi
85
+ }
86
+
87
+ # =============================================================================
88
+ # Synchronous Checkpoint
89
+ # =============================================================================
90
+
91
+ _create_checkpoint_sync() {
92
+ local session_id="$1"
93
+ local iteration="$2"
94
+ local commit_msg="$3"
95
+
96
+ print_verbose "${MSG_CHECKPOINT_CREATING}"
97
+
98
+ # Stage all changes
99
+ git add -A 2>/dev/null
100
+
101
+ # Create commit
102
+ local commit_hash
103
+ commit_hash=$(git commit -m "$commit_msg" 2>/dev/null && git rev-parse --short HEAD)
104
+
105
+ if [[ -n "$commit_hash" ]]; then
106
+ print_verbose "${MSG_CHECKPOINT_CREATED}: $commit_hash"
107
+ log_session "$session_id" "INFO" "Checkpoint created: $commit_hash"
108
+ else
109
+ print_verbose "${MSG_CHECKPOINT_FAILED}"
110
+ log_session "$session_id" "WARN" "Checkpoint failed"
111
+ fi
112
+ }
113
+
114
+ # =============================================================================
115
+ # Asynchronous Checkpoint
116
+ # =============================================================================
117
+
118
+ _create_checkpoint_async() {
119
+ local session_id="$1"
120
+ local iteration="$2"
121
+ local commit_msg="$3"
122
+
123
+ # Create a lock file to prevent concurrent checkpoints
124
+ local lock_file="/tmp/ralph-checkpoint-$session_id.lock"
125
+
126
+ # Try to acquire lock
127
+ if ! mkdir "$lock_file" 2>/dev/null; then
128
+ # Another checkpoint is in progress
129
+ return 0
130
+ fi
131
+
132
+ # Cleanup function
133
+ cleanup() {
134
+ rmdir "$lock_file" 2>/dev/null
135
+ }
136
+ trap cleanup EXIT
137
+
138
+ # Stage all changes
139
+ git add -A 2>/dev/null
140
+
141
+ # Create commit
142
+ git commit -m "$commit_msg" 2>/dev/null
143
+
144
+ # Log result
145
+ if [[ $? -eq 0 ]]; then
146
+ local commit_hash=$(git rev-parse --short HEAD 2>/dev/null)
147
+ log_session "$session_id" "INFO" "Async checkpoint created: $commit_hash"
148
+ fi
149
+
150
+ cleanup
151
+ }
152
+
153
+ # =============================================================================
154
+ # Restore from Checkpoint
155
+ # =============================================================================
156
+
157
+ restore_checkpoint() {
158
+ local session_id="$1"
159
+ local commit_hash="$2"
160
+
161
+ if [[ "$CP_ENABLED" != "true" ]]; then
162
+ print_error "Checkpointing is disabled"
163
+ return 1
164
+ fi
165
+
166
+ print_info "${MSG_CHECKPOINT_RESTORING}"
167
+
168
+ # Verify commit exists
169
+ if ! git cat-file -e "$commit_hash" 2>/dev/null; then
170
+ print_error "Commit not found: $commit_hash"
171
+ return 1
172
+ fi
173
+
174
+ # Create a backup branch of current state
175
+ local backup_branch="ralph-backup-$(date +%s)"
176
+ git branch "$backup_branch" 2>/dev/null
177
+
178
+ # Reset to the checkpoint
179
+ if git reset --hard "$commit_hash" 2>/dev/null; then
180
+ print_success "${MSG_CHECKPOINT_RESTORED}"
181
+ log_session "$session_id" "INFO" "Restored to checkpoint: $commit_hash (backup: $backup_branch)"
182
+ return 0
183
+ else
184
+ print_error "${MSG_CHECKPOINT_FAILED}"
185
+ return 1
186
+ fi
187
+ }
188
+
189
+ # =============================================================================
190
+ # List Checkpoints
191
+ # =============================================================================
192
+
193
+ list_checkpoints() {
194
+ local session_id="$1"
195
+
196
+ if [[ "$CP_ENABLED" != "true" ]]; then
197
+ echo "[]"
198
+ return
199
+ fi
200
+
201
+ # Find commits matching the checkpoint pattern
202
+ local commits
203
+ commits=$(git log --oneline --grep="checkpoint: Ralph" 2>/dev/null | head -20)
204
+
205
+ if [[ -n "$commits" ]]; then
206
+ echo "$commits" | while read -r line; do
207
+ local hash=$(echo "$line" | cut -d' ' -f1)
208
+ local msg=$(echo "$line" | cut -d' ' -f2-)
209
+ echo "{\"hash\":\"$hash\",\"message\":\"$msg\"}"
210
+ done | jq -s '.'
211
+ else
212
+ echo "[]"
213
+ fi
214
+ }
215
+
216
+ # =============================================================================
217
+ # Create Branch for Session
218
+ # =============================================================================
219
+
220
+ create_session_branch() {
221
+ local session_id="$1"
222
+ local branch_name="${CP_BRANCH_PREFIX}${session_id}"
223
+
224
+ if [[ "$CP_ENABLED" != "true" ]]; then
225
+ return 1
226
+ fi
227
+
228
+ # Check if branch already exists
229
+ if git show-ref --verify --quiet "refs/heads/$branch_name" 2>/dev/null; then
230
+ # Switch to existing branch
231
+ git checkout "$branch_name" 2>/dev/null
232
+ else
233
+ # Create new branch
234
+ git checkout -b "$branch_name" 2>/dev/null
235
+ fi
236
+
237
+ print_verbose "${MSG_CHECKPOINT_BRANCH}: $branch_name"
238
+ }
@@ -0,0 +1,172 @@
1
+ #!/bin/bash
2
+ # =============================================================================
3
+ # Ralph Wiggum - Circuit Breaker Module
4
+ # Safety mechanism to prevent infinite loops and detect stalls
5
+ # =============================================================================
6
+
7
+ # Circuit breaker thresholds (defaults)
8
+ CB_NO_CHANGES_THRESHOLD="${CB_NO_CHANGES_THRESHOLD:-3}"
9
+ CB_REPEATED_ERROR_THRESHOLD="${CB_REPEATED_ERROR_THRESHOLD:-5}"
10
+ CB_OUTPUT_DECLINE_THRESHOLD="${CB_OUTPUT_DECLINE_THRESHOLD:-70}"
11
+
12
+ # Circuit breaker state
13
+ CB_ITERATIONS_WITHOUT_CHANGES=0
14
+ CB_CONSECUTIVE_ERRORS=0
15
+ CB_PEAK_OUTPUT_LENGTH=0
16
+ CB_LAST_OUTPUT_LENGTH=0
17
+ CB_TRIGGERED=false
18
+ CB_TRIGGER_REASON=""
19
+
20
+ # =============================================================================
21
+ # Initialization
22
+ # =============================================================================
23
+
24
+ init_circuit_breaker() {
25
+ CB_ITERATIONS_WITHOUT_CHANGES=0
26
+ CB_CONSECUTIVE_ERRORS=0
27
+ CB_PEAK_OUTPUT_LENGTH=0
28
+ CB_LAST_OUTPUT_LENGTH=0
29
+ CB_TRIGGERED=false
30
+ CB_TRIGGER_REASON=""
31
+
32
+ # Load thresholds from config if available
33
+ if [[ -n "$CONFIG_FILE" && -f "$CONFIG_FILE" ]] && command -v yq &> /dev/null; then
34
+ local no_changes=$(yq e '.circuit_breaker.no_file_changes_threshold // ""' "$CONFIG_FILE" 2>/dev/null)
35
+ [[ -n "$no_changes" ]] && CB_NO_CHANGES_THRESHOLD=$no_changes
36
+
37
+ local errors=$(yq e '.circuit_breaker.repeated_error_threshold // ""' "$CONFIG_FILE" 2>/dev/null)
38
+ [[ -n "$errors" ]] && CB_REPEATED_ERROR_THRESHOLD=$errors
39
+
40
+ local decline=$(yq e '.circuit_breaker.output_decline_threshold // ""' "$CONFIG_FILE" 2>/dev/null)
41
+ [[ -n "$decline" ]] && CB_OUTPUT_DECLINE_THRESHOLD=$decline
42
+ fi
43
+
44
+ print_verbose "Circuit breaker initialized:"
45
+ print_verbose " - No changes threshold: $CB_NO_CHANGES_THRESHOLD"
46
+ print_verbose " - Error threshold: $CB_REPEATED_ERROR_THRESHOLD"
47
+ print_verbose " - Output decline threshold: ${CB_OUTPUT_DECLINE_THRESHOLD}%"
48
+ }
49
+
50
+ # =============================================================================
51
+ # Circuit Breaker Check
52
+ # =============================================================================
53
+
54
+ check_circuit_breaker() {
55
+ # Return 0 (true) if triggered, 1 (false) if OK to continue
56
+
57
+ # Check no progress (no file changes)
58
+ if [[ $CB_ITERATIONS_WITHOUT_CHANGES -ge $CB_NO_CHANGES_THRESHOLD ]]; then
59
+ CB_TRIGGERED=true
60
+ CB_TRIGGER_REASON="no_progress"
61
+ print_warning "${MSG_CB_TRIGGERED}: ${MSG_CB_NO_CHANGES} $CB_ITERATIONS_WITHOUT_CHANGES ${MSG_CB_ITERATIONS}"
62
+ return 0
63
+ fi
64
+
65
+ # Check repeated errors
66
+ if [[ $CB_CONSECUTIVE_ERRORS -ge $CB_REPEATED_ERROR_THRESHOLD ]]; then
67
+ CB_TRIGGERED=true
68
+ CB_TRIGGER_REASON="repeated_errors"
69
+ print_warning "${MSG_CB_TRIGGERED}: ${MSG_CB_REPEATED_ERRORS}"
70
+ return 0
71
+ fi
72
+
73
+ # Check output decline
74
+ if [[ $CB_PEAK_OUTPUT_LENGTH -gt 0 && $CB_LAST_OUTPUT_LENGTH -gt 0 ]]; then
75
+ local decline_percent=$(( (CB_PEAK_OUTPUT_LENGTH - CB_LAST_OUTPUT_LENGTH) * 100 / CB_PEAK_OUTPUT_LENGTH ))
76
+ if [[ $decline_percent -ge $CB_OUTPUT_DECLINE_THRESHOLD ]]; then
77
+ CB_TRIGGERED=true
78
+ CB_TRIGGER_REASON="output_decline"
79
+ print_warning "${MSG_CB_TRIGGERED}: ${MSG_CB_OUTPUT_DECLINE} ${decline_percent}${MSG_CB_PERCENT}"
80
+ return 0
81
+ fi
82
+ fi
83
+
84
+ return 1
85
+ }
86
+
87
+ # =============================================================================
88
+ # Update Circuit Breaker State
89
+ # =============================================================================
90
+
91
+ update_circuit_breaker() {
92
+ local event_type="$1"
93
+ local output="$2"
94
+
95
+ case "$event_type" in
96
+ progress)
97
+ # Reset counters on progress
98
+ CB_ITERATIONS_WITHOUT_CHANGES=0
99
+ CB_CONSECUTIVE_ERRORS=0
100
+
101
+ # Update output tracking
102
+ local output_length=${#output}
103
+ CB_LAST_OUTPUT_LENGTH=$output_length
104
+ if [[ $output_length -gt $CB_PEAK_OUTPUT_LENGTH ]]; then
105
+ CB_PEAK_OUTPUT_LENGTH=$output_length
106
+ fi
107
+ ;;
108
+
109
+ no_progress)
110
+ CB_ITERATIONS_WITHOUT_CHANGES=$((CB_ITERATIONS_WITHOUT_CHANGES + 1))
111
+ print_verbose "No progress: $CB_ITERATIONS_WITHOUT_CHANGES / $CB_NO_CHANGES_THRESHOLD"
112
+ ;;
113
+
114
+ error)
115
+ CB_CONSECUTIVE_ERRORS=$((CB_CONSECUTIVE_ERRORS + 1))
116
+ print_verbose "Error count: $CB_CONSECUTIVE_ERRORS / $CB_REPEATED_ERROR_THRESHOLD"
117
+ ;;
118
+
119
+ reset)
120
+ CB_ITERATIONS_WITHOUT_CHANGES=0
121
+ CB_CONSECUTIVE_ERRORS=0
122
+ CB_TRIGGERED=false
123
+ CB_TRIGGER_REASON=""
124
+ print_verbose "${MSG_CB_RESET}"
125
+ ;;
126
+ esac
127
+
128
+ # Update session state if available
129
+ if [[ -n "$SESSION_ID" ]]; then
130
+ update_session_state "$SESSION_ID" "circuit_breaker" "{
131
+ \"iterations_without_changes\": $CB_ITERATIONS_WITHOUT_CHANGES,
132
+ \"consecutive_errors\": $CB_CONSECUTIVE_ERRORS,
133
+ \"peak_output_length\": $CB_PEAK_OUTPUT_LENGTH,
134
+ \"last_output_length\": $CB_LAST_OUTPUT_LENGTH,
135
+ \"triggered\": $CB_TRIGGERED,
136
+ \"trigger_reason\": \"$CB_TRIGGER_REASON\"
137
+ }"
138
+ fi
139
+ }
140
+
141
+ # =============================================================================
142
+ # Circuit Breaker Status
143
+ # =============================================================================
144
+
145
+ get_circuit_breaker_status() {
146
+ cat <<EOF
147
+ {
148
+ "iterations_without_changes": $CB_ITERATIONS_WITHOUT_CHANGES,
149
+ "consecutive_errors": $CB_CONSECUTIVE_ERRORS,
150
+ "peak_output_length": $CB_PEAK_OUTPUT_LENGTH,
151
+ "last_output_length": $CB_LAST_OUTPUT_LENGTH,
152
+ "triggered": $CB_TRIGGERED,
153
+ "trigger_reason": "$CB_TRIGGER_REASON",
154
+ "thresholds": {
155
+ "no_changes": $CB_NO_CHANGES_THRESHOLD,
156
+ "errors": $CB_REPEATED_ERROR_THRESHOLD,
157
+ "output_decline": $CB_OUTPUT_DECLINE_THRESHOLD
158
+ }
159
+ }
160
+ EOF
161
+ }
162
+
163
+ # =============================================================================
164
+ # Force Trip
165
+ # =============================================================================
166
+
167
+ trip_circuit_breaker() {
168
+ local reason="$1"
169
+ CB_TRIGGERED=true
170
+ CB_TRIGGER_REASON="${reason:-manual}"
171
+ print_warning "${MSG_CB_TRIGGERED}: $CB_TRIGGER_REASON"
172
+ }