feat(structure): migrate Ralph files to .ralph/ subfolder (#109)
* feat(structure): migrate Ralph files to .ralph/ subfolder BREAKING CHANGE: Ralph configuration files now live in .ralph/ subfolder This refactoring moves all Ralph-specific files into a hidden .ralph/ directory while keeping src/ at the project root. This improves compatibility with existing tooling and keeps the project root clean. Changes: - Move PROMPT.md, @fix_plan.md, @AGENT.md to .ralph/ - Move specs/, logs/, docs/generated/, examples/ to .ralph/ - Move state files (.response_analysis, .circuit_breaker_state, etc.) to .ralph/ - Keep src/ at project root (unchanged) - Add RALPH_DIR=".ralph" configuration variable - Add ralph-migrate command for existing projects - Create migrate_to_ralph_folder.sh migration script - Update all path references in scripts and tests - Update documentation (README.md, CLAUDE.md) New project structure: project/ ├── .ralph/ # Ralph configuration │ ├── PROMPT.md │ ├── @fix_plan.md │ ├── @AGENT.md │ ├── specs/ │ ├── logs/ │ └── docs/generated/ └── src/ # Source code (unchanged) Migration: Run `ralph-migrate` in existing projects to upgrade. All 310 tests pass (100% pass rate). * chore: add .claude/settings.local.json to .gitignore * fix: address code review feedback for .ralph/ subfolder structure Fixes multiple path-related issues identified in code review: Test fixes: - Fix create_sample_prompt to use $RALPH_DIR/PROMPT.md in test_session_continuity.bats - Fix result_file path to use $RALPH_DIR/.json_parse_result in test_json_parsing.bats - Fix @fix_plan.md and .response_analysis paths in test_cli_modern.bats - Update templates directory missing test to account for global fallback Template fix: - Fix @fix_plan.md reference in templates/PROMPT.md to use .ralph/ prefix Script fixes: - Fix PROMPT_FILE comparison in ralph_loop.sh to use $RALPH_DIR/PROMPT.md - Fix examples migration logic in migrate_to_ralph_folder.sh (remove premature mkdir) - Move templates directory check AFTER cd in setup.sh (was checking wrong location) - Add template directory validation with fallback to global templates All 310 tests pass. * Update migrate_to_ralph_folder.sh Co-authored-by: macroscopeapp[bot] <170038800+macroscopeapp[bot]@users.noreply.github.com> * fix: address code review feedback for .ralph/ subfolder structure Code Review Fixes: - Fix test_json_parsing.bats: all result_file and session file paths now use $RALPH_DIR prefix - Fix ralph_loop.sh help text: paths now show .ralph/.ralph_session, .ralph/.call_count, etc. - Fix migrate_to_ralph_folder.sh: - Proper error handling for date command (separate local declaration) - Use cp -a source/. dest/ pattern to preserve dotfiles and attributes - Remove 2>/dev/null suppression to surface copy errors - Update create_files.sh to use .ralph/ structure for embedded scripts - Update .gitignore with all .ralph/ state file paths - Add old structure detection in ralph_loop.sh with helpful migration message Version Update: - Bump to v0.10.0 (breaking change: structural reorganization) - Update README.md and CLAUDE.md with new version and release notes - Add ralph-migrate documentation to Key Commands section All 310 tests pass. --------- Co-authored-by: macroscopeapp[bot] <170038800+macroscopeapp[bot]@users.noreply.github.com>
This commit is contained in:
parent
0e95f67318
commit
9b19d70e35
27 changed files with 1126 additions and 585 deletions
|
|
@ -13,31 +13,33 @@ source "$SCRIPT_DIR/lib/response_analyzer.sh"
|
|||
source "$SCRIPT_DIR/lib/circuit_breaker.sh"
|
||||
|
||||
# Configuration
|
||||
PROMPT_FILE="PROMPT.md"
|
||||
LOG_DIR="logs"
|
||||
DOCS_DIR="docs/generated"
|
||||
STATUS_FILE="status.json"
|
||||
PROGRESS_FILE="progress.json"
|
||||
# Ralph-specific files live in .ralph/ subfolder
|
||||
RALPH_DIR=".ralph"
|
||||
PROMPT_FILE="$RALPH_DIR/PROMPT.md"
|
||||
LOG_DIR="$RALPH_DIR/logs"
|
||||
DOCS_DIR="$RALPH_DIR/docs/generated"
|
||||
STATUS_FILE="$RALPH_DIR/status.json"
|
||||
PROGRESS_FILE="$RALPH_DIR/progress.json"
|
||||
CLAUDE_CODE_CMD="claude"
|
||||
MAX_CALLS_PER_HOUR=100 # Adjust based on your plan
|
||||
VERBOSE_PROGRESS=false # Default: no verbose progress updates
|
||||
CLAUDE_TIMEOUT_MINUTES=15 # Default: 15 minutes timeout for Claude Code execution
|
||||
SLEEP_DURATION=3600 # 1 hour in seconds
|
||||
CALL_COUNT_FILE=".call_count"
|
||||
TIMESTAMP_FILE=".last_reset"
|
||||
CALL_COUNT_FILE="$RALPH_DIR/.call_count"
|
||||
TIMESTAMP_FILE="$RALPH_DIR/.last_reset"
|
||||
USE_TMUX=false
|
||||
|
||||
# Modern Claude CLI configuration (Phase 1.1)
|
||||
CLAUDE_OUTPUT_FORMAT="json" # Options: json, text
|
||||
CLAUDE_ALLOWED_TOOLS="Write,Bash(git *),Read" # Comma-separated list of allowed tools
|
||||
CLAUDE_USE_CONTINUE=true # Enable session continuity
|
||||
CLAUDE_SESSION_FILE=".claude_session_id" # Session ID persistence file
|
||||
CLAUDE_SESSION_FILE="$RALPH_DIR/.claude_session_id" # Session ID persistence file
|
||||
CLAUDE_MIN_VERSION="2.0.76" # Minimum required Claude CLI version
|
||||
|
||||
# Session management configuration (Phase 1.2)
|
||||
# Note: SESSION_EXPIRATION_SECONDS is defined in lib/response_analyzer.sh (86400 = 24 hours)
|
||||
RALPH_SESSION_FILE=".ralph_session" # Ralph-specific session tracking (lifecycle)
|
||||
RALPH_SESSION_HISTORY_FILE=".ralph_session_history" # Session transition history
|
||||
RALPH_SESSION_FILE="$RALPH_DIR/.ralph_session" # Ralph-specific session tracking (lifecycle)
|
||||
RALPH_SESSION_HISTORY_FILE="$RALPH_DIR/.ralph_session_history" # Session transition history
|
||||
# Session expiration: 24 hours default balances project continuity with fresh context
|
||||
# Too short = frequent context loss; Too long = stale context causes unpredictable behavior
|
||||
CLAUDE_SESSION_EXPIRY_HOURS=${CLAUDE_SESSION_EXPIRY_HOURS:-24}
|
||||
|
|
@ -65,7 +67,8 @@ VALID_TOOL_PATTERNS=(
|
|||
)
|
||||
|
||||
# Exit detection configuration
|
||||
EXIT_SIGNALS_FILE=".exit_signals"
|
||||
EXIT_SIGNALS_FILE="$RALPH_DIR/.exit_signals"
|
||||
RESPONSE_ANALYSIS_FILE="$RALPH_DIR/.response_analysis"
|
||||
MAX_CONSECUTIVE_TEST_LOOPS=3
|
||||
MAX_CONSECUTIVE_DONE_SIGNALS=2
|
||||
TEST_PERCENTAGE_THRESHOLD=30 # If more than 30% of recent loops are test-only, flag it
|
||||
|
|
@ -124,7 +127,7 @@ setup_tmux_session() {
|
|||
if [[ "$MAX_CALLS_PER_HOUR" != "100" ]]; then
|
||||
ralph_cmd="$ralph_cmd --calls $MAX_CALLS_PER_HOUR"
|
||||
fi
|
||||
if [[ "$PROMPT_FILE" != "PROMPT.md" ]]; then
|
||||
if [[ "$PROMPT_FILE" != "$RALPH_DIR/PROMPT.md" ]]; then
|
||||
ralph_cmd="$ralph_cmd --prompt '$PROMPT_FILE'"
|
||||
fi
|
||||
|
||||
|
|
@ -315,8 +318,8 @@ should_exit_gracefully() {
|
|||
# but Claude explicitly indicates work is still in progress via RALPH_STATUS block.
|
||||
# The exit_signal in .response_analysis represents Claude's explicit intent.
|
||||
local claude_exit_signal="false"
|
||||
if [[ -f ".response_analysis" ]]; then
|
||||
claude_exit_signal=$(jq -r '.analysis.exit_signal // false' ".response_analysis" 2>/dev/null || echo "false")
|
||||
if [[ -f "$RESPONSE_ANALYSIS_FILE" ]]; then
|
||||
claude_exit_signal=$(jq -r '.analysis.exit_signal // false' "$RESPONSE_ANALYSIS_FILE" 2>/dev/null || echo "false")
|
||||
fi
|
||||
|
||||
if [[ $recent_completion_indicators -ge 2 ]] && [[ "$claude_exit_signal" == "true" ]]; then
|
||||
|
|
@ -328,23 +331,23 @@ should_exit_gracefully() {
|
|||
fi
|
||||
|
||||
# 4. Check fix_plan.md for completion
|
||||
if [[ -f "@fix_plan.md" ]]; then
|
||||
local total_items=$(grep -c "^- \[" "@fix_plan.md" 2>/dev/null)
|
||||
local completed_items=$(grep -c "^- \[x\]" "@fix_plan.md" 2>/dev/null)
|
||||
|
||||
if [[ -f "$RALPH_DIR/@fix_plan.md" ]]; then
|
||||
local total_items=$(grep -c "^- \[" "$RALPH_DIR/@fix_plan.md" 2>/dev/null)
|
||||
local completed_items=$(grep -c "^- \[x\]" "$RALPH_DIR/@fix_plan.md" 2>/dev/null)
|
||||
|
||||
# Handle case where grep returns no matches (exit code 1)
|
||||
[[ -z "$total_items" ]] && total_items=0
|
||||
[[ -z "$completed_items" ]] && completed_items=0
|
||||
|
||||
log_status "INFO" "DEBUG: @fix_plan.md check - total_items:$total_items, completed_items:$completed_items" >&2
|
||||
|
||||
|
||||
log_status "INFO" "DEBUG: .ralph/@fix_plan.md check - total_items:$total_items, completed_items:$completed_items" >&2
|
||||
|
||||
if [[ $total_items -gt 0 ]] && [[ $completed_items -eq $total_items ]]; then
|
||||
log_status "WARN" "Exit condition: All fix_plan.md items completed ($completed_items/$total_items)" >&2
|
||||
echo "plan_complete"
|
||||
return 0
|
||||
fi
|
||||
else
|
||||
log_status "INFO" "DEBUG: @fix_plan.md file not found" >&2
|
||||
log_status "INFO" "DEBUG: .ralph/@fix_plan.md file not found" >&2
|
||||
fi
|
||||
|
||||
log_status "INFO" "DEBUG: No exit conditions met, continuing loop" >&2
|
||||
|
|
@ -442,22 +445,22 @@ build_loop_context() {
|
|||
context="Loop #${loop_count}. "
|
||||
|
||||
# Extract incomplete tasks from @fix_plan.md
|
||||
if [[ -f "@fix_plan.md" ]]; then
|
||||
local incomplete_tasks=$(grep -c "^- \[ \]" "@fix_plan.md" 2>/dev/null || echo "0")
|
||||
if [[ -f "$RALPH_DIR/@fix_plan.md" ]]; then
|
||||
local incomplete_tasks=$(grep -c "^- \[ \]" "$RALPH_DIR/@fix_plan.md" 2>/dev/null || echo "0")
|
||||
context+="Remaining tasks: ${incomplete_tasks}. "
|
||||
fi
|
||||
|
||||
# Add circuit breaker state
|
||||
if [[ -f ".circuit_breaker_state" ]]; then
|
||||
local cb_state=$(jq -r '.state // "UNKNOWN"' .circuit_breaker_state 2>/dev/null)
|
||||
if [[ -f "$RALPH_DIR/.circuit_breaker_state" ]]; then
|
||||
local cb_state=$(jq -r '.state // "UNKNOWN"' "$RALPH_DIR/.circuit_breaker_state" 2>/dev/null)
|
||||
if [[ "$cb_state" != "CLOSED" && "$cb_state" != "null" && -n "$cb_state" ]]; then
|
||||
context+="Circuit breaker: ${cb_state}. "
|
||||
fi
|
||||
fi
|
||||
|
||||
# Add previous loop summary (truncated)
|
||||
if [[ -f ".response_analysis" ]]; then
|
||||
local prev_summary=$(jq -r '.analysis.work_summary // ""' .response_analysis 2>/dev/null | head -c 200)
|
||||
if [[ -f "$RESPONSE_ANALYSIS_FILE" ]]; then
|
||||
local prev_summary=$(jq -r '.analysis.work_summary // ""' "$RESPONSE_ANALYSIS_FILE" 2>/dev/null | head -c 200)
|
||||
if [[ -n "$prev_summary" && "$prev_summary" != "null" ]]; then
|
||||
context+="Previous: ${prev_summary}"
|
||||
fi
|
||||
|
|
@ -1028,32 +1031,46 @@ loop_count=0
|
|||
|
||||
# Main loop
|
||||
main() {
|
||||
|
||||
|
||||
log_status "SUCCESS" "🚀 Ralph loop starting with Claude Code"
|
||||
log_status "INFO" "Max calls per hour: $MAX_CALLS_PER_HOUR"
|
||||
log_status "INFO" "Logs: $LOG_DIR/ | Docs: $DOCS_DIR/ | Status: $STATUS_FILE"
|
||||
|
||||
|
||||
# Check if project uses old flat structure and needs migration
|
||||
if [[ -f "PROMPT.md" ]] && [[ ! -d ".ralph" ]]; then
|
||||
log_status "ERROR" "This project uses the old flat structure."
|
||||
echo ""
|
||||
echo "Ralph v0.10.0+ uses a .ralph/ subfolder to keep your project root clean."
|
||||
echo ""
|
||||
echo "To upgrade your project, run:"
|
||||
echo " ralph-migrate"
|
||||
echo ""
|
||||
echo "This will move Ralph-specific files to .ralph/ while preserving src/ at root."
|
||||
echo "A backup will be created before migration."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check if this is a Ralph project directory
|
||||
if [[ ! -f "$PROMPT_FILE" ]]; then
|
||||
log_status "ERROR" "Prompt file '$PROMPT_FILE' not found!"
|
||||
echo ""
|
||||
|
||||
# Check if this looks like a partial Ralph project
|
||||
if [[ -f "@fix_plan.md" ]] || [[ -d "specs" ]] || [[ -f "@AGENT.md" ]]; then
|
||||
echo "This appears to be a Ralph project but is missing PROMPT.md."
|
||||
if [[ -f "$RALPH_DIR/@fix_plan.md" ]] || [[ -d "$RALPH_DIR/specs" ]] || [[ -f "$RALPH_DIR/@AGENT.md" ]]; then
|
||||
echo "This appears to be a Ralph project but is missing .ralph/PROMPT.md."
|
||||
echo "You may need to create or restore the PROMPT.md file."
|
||||
else
|
||||
echo "This directory is not a Ralph project."
|
||||
fi
|
||||
|
||||
|
||||
echo ""
|
||||
echo "To fix this:"
|
||||
echo " 1. Create a new project: ralph-setup my-project"
|
||||
echo " 2. Import existing requirements: ralph-import requirements.md"
|
||||
echo " 3. Navigate to an existing Ralph project directory"
|
||||
echo " 4. Or create PROMPT.md manually in this directory"
|
||||
echo " 4. Or create .ralph/PROMPT.md manually in this directory"
|
||||
echo ""
|
||||
echo "Ralph projects should contain: PROMPT.md, @fix_plan.md, specs/, src/, etc."
|
||||
echo "Ralph projects should contain: .ralph/PROMPT.md, .ralph/@fix_plan.md, .ralph/specs/, src/, etc."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
|
@ -1203,10 +1220,10 @@ Files created:
|
|||
- $LOG_DIR/: All execution logs
|
||||
- $DOCS_DIR/: Generated documentation
|
||||
- $STATUS_FILE: Current status (JSON)
|
||||
- .ralph_session: Session lifecycle tracking
|
||||
- .ralph_session_history: Session transition history (last 50)
|
||||
- .call_count: API call counter for rate limiting
|
||||
- .last_reset: Timestamp of last rate limit reset
|
||||
- .ralph/.ralph_session: Session lifecycle tracking
|
||||
- .ralph/.ralph_session_history: Session transition history (last 50)
|
||||
- .ralph/.call_count: API call counter for rate limiting
|
||||
- .ralph/.last_reset: Timestamp of last rate limit reset
|
||||
|
||||
Example workflow:
|
||||
ralph-setup my-project # Create project
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue