feat(enable): add ralph-enable wizard for existing projects (v0.11.0) (#124)

* feat(enable): add ralph-enable wizard for existing projects (v0.11.0)

Add interactive wizard and CI version for enabling Ralph in existing projects.

New commands:
- ralph-enable: Interactive 5-phase wizard for humans
- ralph-enable-ci: Non-interactive version with JSON output for CI/automation

New library components:
- lib/enable_core.sh: Shared logic for idempotency, project detection, templates
- lib/wizard_utils.sh: Interactive prompt utilities
- lib/task_sources.sh: Task import from beads, GitHub Issues, PRD documents

Features:
- Auto-detects project type (TypeScript, Python, Rust, Go)
- Auto-detects framework (Next.js, FastAPI, Django, Express)
- Imports tasks from beads, GitHub Issues, or PRD documents
- Generates .ralphrc project configuration file
- Idempotent: safe to run multiple times, respects existing files
- Exit codes: 0 (success), 1 (error), 2 (already enabled)

Updated:
- install.sh: Added new commands to global installation
- ralph_loop.sh: Loads .ralphrc configuration at startup

Tests: 75 new tests (30 enable_core + 23 task_sources + 22 integration)
Total: 396 tests passing (100% pass rate)

Closes #85, #121, #64, #87, #99

* fix(enable): address code review feedback

Fixes from PR #124 review:

1. sed -i portability (ralph_enable.sh:456)
   - Use portable sed + mv pattern instead of GNU-only sed -i

2. sed regex portability (lib/task_sources.sh)
   - Replace \s with POSIX [[:space:]] character class
   - Add sed -E flag for extended regex

3. jq availability check (ralph_enable_ci.sh:177)
   - Add check for jq when --json flag is used

4. Unused filter parameter (lib/task_sources.sh:44)
   - Pass filter to bd list --filter command

5. Word-splitting in select_multiple (ralph_enable.sh:322)
   - Return comma-separated indices instead of space-separated text
   - Update caller to parse indices correctly

6. Missing || true for check_existing_ralph (ralph_enable.sh:185)
   - Prevent set -e from exiting on non-zero return

7. select_multiple stdout corruption (lib/wizard_utils.sh)
   - Redirect interactive output to stderr
   - Only final result goes to stdout

8. Color variables not exported (lib/wizard_utils.sh:12)
   - Export WIZARD_* color variables for subshells

9. select_option infinite loop (lib/wizard_utils.sh:179)
   - Add guard for empty options array

* fix(tests): add missing mocks and exports for new enable feature

- Add RESPONSE_ANALYSIS_FILE export to test_session_continuity.bats setup
- Add mock ralph_enable.sh and ralph_enable_ci.sh to test_installation.bats
- Add mock lib files: enable_core.sh, wizard_utils.sh, task_sources.sh, timeout_utils.sh

All 396 tests now pass.

* fix(config): fix critical issues from PR review

1. .ralphrc Configuration Loading Fix:
   - Captured env var state BEFORE setting defaults with _env_* variables
   - load_ralphrc now only restores values explicitly set by environment
   - .ralphrc settings are now properly applied (not overwritten by defaults)

2. sed Command Injection Fix:
   - Replaced sed with awk for .ralphrc updates in ralph_enable.sh
   - awk -v pattern safely handles user input without shell injection risk

3. Shell Injection Fix in safe_create_file():
   - Replaced echo with printf '%s\n' for safer content handling
   - Prevents issues with backslashes, -n, and special characters

4. Specific Error Codes:
   - Added ENABLE_INVALID_ARGS=3 for argument errors
   - Added ENABLE_FILE_NOT_FOUND=4 for missing files
   - Added ENABLE_DEPENDENCY_MISSING=5 for missing deps (e.g., jq)
   - Added ENABLE_PERMISSION_DENIED=6 for permission errors
   - Updated ralph_enable.sh and ralph_enable_ci.sh to use specific codes

5. Added tests for .ralphrc loading pattern verification

Test count: 398 (up from 396)

* fix(enable): make --force flag actually overwrite existing files

The --force flag was accepted but safe_create_file() always skipped
existing files regardless of ENABLE_FORCE value.

Changes:
- safe_create_file() now checks ENABLE_FORCE environment variable
- When ENABLE_FORCE="true", overwrites existing files instead of skipping
- Added proper logging for overwrite operations

Added tests:
- Verify enable_ralph_in_directory actually changes file contents with --force
- Test safe_create_file overwrites when ENABLE_FORCE is true
- Test safe_create_file skips when ENABLE_FORCE is false

Test count: 400 (up from 398)

---------

Co-authored-by: Test User <test@example.com>
This commit is contained in:
Frank Bria 2026-01-25 14:37:25 -07:00 committed by GitHub
parent 019b8c738a
commit 910f794fcc
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
15 changed files with 4169 additions and 18 deletions

View file

@ -21,18 +21,30 @@ 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="$RALPH_DIR/.call_count"
TIMESTAMP_FILE="$RALPH_DIR/.last_reset"
USE_TMUX=false
# Save environment variable state BEFORE setting defaults
# These are used by load_ralphrc() to determine which values came from environment
_env_MAX_CALLS_PER_HOUR="${MAX_CALLS_PER_HOUR:-}"
_env_CLAUDE_TIMEOUT_MINUTES="${CLAUDE_TIMEOUT_MINUTES:-}"
_env_CLAUDE_OUTPUT_FORMAT="${CLAUDE_OUTPUT_FORMAT:-}"
_env_CLAUDE_ALLOWED_TOOLS="${CLAUDE_ALLOWED_TOOLS:-}"
_env_CLAUDE_USE_CONTINUE="${CLAUDE_USE_CONTINUE:-}"
_env_CLAUDE_SESSION_EXPIRY_HOURS="${CLAUDE_SESSION_EXPIRY_HOURS:-}"
_env_VERBOSE_PROGRESS="${VERBOSE_PROGRESS:-}"
# Now set defaults (only if not already set by environment)
MAX_CALLS_PER_HOUR="${MAX_CALLS_PER_HOUR:-100}"
VERBOSE_PROGRESS="${VERBOSE_PROGRESS:-false}"
CLAUDE_TIMEOUT_MINUTES="${CLAUDE_TIMEOUT_MINUTES:-15}"
# 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_OUTPUT_FORMAT="${CLAUDE_OUTPUT_FORMAT:-json}"
CLAUDE_ALLOWED_TOOLS="${CLAUDE_ALLOWED_TOOLS:-Write,Bash(git *),Read}"
CLAUDE_USE_CONTINUE="${CLAUDE_USE_CONTINUE:-true}"
CLAUDE_SESSION_FILE="$RALPH_DIR/.claude_session_id" # Session ID persistence file
CLAUDE_MIN_VERSION="2.0.76" # Minimum required Claude CLI version
@ -73,6 +85,65 @@ 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
# .ralphrc configuration file
RALPHRC_FILE=".ralphrc"
RALPHRC_LOADED=false
# load_ralphrc - Load project-specific configuration from .ralphrc
#
# This function sources .ralphrc if it exists, applying project-specific
# settings. Environment variables take precedence over .ralphrc values.
#
# Configuration values that can be overridden:
# - MAX_CALLS_PER_HOUR
# - CLAUDE_TIMEOUT_MINUTES
# - CLAUDE_OUTPUT_FORMAT
# - ALLOWED_TOOLS (mapped to CLAUDE_ALLOWED_TOOLS)
# - SESSION_CONTINUITY (mapped to CLAUDE_USE_CONTINUE)
# - SESSION_EXPIRY_HOURS (mapped to CLAUDE_SESSION_EXPIRY_HOURS)
# - CB_NO_PROGRESS_THRESHOLD
# - CB_SAME_ERROR_THRESHOLD
# - CB_OUTPUT_DECLINE_THRESHOLD
# - RALPH_VERBOSE
#
load_ralphrc() {
if [[ ! -f "$RALPHRC_FILE" ]]; then
return 0
fi
# Source .ralphrc (this may override default values)
# shellcheck source=/dev/null
source "$RALPHRC_FILE"
# Map .ralphrc variable names to internal names
if [[ -n "${ALLOWED_TOOLS:-}" ]]; then
CLAUDE_ALLOWED_TOOLS="$ALLOWED_TOOLS"
fi
if [[ -n "${SESSION_CONTINUITY:-}" ]]; then
CLAUDE_USE_CONTINUE="$SESSION_CONTINUITY"
fi
if [[ -n "${SESSION_EXPIRY_HOURS:-}" ]]; then
CLAUDE_SESSION_EXPIRY_HOURS="$SESSION_EXPIRY_HOURS"
fi
if [[ -n "${RALPH_VERBOSE:-}" ]]; then
VERBOSE_PROGRESS="$RALPH_VERBOSE"
fi
# Restore ONLY values that were explicitly set via environment variables
# (not script defaults). The _env_* variables were captured BEFORE defaults were set.
# If _env_* is non-empty, the user explicitly set it in their environment.
[[ -n "$_env_MAX_CALLS_PER_HOUR" ]] && MAX_CALLS_PER_HOUR="$_env_MAX_CALLS_PER_HOUR"
[[ -n "$_env_CLAUDE_TIMEOUT_MINUTES" ]] && CLAUDE_TIMEOUT_MINUTES="$_env_CLAUDE_TIMEOUT_MINUTES"
[[ -n "$_env_CLAUDE_OUTPUT_FORMAT" ]] && CLAUDE_OUTPUT_FORMAT="$_env_CLAUDE_OUTPUT_FORMAT"
[[ -n "$_env_CLAUDE_ALLOWED_TOOLS" ]] && CLAUDE_ALLOWED_TOOLS="$_env_CLAUDE_ALLOWED_TOOLS"
[[ -n "$_env_CLAUDE_USE_CONTINUE" ]] && CLAUDE_USE_CONTINUE="$_env_CLAUDE_USE_CONTINUE"
[[ -n "$_env_CLAUDE_SESSION_EXPIRY_HOURS" ]] && CLAUDE_SESSION_EXPIRY_HOURS="$_env_CLAUDE_SESSION_EXPIRY_HOURS"
[[ -n "$_env_VERBOSE_PROGRESS" ]] && VERBOSE_PROGRESS="$_env_VERBOSE_PROGRESS"
RALPHRC_LOADED=true
return 0
}
# Colors for terminal output
RED='\033[0;31m'
GREEN='\033[0;32m'
@ -1053,6 +1124,12 @@ loop_count=0
# Main loop
main() {
# Load project-specific configuration from .ralphrc
if load_ralphrc; then
if [[ "$RALPHRC_LOADED" == "true" ]]; then
log_status "INFO" "Loaded configuration from .ralphrc"
fi
fi
log_status "SUCCESS" "🚀 Ralph loop starting with Claude Code"
log_status "INFO" "Max calls per hour: $MAX_CALLS_PER_HOUR"
@ -1087,10 +1164,11 @@ main() {
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 .ralph/PROMPT.md manually in this directory"
echo " 1. Enable Ralph in existing project: ralph-enable"
echo " 2. Create a new project: ralph-setup my-project"
echo " 3. Import existing requirements: ralph-import requirements.md"
echo " 4. Navigate to an existing Ralph project directory"
echo " 5. Or create .ralph/PROMPT.md manually in this directory"
echo ""
echo "Ralph projects should contain: .ralph/PROMPT.md, .ralph/@fix_plan.md, .ralph/specs/, src/, etc."
exit 1