@the-bearded-bear/claude-craft 3.0.2 → 3.1.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/Dev/i18n/de/Common/agents/ralph-conductor.md +146 -0
- package/Dev/i18n/de/Common/commands/ralph-run.md +171 -0
- package/Dev/i18n/de/Common/commands/setup-project-context.md +286 -0
- package/Dev/i18n/en/Common/agents/ralph-conductor.md +146 -0
- package/Dev/i18n/en/Common/commands/ralph-run.md +171 -0
- package/Dev/i18n/en/Common/commands/setup-project-context.md +286 -0
- package/Dev/i18n/es/Common/agents/ralph-conductor.md +146 -0
- package/Dev/i18n/es/Common/commands/ralph-run.md +171 -0
- package/Dev/i18n/es/Common/commands/setup-project-context.md +286 -0
- package/Dev/i18n/fr/Common/agents/ralph-conductor.md +146 -0
- package/Dev/i18n/fr/Common/commands/ralph-run.md +171 -0
- package/Dev/i18n/fr/Common/commands/setup-project-context.md +286 -0
- package/Dev/i18n/pt/Common/agents/ralph-conductor.md +146 -0
- package/Dev/i18n/pt/Common/commands/ralph-run.md +171 -0
- package/Dev/i18n/pt/Common/commands/setup-project-context.md +286 -0
- package/Tools/Ralph/README.md +303 -0
- package/Tools/Ralph/lib/checkpoint.sh +238 -0
- package/Tools/Ralph/lib/circuit-breaker.sh +172 -0
- package/Tools/Ralph/lib/dod-validator.sh +306 -0
- package/Tools/Ralph/lib/loop.sh +232 -0
- package/Tools/Ralph/lib/session.sh +234 -0
- package/Tools/Ralph/ralph.sh +491 -0
- package/Tools/Ralph/templates/ralph.yml.template +178 -0
- package/Tools/i18n/ralph/de.sh +147 -0
- package/Tools/i18n/ralph/en.sh +147 -0
- package/Tools/i18n/ralph/es.sh +147 -0
- package/Tools/i18n/ralph/fr.sh +147 -0
- package/Tools/i18n/ralph/pt.sh +147 -0
- package/cli/index.js +90 -0
- package/package.json +1 -1
|
@@ -0,0 +1,491 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# =============================================================================
|
|
3
|
+
# Ralph Wiggum - Continuous AI Agent Loop
|
|
4
|
+
# Run Claude in a continuous loop until task completion
|
|
5
|
+
# =============================================================================
|
|
6
|
+
|
|
7
|
+
set -e
|
|
8
|
+
|
|
9
|
+
# Version
|
|
10
|
+
RALPH_VERSION="1.0.0"
|
|
11
|
+
|
|
12
|
+
# Script paths
|
|
13
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
14
|
+
LIB_DIR="$SCRIPT_DIR/lib"
|
|
15
|
+
I18N_DIR="$(dirname "$SCRIPT_DIR")/i18n/ralph"
|
|
16
|
+
TEMPLATES_DIR="$SCRIPT_DIR/templates"
|
|
17
|
+
|
|
18
|
+
# Configuration defaults
|
|
19
|
+
DEFAULT_MAX_ITERATIONS=25
|
|
20
|
+
DEFAULT_TIMEOUT=600000
|
|
21
|
+
DEFAULT_DELAY=1000
|
|
22
|
+
DEFAULT_SESSION_DIR=".ralph"
|
|
23
|
+
DEFAULT_CONFIG_FILE="ralph.yml"
|
|
24
|
+
DEFAULT_COMPLETION_MARKER="<promise>COMPLETE</promise>"
|
|
25
|
+
|
|
26
|
+
# i18n Configuration
|
|
27
|
+
VALID_LANGS=("en" "fr" "es" "de" "pt")
|
|
28
|
+
DEFAULT_LANG="en"
|
|
29
|
+
|
|
30
|
+
# Colors
|
|
31
|
+
C_RESET='\033[0m'
|
|
32
|
+
C_BOLD='\033[1m'
|
|
33
|
+
C_DIM='\033[2m'
|
|
34
|
+
C_RED='\033[0;31m'
|
|
35
|
+
C_GREEN='\033[0;32m'
|
|
36
|
+
C_YELLOW='\033[0;33m'
|
|
37
|
+
C_BLUE='\033[0;34m'
|
|
38
|
+
C_MAGENTA='\033[0;35m'
|
|
39
|
+
C_CYAN='\033[0;36m'
|
|
40
|
+
|
|
41
|
+
# Global state
|
|
42
|
+
LANG_ARG=""
|
|
43
|
+
PROMPT=""
|
|
44
|
+
CONFIG_FILE=""
|
|
45
|
+
SESSION_ID=""
|
|
46
|
+
MAX_ITERATIONS=$DEFAULT_MAX_ITERATIONS
|
|
47
|
+
TIMEOUT=$DEFAULT_TIMEOUT
|
|
48
|
+
DELAY=$DEFAULT_DELAY
|
|
49
|
+
VERBOSE=false
|
|
50
|
+
DRY_RUN=false
|
|
51
|
+
CONTINUE_SESSION=""
|
|
52
|
+
|
|
53
|
+
# =============================================================================
|
|
54
|
+
# i18n - Load messages
|
|
55
|
+
# =============================================================================
|
|
56
|
+
|
|
57
|
+
load_messages() {
|
|
58
|
+
local lang="${LANG_ARG:-$DEFAULT_LANG}"
|
|
59
|
+
local msg_file="$I18N_DIR/${lang}.sh"
|
|
60
|
+
|
|
61
|
+
if [[ -f "$msg_file" ]]; then
|
|
62
|
+
# shellcheck source=/dev/null
|
|
63
|
+
source "$msg_file"
|
|
64
|
+
else
|
|
65
|
+
# Fallback to English
|
|
66
|
+
local fallback="$I18N_DIR/en.sh"
|
|
67
|
+
if [[ -f "$fallback" ]]; then
|
|
68
|
+
# shellcheck source=/dev/null
|
|
69
|
+
source "$fallback"
|
|
70
|
+
else
|
|
71
|
+
# Minimal embedded defaults
|
|
72
|
+
MSG_HEADER="Ralph Wiggum - Continuous AI Agent Loop"
|
|
73
|
+
MSG_ERROR="Error"
|
|
74
|
+
MSG_GOODBYE="Goodbye!"
|
|
75
|
+
fi
|
|
76
|
+
fi
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
# =============================================================================
|
|
80
|
+
# Utilities
|
|
81
|
+
# =============================================================================
|
|
82
|
+
|
|
83
|
+
print_header() {
|
|
84
|
+
echo -e "\n${C_CYAN}╔════════════════════════════════════════════════════════════╗${C_RESET}"
|
|
85
|
+
echo -e "${C_CYAN}║${C_RESET} ${C_BOLD}🔁 ${MSG_HEADER}${C_RESET} ${C_CYAN}║${C_RESET}"
|
|
86
|
+
echo -e "${C_CYAN}║${C_RESET} ${C_DIM}${MSG_VERSION} ${RALPH_VERSION}${C_RESET} ${C_CYAN}║${C_RESET}"
|
|
87
|
+
echo -e "${C_CYAN}╚════════════════════════════════════════════════════════════╝${C_RESET}\n"
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
print_success() {
|
|
91
|
+
echo -e "${C_GREEN}✓${C_RESET} $1"
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
print_error() {
|
|
95
|
+
echo -e "${C_RED}✗${C_RESET} $1" >&2
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
print_info() {
|
|
99
|
+
echo -e "${C_BLUE}ℹ${C_RESET} $1"
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
print_warning() {
|
|
103
|
+
echo -e "${C_YELLOW}⚠${C_RESET} $1"
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
print_verbose() {
|
|
107
|
+
if [[ "$VERBOSE" == "true" ]]; then
|
|
108
|
+
echo -e "${C_DIM} $1${C_RESET}"
|
|
109
|
+
fi
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
print_iteration() {
|
|
113
|
+
local current=$1
|
|
114
|
+
local max=$2
|
|
115
|
+
echo -e "\n${C_CYAN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${C_RESET}"
|
|
116
|
+
echo -e "${C_BOLD}${MSG_ITERATION} ${current} ${MSG_OF} ${max}${C_RESET}"
|
|
117
|
+
echo -e "${C_CYAN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${C_RESET}\n"
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
# =============================================================================
|
|
121
|
+
# Dependency checks
|
|
122
|
+
# =============================================================================
|
|
123
|
+
|
|
124
|
+
check_dependencies() {
|
|
125
|
+
local missing=()
|
|
126
|
+
|
|
127
|
+
# Check for claude command
|
|
128
|
+
if ! command -v claude &> /dev/null; then
|
|
129
|
+
missing+=("claude")
|
|
130
|
+
fi
|
|
131
|
+
|
|
132
|
+
# Check for jq (JSON parsing)
|
|
133
|
+
if ! command -v jq &> /dev/null; then
|
|
134
|
+
missing+=("jq")
|
|
135
|
+
fi
|
|
136
|
+
|
|
137
|
+
# Check for git (optional but recommended for checkpointing)
|
|
138
|
+
if ! command -v git &> /dev/null; then
|
|
139
|
+
print_warning "${MSG_ERROR_GIT_NOT_FOUND}"
|
|
140
|
+
fi
|
|
141
|
+
|
|
142
|
+
# Check for yq (YAML parsing - optional)
|
|
143
|
+
if ! command -v yq &> /dev/null; then
|
|
144
|
+
print_verbose "${MSG_ERROR_YQ_NOT_FOUND}"
|
|
145
|
+
fi
|
|
146
|
+
|
|
147
|
+
if [[ ${#missing[@]} -gt 0 ]]; then
|
|
148
|
+
print_error "${MSG_ERROR}: Missing required dependencies: ${missing[*]}"
|
|
149
|
+
exit 1
|
|
150
|
+
fi
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
# =============================================================================
|
|
154
|
+
# Load library modules
|
|
155
|
+
# =============================================================================
|
|
156
|
+
|
|
157
|
+
load_modules() {
|
|
158
|
+
local modules=("session" "loop" "dod-validator" "circuit-breaker" "checkpoint")
|
|
159
|
+
|
|
160
|
+
for module in "${modules[@]}"; do
|
|
161
|
+
local module_file="$LIB_DIR/${module}.sh"
|
|
162
|
+
if [[ -f "$module_file" ]]; then
|
|
163
|
+
# shellcheck source=/dev/null
|
|
164
|
+
source "$module_file"
|
|
165
|
+
print_verbose "Loaded module: $module"
|
|
166
|
+
else
|
|
167
|
+
print_warning "Module not found: $module_file"
|
|
168
|
+
fi
|
|
169
|
+
done
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
# =============================================================================
|
|
173
|
+
# Configuration loading
|
|
174
|
+
# =============================================================================
|
|
175
|
+
|
|
176
|
+
load_config() {
|
|
177
|
+
local config_path="${CONFIG_FILE:-$DEFAULT_CONFIG_FILE}"
|
|
178
|
+
|
|
179
|
+
# Check multiple locations
|
|
180
|
+
local search_paths=(
|
|
181
|
+
"$config_path"
|
|
182
|
+
".claude/$config_path"
|
|
183
|
+
"$PWD/$config_path"
|
|
184
|
+
)
|
|
185
|
+
|
|
186
|
+
for path in "${search_paths[@]}"; do
|
|
187
|
+
if [[ -f "$path" ]]; then
|
|
188
|
+
print_info "${MSG_CONFIG_LOADING}"
|
|
189
|
+
|
|
190
|
+
# Parse YAML config if yq is available
|
|
191
|
+
if command -v yq &> /dev/null; then
|
|
192
|
+
# Session settings
|
|
193
|
+
local max_iter=$(yq e '.session.max_iterations // ""' "$path" 2>/dev/null)
|
|
194
|
+
[[ -n "$max_iter" ]] && MAX_ITERATIONS=$max_iter
|
|
195
|
+
|
|
196
|
+
local timeout=$(yq e '.session.timeout // ""' "$path" 2>/dev/null)
|
|
197
|
+
[[ -n "$timeout" ]] && TIMEOUT=$timeout
|
|
198
|
+
|
|
199
|
+
local delay=$(yq e '.session.delay_between_iterations // ""' "$path" 2>/dev/null)
|
|
200
|
+
[[ -n "$delay" ]] && DELAY=$delay
|
|
201
|
+
|
|
202
|
+
# Circuit breaker settings are loaded in circuit-breaker.sh
|
|
203
|
+
# DoD settings are loaded in dod-validator.sh
|
|
204
|
+
|
|
205
|
+
print_success "${MSG_CONFIG_LOADED}: $path"
|
|
206
|
+
else
|
|
207
|
+
print_warning "${MSG_ERROR_YQ_NOT_FOUND} - Using CLI arguments only"
|
|
208
|
+
fi
|
|
209
|
+
|
|
210
|
+
CONFIG_FILE="$path"
|
|
211
|
+
return 0
|
|
212
|
+
fi
|
|
213
|
+
done
|
|
214
|
+
|
|
215
|
+
print_verbose "${MSG_CONFIG_NOT_FOUND}, ${MSG_CONFIG_USING_DEFAULTS}"
|
|
216
|
+
return 0
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
# =============================================================================
|
|
220
|
+
# Help
|
|
221
|
+
# =============================================================================
|
|
222
|
+
|
|
223
|
+
show_help() {
|
|
224
|
+
echo -e "${C_BOLD}${MSG_HELP_USAGE}:${C_RESET}"
|
|
225
|
+
echo " ralph.sh [options] <prompt>"
|
|
226
|
+
echo ""
|
|
227
|
+
echo -e "${C_BOLD}${MSG_HELP_DESCRIPTION}${C_RESET}"
|
|
228
|
+
echo ""
|
|
229
|
+
echo -e "${C_BOLD}${MSG_HELP_OPTIONS}:${C_RESET}"
|
|
230
|
+
echo " <prompt> ${MSG_HELP_PROMPT}"
|
|
231
|
+
echo " --config=<file> ${MSG_HELP_CONFIG}"
|
|
232
|
+
echo " --continue=<id> ${MSG_HELP_CONTINUE}"
|
|
233
|
+
echo " --max-iterations=<n> ${MSG_HELP_MAX_ITER}"
|
|
234
|
+
echo " --verbose ${MSG_HELP_VERBOSE}"
|
|
235
|
+
echo " --dry-run ${MSG_HELP_DRY_RUN}"
|
|
236
|
+
echo " --lang=<code> ${MSG_HELP_LANG}"
|
|
237
|
+
echo " --help ${MSG_HELP_HELP}"
|
|
238
|
+
echo ""
|
|
239
|
+
echo -e "${C_BOLD}${MSG_HELP_EXAMPLES}:${C_RESET}"
|
|
240
|
+
echo ""
|
|
241
|
+
echo " # ${MSG_HELP_EXAMPLE_BASIC}"
|
|
242
|
+
echo " ralph.sh \"Implement user authentication\""
|
|
243
|
+
echo ""
|
|
244
|
+
echo " # ${MSG_HELP_EXAMPLE_CONFIG}"
|
|
245
|
+
echo " ralph.sh --config=ralph.yml \"Fix the login bug\""
|
|
246
|
+
echo ""
|
|
247
|
+
echo " # ${MSG_HELP_EXAMPLE_RESUME}"
|
|
248
|
+
echo " ralph.sh --continue=abc123"
|
|
249
|
+
echo ""
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
# =============================================================================
|
|
253
|
+
# Argument parsing
|
|
254
|
+
# =============================================================================
|
|
255
|
+
|
|
256
|
+
parse_args() {
|
|
257
|
+
while [[ $# -gt 0 ]]; do
|
|
258
|
+
case "$1" in
|
|
259
|
+
--lang=*)
|
|
260
|
+
LANG_ARG="${1#--lang=}"
|
|
261
|
+
# Validate language
|
|
262
|
+
local valid=false
|
|
263
|
+
for l in "${VALID_LANGS[@]}"; do
|
|
264
|
+
[[ "$LANG_ARG" == "$l" ]] && valid=true
|
|
265
|
+
done
|
|
266
|
+
if ! $valid; then
|
|
267
|
+
echo -e "${C_RED}Invalid language: $LANG_ARG${C_RESET}"
|
|
268
|
+
echo "Valid languages: ${VALID_LANGS[*]}"
|
|
269
|
+
exit 1
|
|
270
|
+
fi
|
|
271
|
+
;;
|
|
272
|
+
--config=*)
|
|
273
|
+
CONFIG_FILE="${1#--config=}"
|
|
274
|
+
;;
|
|
275
|
+
--continue=*)
|
|
276
|
+
CONTINUE_SESSION="${1#--continue=}"
|
|
277
|
+
;;
|
|
278
|
+
--max-iterations=*)
|
|
279
|
+
MAX_ITERATIONS="${1#--max-iterations=}"
|
|
280
|
+
;;
|
|
281
|
+
--timeout=*)
|
|
282
|
+
TIMEOUT="${1#--timeout=}"
|
|
283
|
+
;;
|
|
284
|
+
--delay=*)
|
|
285
|
+
DELAY="${1#--delay=}"
|
|
286
|
+
;;
|
|
287
|
+
--verbose)
|
|
288
|
+
VERBOSE=true
|
|
289
|
+
;;
|
|
290
|
+
--dry-run)
|
|
291
|
+
DRY_RUN=true
|
|
292
|
+
;;
|
|
293
|
+
--help|-h)
|
|
294
|
+
load_messages
|
|
295
|
+
show_help
|
|
296
|
+
exit 0
|
|
297
|
+
;;
|
|
298
|
+
-*)
|
|
299
|
+
echo "Unknown option: $1"
|
|
300
|
+
exit 1
|
|
301
|
+
;;
|
|
302
|
+
*)
|
|
303
|
+
# Positional argument = prompt
|
|
304
|
+
PROMPT="$1"
|
|
305
|
+
;;
|
|
306
|
+
esac
|
|
307
|
+
shift
|
|
308
|
+
done
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
# =============================================================================
|
|
312
|
+
# Main Ralph loop
|
|
313
|
+
# =============================================================================
|
|
314
|
+
|
|
315
|
+
run_ralph() {
|
|
316
|
+
local iteration=0
|
|
317
|
+
local exit_reason=""
|
|
318
|
+
local dod_passed=false
|
|
319
|
+
local start_time=$(date +%s)
|
|
320
|
+
|
|
321
|
+
# Initialize or resume session
|
|
322
|
+
if [[ -n "$CONTINUE_SESSION" ]]; then
|
|
323
|
+
SESSION_ID="$CONTINUE_SESSION"
|
|
324
|
+
resume_session "$SESSION_ID" || {
|
|
325
|
+
print_error "${MSG_SESSION_NOT_FOUND}: $SESSION_ID"
|
|
326
|
+
exit 1
|
|
327
|
+
}
|
|
328
|
+
print_success "${MSG_SESSION_RESUMED}: $SESSION_ID"
|
|
329
|
+
else
|
|
330
|
+
SESSION_ID=$(create_session "$PROMPT")
|
|
331
|
+
print_success "${MSG_SESSION_CREATED}: $SESSION_ID"
|
|
332
|
+
fi
|
|
333
|
+
|
|
334
|
+
# Initialize circuit breaker
|
|
335
|
+
init_circuit_breaker
|
|
336
|
+
|
|
337
|
+
print_info "${MSG_STARTING_LOOP}..."
|
|
338
|
+
print_verbose "${MSG_SESSION_ID}: $SESSION_ID"
|
|
339
|
+
print_verbose "Max iterations: $MAX_ITERATIONS"
|
|
340
|
+
print_verbose "Timeout: ${TIMEOUT}ms"
|
|
341
|
+
|
|
342
|
+
# Main loop
|
|
343
|
+
while [[ $iteration -lt $MAX_ITERATIONS ]]; do
|
|
344
|
+
iteration=$((iteration + 1))
|
|
345
|
+
print_iteration $iteration $MAX_ITERATIONS
|
|
346
|
+
|
|
347
|
+
# Check circuit breaker
|
|
348
|
+
if check_circuit_breaker; then
|
|
349
|
+
exit_reason="circuit_breaker"
|
|
350
|
+
break
|
|
351
|
+
fi
|
|
352
|
+
|
|
353
|
+
# Dry run mode
|
|
354
|
+
if [[ "$DRY_RUN" == "true" ]]; then
|
|
355
|
+
print_info "[DRY-RUN] Would invoke Claude with session $SESSION_ID"
|
|
356
|
+
continue
|
|
357
|
+
fi
|
|
358
|
+
|
|
359
|
+
# Invoke Claude
|
|
360
|
+
print_info "${MSG_INVOKING_CLAUDE}"
|
|
361
|
+
local response
|
|
362
|
+
response=$(invoke_claude "$SESSION_ID" "$PROMPT" "$TIMEOUT")
|
|
363
|
+
local invoke_status=$?
|
|
364
|
+
|
|
365
|
+
if [[ $invoke_status -ne 0 ]]; then
|
|
366
|
+
print_error "${MSG_ERROR}: Claude invocation failed"
|
|
367
|
+
update_circuit_breaker "error" "$response"
|
|
368
|
+
continue
|
|
369
|
+
fi
|
|
370
|
+
|
|
371
|
+
# Update metrics
|
|
372
|
+
update_session_metrics "$SESSION_ID" "$iteration" "$response"
|
|
373
|
+
|
|
374
|
+
# Create checkpoint (async if configured)
|
|
375
|
+
create_checkpoint "$SESSION_ID" "$iteration"
|
|
376
|
+
|
|
377
|
+
# Check Definition of Done
|
|
378
|
+
print_info "${MSG_DOD_CHECKING}"
|
|
379
|
+
if validate_dod "$response" "$CONFIG_FILE"; then
|
|
380
|
+
dod_passed=true
|
|
381
|
+
exit_reason="dod_complete"
|
|
382
|
+
print_success "${MSG_DOD_PASSED}"
|
|
383
|
+
break
|
|
384
|
+
else
|
|
385
|
+
print_warning "${MSG_DOD_FAILED}"
|
|
386
|
+
update_circuit_breaker "no_progress" ""
|
|
387
|
+
fi
|
|
388
|
+
|
|
389
|
+
# Feed response back as prompt for next iteration
|
|
390
|
+
PROMPT="$response"
|
|
391
|
+
|
|
392
|
+
# Rate limiting delay
|
|
393
|
+
if [[ $DELAY -gt 0 ]]; then
|
|
394
|
+
local delay_sec=$((DELAY / 1000))
|
|
395
|
+
print_verbose "${MSG_WAITING} ${delay_sec} ${MSG_SECONDS}..."
|
|
396
|
+
sleep "$delay_sec"
|
|
397
|
+
fi
|
|
398
|
+
done
|
|
399
|
+
|
|
400
|
+
# Check if max iterations reached
|
|
401
|
+
if [[ $iteration -ge $MAX_ITERATIONS && "$dod_passed" != "true" ]]; then
|
|
402
|
+
exit_reason="max_iterations"
|
|
403
|
+
print_warning "${MSG_CB_MAX_REACHED}"
|
|
404
|
+
fi
|
|
405
|
+
|
|
406
|
+
# Calculate duration
|
|
407
|
+
local end_time=$(date +%s)
|
|
408
|
+
local duration=$((end_time - start_time))
|
|
409
|
+
|
|
410
|
+
# Print summary
|
|
411
|
+
print_summary "$SESSION_ID" "$iteration" "$duration" "$dod_passed" "$exit_reason"
|
|
412
|
+
|
|
413
|
+
# Save final state
|
|
414
|
+
save_session "$SESSION_ID" "$exit_reason"
|
|
415
|
+
|
|
416
|
+
# Return appropriate exit code
|
|
417
|
+
if [[ "$dod_passed" == "true" ]]; then
|
|
418
|
+
return 0
|
|
419
|
+
else
|
|
420
|
+
return 1
|
|
421
|
+
fi
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
# =============================================================================
|
|
425
|
+
# Summary
|
|
426
|
+
# =============================================================================
|
|
427
|
+
|
|
428
|
+
print_summary() {
|
|
429
|
+
local session_id="$1"
|
|
430
|
+
local iterations="$2"
|
|
431
|
+
local duration="$3"
|
|
432
|
+
local dod_passed="$4"
|
|
433
|
+
local exit_reason="$5"
|
|
434
|
+
|
|
435
|
+
echo -e "\n${C_CYAN}╔════════════════════════════════════════════════════════════╗${C_RESET}"
|
|
436
|
+
echo -e "${C_CYAN}║${C_RESET} ${C_BOLD}📊 ${MSG_SUMMARY_TITLE}${C_RESET} ${C_CYAN}║${C_RESET}"
|
|
437
|
+
echo -e "${C_CYAN}╚════════════════════════════════════════════════════════════╝${C_RESET}\n"
|
|
438
|
+
|
|
439
|
+
echo -e " ${C_BOLD}${MSG_SESSION_ID}:${C_RESET} $session_id"
|
|
440
|
+
echo -e " ${C_BOLD}${MSG_SUMMARY_ITERATIONS}:${C_RESET} $iterations"
|
|
441
|
+
echo -e " ${C_BOLD}${MSG_SUMMARY_DURATION}:${C_RESET} ${duration}s"
|
|
442
|
+
|
|
443
|
+
if [[ "$dod_passed" == "true" ]]; then
|
|
444
|
+
echo -e " ${C_BOLD}${MSG_SUMMARY_DOD_STATUS}:${C_RESET} ${C_GREEN}${MSG_DOD_PASSED}${C_RESET}"
|
|
445
|
+
else
|
|
446
|
+
echo -e " ${C_BOLD}${MSG_SUMMARY_DOD_STATUS}:${C_RESET} ${C_RED}${MSG_DOD_FAILED}${C_RESET}"
|
|
447
|
+
fi
|
|
448
|
+
|
|
449
|
+
echo -e " ${C_BOLD}${MSG_SUMMARY_EXIT_REASON}:${C_RESET} $exit_reason"
|
|
450
|
+
echo ""
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
# =============================================================================
|
|
454
|
+
# Main
|
|
455
|
+
# =============================================================================
|
|
456
|
+
|
|
457
|
+
main() {
|
|
458
|
+
# Parse arguments first (before loading messages for --lang)
|
|
459
|
+
parse_args "$@"
|
|
460
|
+
|
|
461
|
+
# Load i18n messages
|
|
462
|
+
load_messages
|
|
463
|
+
|
|
464
|
+
# Print header
|
|
465
|
+
print_header
|
|
466
|
+
|
|
467
|
+
# Check dependencies
|
|
468
|
+
check_dependencies
|
|
469
|
+
|
|
470
|
+
# Load library modules
|
|
471
|
+
load_modules
|
|
472
|
+
|
|
473
|
+
# Load configuration
|
|
474
|
+
load_config
|
|
475
|
+
|
|
476
|
+
# Validate we have a prompt or are resuming
|
|
477
|
+
if [[ -z "$PROMPT" && -z "$CONTINUE_SESSION" ]]; then
|
|
478
|
+
print_error "${MSG_ERROR_NO_PROMPT}"
|
|
479
|
+
echo ""
|
|
480
|
+
show_help
|
|
481
|
+
exit 1
|
|
482
|
+
fi
|
|
483
|
+
|
|
484
|
+
# Run the main loop
|
|
485
|
+
run_ralph
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
# Run if executed directly (not sourced)
|
|
489
|
+
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
|
|
490
|
+
main "$@"
|
|
491
|
+
fi
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
# =============================================================================
|
|
2
|
+
# Ralph Wiggum Configuration
|
|
3
|
+
# Continuous AI Agent Loop Configuration
|
|
4
|
+
# =============================================================================
|
|
5
|
+
#
|
|
6
|
+
# Copy this file to your project root as `ralph.yml` or `.claude/ralph.yml`
|
|
7
|
+
# and customize according to your needs.
|
|
8
|
+
#
|
|
9
|
+
# Documentation: https://github.com/TheBeardedBearSAS/claude-craft
|
|
10
|
+
# =============================================================================
|
|
11
|
+
|
|
12
|
+
version: "1.0"
|
|
13
|
+
|
|
14
|
+
# =============================================================================
|
|
15
|
+
# Session Settings
|
|
16
|
+
# =============================================================================
|
|
17
|
+
session:
|
|
18
|
+
# Session ID: "auto" generates a unique ID, or specify a fixed ID
|
|
19
|
+
id: auto
|
|
20
|
+
|
|
21
|
+
# Timeout per Claude invocation (milliseconds)
|
|
22
|
+
# Default: 600000 (10 minutes)
|
|
23
|
+
timeout: 600000
|
|
24
|
+
|
|
25
|
+
# Maximum number of iterations before stopping
|
|
26
|
+
# Default: 25
|
|
27
|
+
max_iterations: 25
|
|
28
|
+
|
|
29
|
+
# Delay between iterations (milliseconds) - rate limiting
|
|
30
|
+
# Default: 1000 (1 second)
|
|
31
|
+
delay_between_iterations: 1000
|
|
32
|
+
|
|
33
|
+
# =============================================================================
|
|
34
|
+
# Circuit Breaker - Safety Mechanism
|
|
35
|
+
# =============================================================================
|
|
36
|
+
# The circuit breaker prevents infinite loops and detects stalls
|
|
37
|
+
circuit_breaker:
|
|
38
|
+
# Enable/disable circuit breaker
|
|
39
|
+
enabled: true
|
|
40
|
+
|
|
41
|
+
# Stop if no file changes detected for N iterations
|
|
42
|
+
no_file_changes_threshold: 3
|
|
43
|
+
|
|
44
|
+
# Stop if same error repeats N times
|
|
45
|
+
repeated_error_threshold: 5
|
|
46
|
+
|
|
47
|
+
# Stop if output length declines by N% from peak
|
|
48
|
+
output_decline_threshold: 70
|
|
49
|
+
|
|
50
|
+
# =============================================================================
|
|
51
|
+
# Git Checkpointing
|
|
52
|
+
# =============================================================================
|
|
53
|
+
# Automatically creates git commits for recovery and history tracking
|
|
54
|
+
checkpointing:
|
|
55
|
+
# Enable/disable checkpointing
|
|
56
|
+
enabled: true
|
|
57
|
+
|
|
58
|
+
# Run checkpointing asynchronously (non-blocking)
|
|
59
|
+
async: true
|
|
60
|
+
|
|
61
|
+
# Branch prefix for Ralph sessions
|
|
62
|
+
branch_prefix: "ralph/"
|
|
63
|
+
|
|
64
|
+
# Commit message template
|
|
65
|
+
# Variables: {iteration}, {session_id}
|
|
66
|
+
commit_message_template: "checkpoint: Ralph iteration {iteration}"
|
|
67
|
+
|
|
68
|
+
# =============================================================================
|
|
69
|
+
# Agent Settings
|
|
70
|
+
# =============================================================================
|
|
71
|
+
# Configure which AI agent to use
|
|
72
|
+
agent:
|
|
73
|
+
# Agent name: claude, kiro, q, gemini
|
|
74
|
+
name: claude
|
|
75
|
+
|
|
76
|
+
# Command to invoke the agent
|
|
77
|
+
command: claude
|
|
78
|
+
|
|
79
|
+
# Additional arguments
|
|
80
|
+
args:
|
|
81
|
+
- "--continue"
|
|
82
|
+
- "${SESSION_ID}"
|
|
83
|
+
- "-p"
|
|
84
|
+
- "${PROMPT}"
|
|
85
|
+
|
|
86
|
+
# =============================================================================
|
|
87
|
+
# Definition of Done (DoD)
|
|
88
|
+
# =============================================================================
|
|
89
|
+
# Criteria that must be met for the task to be considered complete
|
|
90
|
+
definition_of_done:
|
|
91
|
+
# Simple mode: completion marker string
|
|
92
|
+
# If Claude outputs this exact string, task is complete
|
|
93
|
+
completion_marker: "<promise>COMPLETE</promise>"
|
|
94
|
+
|
|
95
|
+
# Advanced mode: checklist of validation criteria
|
|
96
|
+
# Uncomment and customize the checklist below for structured DoD
|
|
97
|
+
#
|
|
98
|
+
# checklist:
|
|
99
|
+
# # -------------------------------------------------------------------------
|
|
100
|
+
# # Validator type: command
|
|
101
|
+
# # Runs a shell command and checks exit code (0 = pass)
|
|
102
|
+
# # -------------------------------------------------------------------------
|
|
103
|
+
# - id: tests
|
|
104
|
+
# name: "All tests pass"
|
|
105
|
+
# type: command
|
|
106
|
+
# command: "docker compose exec app npm test"
|
|
107
|
+
# required: true
|
|
108
|
+
#
|
|
109
|
+
# - id: lint
|
|
110
|
+
# name: "No lint errors"
|
|
111
|
+
# type: command
|
|
112
|
+
# command: "docker compose exec app npm run lint"
|
|
113
|
+
# required: true
|
|
114
|
+
#
|
|
115
|
+
# - id: typecheck
|
|
116
|
+
# name: "TypeScript compiles"
|
|
117
|
+
# type: command
|
|
118
|
+
# command: "docker compose exec app npx tsc --noEmit"
|
|
119
|
+
# required: true
|
|
120
|
+
#
|
|
121
|
+
# - id: build
|
|
122
|
+
# name: "Build succeeds"
|
|
123
|
+
# type: command
|
|
124
|
+
# command: "docker compose exec app npm run build"
|
|
125
|
+
# required: false # Warning only, not blocking
|
|
126
|
+
#
|
|
127
|
+
# # -------------------------------------------------------------------------
|
|
128
|
+
# # Validator type: output_contains
|
|
129
|
+
# # Checks if Claude's output contains a pattern (regex)
|
|
130
|
+
# # -------------------------------------------------------------------------
|
|
131
|
+
# - id: completion
|
|
132
|
+
# name: "Claude signals completion"
|
|
133
|
+
# type: output_contains
|
|
134
|
+
# pattern: "<promise>COMPLETE</promise>"
|
|
135
|
+
# required: true
|
|
136
|
+
#
|
|
137
|
+
# # -------------------------------------------------------------------------
|
|
138
|
+
# # Validator type: file_changed
|
|
139
|
+
# # Checks if files matching pattern were modified
|
|
140
|
+
# # -------------------------------------------------------------------------
|
|
141
|
+
# - id: docs
|
|
142
|
+
# name: "Documentation updated"
|
|
143
|
+
# type: file_changed
|
|
144
|
+
# pattern: "*.md"
|
|
145
|
+
# required: false
|
|
146
|
+
#
|
|
147
|
+
# # -------------------------------------------------------------------------
|
|
148
|
+
# # Validator type: hook
|
|
149
|
+
# # Runs an existing Claude hook script
|
|
150
|
+
# # -------------------------------------------------------------------------
|
|
151
|
+
# - id: quality_gate
|
|
152
|
+
# name: "Quality gate passes"
|
|
153
|
+
# type: hook
|
|
154
|
+
# script: ".claude/hooks/quality-gate.sh"
|
|
155
|
+
# required: true
|
|
156
|
+
#
|
|
157
|
+
# # -------------------------------------------------------------------------
|
|
158
|
+
# # Validator type: human
|
|
159
|
+
# # Prompts for human confirmation (interactive)
|
|
160
|
+
# # -------------------------------------------------------------------------
|
|
161
|
+
# - id: manual_review
|
|
162
|
+
# name: "Manual review approved"
|
|
163
|
+
# type: human
|
|
164
|
+
# prompt: "Does the implementation look correct? (y/n):"
|
|
165
|
+
# required: false
|
|
166
|
+
|
|
167
|
+
# =============================================================================
|
|
168
|
+
# Output Settings
|
|
169
|
+
# =============================================================================
|
|
170
|
+
output:
|
|
171
|
+
# Log file path (relative to session directory)
|
|
172
|
+
log_file: ".ralph/session.log"
|
|
173
|
+
|
|
174
|
+
# Metrics file path (JSON format)
|
|
175
|
+
metrics_file: ".ralph/metrics.json"
|
|
176
|
+
|
|
177
|
+
# Enable verbose output
|
|
178
|
+
verbose: false
|