wiggum-cli 0.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/LICENSE +21 -0
- package/README.md +341 -0
- package/bin/ralph.js +8 -0
- package/dist/ai/enhancer.d.ts +100 -0
- package/dist/ai/enhancer.d.ts.map +1 -0
- package/dist/ai/enhancer.js +233 -0
- package/dist/ai/enhancer.js.map +1 -0
- package/dist/ai/index.d.ts +8 -0
- package/dist/ai/index.d.ts.map +1 -0
- package/dist/ai/index.js +11 -0
- package/dist/ai/index.js.map +1 -0
- package/dist/ai/prompts.d.ts +26 -0
- package/dist/ai/prompts.d.ts.map +1 -0
- package/dist/ai/prompts.js +201 -0
- package/dist/ai/prompts.js.map +1 -0
- package/dist/ai/providers.d.ts +35 -0
- package/dist/ai/providers.d.ts.map +1 -0
- package/dist/ai/providers.js +104 -0
- package/dist/ai/providers.js.map +1 -0
- package/dist/cli.d.ts +6 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +196 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/init.d.ts +16 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +124 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/monitor.d.ts +17 -0
- package/dist/commands/monitor.d.ts.map +1 -0
- package/dist/commands/monitor.js +342 -0
- package/dist/commands/monitor.js.map +1 -0
- package/dist/commands/new.d.ts +19 -0
- package/dist/commands/new.d.ts.map +1 -0
- package/dist/commands/new.js +272 -0
- package/dist/commands/new.js.map +1 -0
- package/dist/commands/run.d.ts +16 -0
- package/dist/commands/run.d.ts.map +1 -0
- package/dist/commands/run.js +175 -0
- package/dist/commands/run.js.map +1 -0
- package/dist/generator/config.d.ts +59 -0
- package/dist/generator/config.d.ts.map +1 -0
- package/dist/generator/config.js +68 -0
- package/dist/generator/config.js.map +1 -0
- package/dist/generator/index.d.ts +64 -0
- package/dist/generator/index.d.ts.map +1 -0
- package/dist/generator/index.js +147 -0
- package/dist/generator/index.js.map +1 -0
- package/dist/generator/templates.d.ts +70 -0
- package/dist/generator/templates.d.ts.map +1 -0
- package/dist/generator/templates.js +296 -0
- package/dist/generator/templates.js.map +1 -0
- package/dist/generator/writer.d.ts +93 -0
- package/dist/generator/writer.d.ts.map +1 -0
- package/dist/generator/writer.js +213 -0
- package/dist/generator/writer.js.map +1 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +17 -0
- package/dist/index.js.map +1 -0
- package/dist/scanner/detectors/core/framework.d.ts +11 -0
- package/dist/scanner/detectors/core/framework.d.ts.map +1 -0
- package/dist/scanner/detectors/core/framework.js +275 -0
- package/dist/scanner/detectors/core/framework.js.map +1 -0
- package/dist/scanner/detectors/core/packageManager.d.ts +11 -0
- package/dist/scanner/detectors/core/packageManager.d.ts.map +1 -0
- package/dist/scanner/detectors/core/packageManager.js +74 -0
- package/dist/scanner/detectors/core/packageManager.js.map +1 -0
- package/dist/scanner/detectors/core/styling.d.ts +12 -0
- package/dist/scanner/detectors/core/styling.d.ts.map +1 -0
- package/dist/scanner/detectors/core/styling.js +230 -0
- package/dist/scanner/detectors/core/styling.js.map +1 -0
- package/dist/scanner/detectors/core/testing.d.ts +12 -0
- package/dist/scanner/detectors/core/testing.d.ts.map +1 -0
- package/dist/scanner/detectors/core/testing.js +190 -0
- package/dist/scanner/detectors/core/testing.js.map +1 -0
- package/dist/scanner/detectors/data/api.d.ts +12 -0
- package/dist/scanner/detectors/data/api.d.ts.map +1 -0
- package/dist/scanner/detectors/data/api.js +261 -0
- package/dist/scanner/detectors/data/api.js.map +1 -0
- package/dist/scanner/detectors/data/database.d.ts +12 -0
- package/dist/scanner/detectors/data/database.d.ts.map +1 -0
- package/dist/scanner/detectors/data/database.js +213 -0
- package/dist/scanner/detectors/data/database.js.map +1 -0
- package/dist/scanner/detectors/data/orm.d.ts +12 -0
- package/dist/scanner/detectors/data/orm.d.ts.map +1 -0
- package/dist/scanner/detectors/data/orm.js +160 -0
- package/dist/scanner/detectors/data/orm.js.map +1 -0
- package/dist/scanner/detectors/frontend/formHandling.d.ts +12 -0
- package/dist/scanner/detectors/frontend/formHandling.d.ts.map +1 -0
- package/dist/scanner/detectors/frontend/formHandling.js +211 -0
- package/dist/scanner/detectors/frontend/formHandling.js.map +1 -0
- package/dist/scanner/detectors/frontend/stateManagement.d.ts +12 -0
- package/dist/scanner/detectors/frontend/stateManagement.d.ts.map +1 -0
- package/dist/scanner/detectors/frontend/stateManagement.js +221 -0
- package/dist/scanner/detectors/frontend/stateManagement.js.map +1 -0
- package/dist/scanner/detectors/frontend/uiComponents.d.ts +12 -0
- package/dist/scanner/detectors/frontend/uiComponents.d.ts.map +1 -0
- package/dist/scanner/detectors/frontend/uiComponents.js +285 -0
- package/dist/scanner/detectors/frontend/uiComponents.js.map +1 -0
- package/dist/scanner/detectors/infra/deployment.d.ts +12 -0
- package/dist/scanner/detectors/infra/deployment.d.ts.map +1 -0
- package/dist/scanner/detectors/infra/deployment.js +301 -0
- package/dist/scanner/detectors/infra/deployment.js.map +1 -0
- package/dist/scanner/detectors/infra/monorepo.d.ts +12 -0
- package/dist/scanner/detectors/infra/monorepo.d.ts.map +1 -0
- package/dist/scanner/detectors/infra/monorepo.js +219 -0
- package/dist/scanner/detectors/infra/monorepo.js.map +1 -0
- package/dist/scanner/detectors/mcp/mcpProject.d.ts +12 -0
- package/dist/scanner/detectors/mcp/mcpProject.d.ts.map +1 -0
- package/dist/scanner/detectors/mcp/mcpProject.js +154 -0
- package/dist/scanner/detectors/mcp/mcpProject.js.map +1 -0
- package/dist/scanner/detectors/mcp/mcpServers.d.ts +17 -0
- package/dist/scanner/detectors/mcp/mcpServers.d.ts.map +1 -0
- package/dist/scanner/detectors/mcp/mcpServers.js +193 -0
- package/dist/scanner/detectors/mcp/mcpServers.js.map +1 -0
- package/dist/scanner/detectors/services/analytics.d.ts +12 -0
- package/dist/scanner/detectors/services/analytics.d.ts.map +1 -0
- package/dist/scanner/detectors/services/analytics.js +236 -0
- package/dist/scanner/detectors/services/analytics.js.map +1 -0
- package/dist/scanner/detectors/services/auth.d.ts +12 -0
- package/dist/scanner/detectors/services/auth.d.ts.map +1 -0
- package/dist/scanner/detectors/services/auth.js +217 -0
- package/dist/scanner/detectors/services/auth.js.map +1 -0
- package/dist/scanner/detectors/services/email.d.ts +12 -0
- package/dist/scanner/detectors/services/email.d.ts.map +1 -0
- package/dist/scanner/detectors/services/email.js +211 -0
- package/dist/scanner/detectors/services/email.js.map +1 -0
- package/dist/scanner/detectors/services/payments.d.ts +12 -0
- package/dist/scanner/detectors/services/payments.d.ts.map +1 -0
- package/dist/scanner/detectors/services/payments.js +185 -0
- package/dist/scanner/detectors/services/payments.js.map +1 -0
- package/dist/scanner/detectors/utils.d.ts +160 -0
- package/dist/scanner/detectors/utils.d.ts.map +1 -0
- package/dist/scanner/detectors/utils.js +222 -0
- package/dist/scanner/detectors/utils.js.map +1 -0
- package/dist/scanner/index.d.ts +42 -0
- package/dist/scanner/index.d.ts.map +1 -0
- package/dist/scanner/index.js +282 -0
- package/dist/scanner/index.js.map +1 -0
- package/dist/scanner/registry.d.ts +43 -0
- package/dist/scanner/registry.d.ts.map +1 -0
- package/dist/scanner/registry.js +243 -0
- package/dist/scanner/registry.js.map +1 -0
- package/dist/scanner/types.d.ts +112 -0
- package/dist/scanner/types.d.ts.map +1 -0
- package/dist/scanner/types.js +6 -0
- package/dist/scanner/types.js.map +1 -0
- package/dist/templates/config/ralph.config.js.tmpl +38 -0
- package/dist/templates/guides/AGENTS.md.tmpl +100 -0
- package/dist/templates/guides/FRONTEND.md.tmpl +523 -0
- package/dist/templates/guides/PERFORMANCE.md.tmpl +264 -0
- package/dist/templates/guides/SECURITY.md.tmpl +100 -0
- package/dist/templates/prompts/PROMPT.md.tmpl +77 -0
- package/dist/templates/prompts/PROMPT_e2e.md.tmpl +234 -0
- package/dist/templates/prompts/PROMPT_feature.md.tmpl +83 -0
- package/dist/templates/prompts/PROMPT_review.md.tmpl +167 -0
- package/dist/templates/prompts/PROMPT_verify.md.tmpl +72 -0
- package/dist/templates/root/.gitignore.tmpl +5 -0
- package/dist/templates/root/LEARNINGS.md.tmpl +24 -0
- package/dist/templates/root/README.md.tmpl +61 -0
- package/dist/templates/scripts/feature-loop.sh.tmpl +267 -0
- package/dist/templates/scripts/loop.sh.tmpl +59 -0
- package/dist/templates/scripts/ralph-monitor.sh.tmpl +244 -0
- package/dist/templates/specs/README.md.tmpl +57 -0
- package/dist/templates/specs/_example.md.tmpl +71 -0
- package/dist/utils/config.d.ts +95 -0
- package/dist/utils/config.d.ts.map +1 -0
- package/dist/utils/config.js +148 -0
- package/dist/utils/config.js.map +1 -0
- package/dist/utils/header.d.ts +5 -0
- package/dist/utils/header.d.ts.map +1 -0
- package/dist/utils/header.js +15 -0
- package/dist/utils/header.js.map +1 -0
- package/dist/utils/logger.d.ts +11 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +24 -0
- package/dist/utils/logger.js.map +1 -0
- package/package.json +44 -0
- package/src/ai/enhancer.ts +350 -0
- package/src/ai/index.ts +38 -0
- package/src/ai/prompts.ts +217 -0
- package/src/ai/providers.ts +136 -0
- package/src/cli.ts +255 -0
- package/src/commands/init.ts +149 -0
- package/src/commands/monitor.ts +412 -0
- package/src/commands/new.ts +312 -0
- package/src/commands/run.ts +214 -0
- package/src/generator/config.ts +116 -0
- package/src/generator/index.ts +227 -0
- package/src/generator/templates.ts +412 -0
- package/src/generator/writer.ts +293 -0
- package/src/index.ts +41 -0
- package/src/scanner/detectors/core/framework.ts +332 -0
- package/src/scanner/detectors/core/packageManager.ts +91 -0
- package/src/scanner/detectors/core/styling.ts +261 -0
- package/src/scanner/detectors/core/testing.ts +221 -0
- package/src/scanner/detectors/data/api.ts +303 -0
- package/src/scanner/detectors/data/database.ts +245 -0
- package/src/scanner/detectors/data/orm.ts +180 -0
- package/src/scanner/detectors/frontend/formHandling.ts +244 -0
- package/src/scanner/detectors/frontend/stateManagement.ts +261 -0
- package/src/scanner/detectors/frontend/uiComponents.ts +328 -0
- package/src/scanner/detectors/infra/deployment.ts +343 -0
- package/src/scanner/detectors/infra/monorepo.ts +251 -0
- package/src/scanner/detectors/mcp/mcpProject.ts +176 -0
- package/src/scanner/detectors/mcp/mcpServers.ts +237 -0
- package/src/scanner/detectors/services/analytics.ts +273 -0
- package/src/scanner/detectors/services/auth.ts +254 -0
- package/src/scanner/detectors/services/email.ts +244 -0
- package/src/scanner/detectors/services/payments.ts +213 -0
- package/src/scanner/detectors/utils.ts +251 -0
- package/src/scanner/index.ts +354 -0
- package/src/scanner/registry.ts +301 -0
- package/src/scanner/types.ts +152 -0
- package/src/templates/config/ralph.config.js.tmpl +38 -0
- package/src/templates/guides/AGENTS.md.tmpl +100 -0
- package/src/templates/guides/FRONTEND.md.tmpl +523 -0
- package/src/templates/guides/PERFORMANCE.md.tmpl +264 -0
- package/src/templates/guides/SECURITY.md.tmpl +100 -0
- package/src/templates/prompts/PROMPT.md.tmpl +77 -0
- package/src/templates/prompts/PROMPT_e2e.md.tmpl +234 -0
- package/src/templates/prompts/PROMPT_feature.md.tmpl +83 -0
- package/src/templates/prompts/PROMPT_review.md.tmpl +167 -0
- package/src/templates/prompts/PROMPT_verify.md.tmpl +72 -0
- package/src/templates/root/.gitignore.tmpl +5 -0
- package/src/templates/root/LEARNINGS.md.tmpl +24 -0
- package/src/templates/root/README.md.tmpl +61 -0
- package/src/templates/scripts/feature-loop.sh.tmpl +267 -0
- package/src/templates/scripts/loop.sh.tmpl +59 -0
- package/src/templates/scripts/ralph-monitor.sh.tmpl +244 -0
- package/src/templates/specs/README.md.tmpl +57 -0
- package/src/templates/specs/_example.md.tmpl +71 -0
- package/src/utils/config.ts +221 -0
- package/src/utils/header.ts +15 -0
- package/src/utils/logger.ts +28 -0
- package/tsconfig.json +19 -0
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# loop.sh - Simple Ralph iteration loop
|
|
3
|
+
# Generated by ralph-cli for {{projectName}}
|
|
4
|
+
# Usage: ./loop.sh [prompt-file] [max-iterations]
|
|
5
|
+
|
|
6
|
+
set -e
|
|
7
|
+
|
|
8
|
+
# Get script directory
|
|
9
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
10
|
+
|
|
11
|
+
# Load config from ralph.config.js if available
|
|
12
|
+
if [ -f "$SCRIPT_DIR/../ralph.config.js" ]; then
|
|
13
|
+
PROMPTS_DIR=$(node -e "console.log(require('$SCRIPT_DIR/../ralph.config.js').paths?.prompts || '.ralph/prompts')" 2>/dev/null || echo ".ralph/prompts")
|
|
14
|
+
DEFAULT_MODEL=$(node -e "console.log(require('$SCRIPT_DIR/../ralph.config.js').loop?.defaultModel || 'sonnet')" 2>/dev/null || echo "sonnet")
|
|
15
|
+
elif [ -f "$SCRIPT_DIR/../../ralph.config.js" ]; then
|
|
16
|
+
PROMPTS_DIR=$(node -e "console.log(require('$SCRIPT_DIR/../../ralph.config.js').paths?.prompts || '.ralph/prompts')" 2>/dev/null || echo ".ralph/prompts")
|
|
17
|
+
DEFAULT_MODEL=$(node -e "console.log(require('$SCRIPT_DIR/../../ralph.config.js').loop?.defaultModel || 'sonnet')" 2>/dev/null || echo "sonnet")
|
|
18
|
+
else
|
|
19
|
+
PROMPTS_DIR=".ralph/prompts"
|
|
20
|
+
DEFAULT_MODEL="sonnet"
|
|
21
|
+
fi
|
|
22
|
+
|
|
23
|
+
# Navigate to project root
|
|
24
|
+
cd "$SCRIPT_DIR/../.."
|
|
25
|
+
|
|
26
|
+
PROMPT_FILE="${1:-$PROMPTS_DIR/PROMPT.md}"
|
|
27
|
+
MAX_ITERATIONS="${2:-0}"
|
|
28
|
+
MODEL="${3:-$DEFAULT_MODEL}"
|
|
29
|
+
ITERATION=0
|
|
30
|
+
|
|
31
|
+
echo "Starting Ralph loop"
|
|
32
|
+
echo " Prompt: $PROMPT_FILE"
|
|
33
|
+
echo " Model: $MODEL"
|
|
34
|
+
echo " Max iterations: $MAX_ITERATIONS (0 = infinite)"
|
|
35
|
+
echo "Press Ctrl+C to stop"
|
|
36
|
+
echo ""
|
|
37
|
+
|
|
38
|
+
# Check if prompt file exists
|
|
39
|
+
if [ ! -f "$PROMPT_FILE" ]; then
|
|
40
|
+
echo "ERROR: Prompt file not found: $PROMPT_FILE"
|
|
41
|
+
exit 1
|
|
42
|
+
fi
|
|
43
|
+
|
|
44
|
+
while true; do
|
|
45
|
+
if [ $MAX_ITERATIONS -gt 0 ] && [ $ITERATION -ge $MAX_ITERATIONS ]; then
|
|
46
|
+
echo "Reached max iterations: $MAX_ITERATIONS"
|
|
47
|
+
break
|
|
48
|
+
fi
|
|
49
|
+
|
|
50
|
+
ITERATION=$((ITERATION + 1))
|
|
51
|
+
echo "======================== ITERATION $ITERATION ========================"
|
|
52
|
+
|
|
53
|
+
cat "$PROMPT_FILE" | claude -p --dangerously-skip-permissions --model "$MODEL"
|
|
54
|
+
|
|
55
|
+
echo ""
|
|
56
|
+
sleep 2
|
|
57
|
+
done
|
|
58
|
+
|
|
59
|
+
echo "Loop completed after $ITERATION iterations"
|
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# ralph-monitor.sh - Dashboard to monitor loop progress
|
|
3
|
+
# Generated by ralph-cli for {{projectName}}
|
|
4
|
+
# Usage: ./ralph-monitor.sh <feature-name>
|
|
5
|
+
|
|
6
|
+
FEATURE="${1:?Usage: ./ralph-monitor.sh <feature-name>}"
|
|
7
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
8
|
+
|
|
9
|
+
# Load config from ralph.config.js if available
|
|
10
|
+
if [ -f "$SCRIPT_DIR/../ralph.config.js" ]; then
|
|
11
|
+
SPEC_DIR=$(node -e "console.log(require('$SCRIPT_DIR/../ralph.config.js').paths?.specs || '.ralph/specs')" 2>/dev/null || echo ".ralph/specs")
|
|
12
|
+
elif [ -f "$SCRIPT_DIR/../../ralph.config.js" ]; then
|
|
13
|
+
SPEC_DIR=$(node -e "console.log(require('$SCRIPT_DIR/../../ralph.config.js').paths?.specs || '.ralph/specs')" 2>/dev/null || echo ".ralph/specs")
|
|
14
|
+
else
|
|
15
|
+
SPEC_DIR=".ralph/specs"
|
|
16
|
+
fi
|
|
17
|
+
|
|
18
|
+
# Navigate to project root
|
|
19
|
+
cd "$SCRIPT_DIR/../.."
|
|
20
|
+
|
|
21
|
+
PLAN_FILE="$SPEC_DIR/${FEATURE}-implementation-plan.md"
|
|
22
|
+
SPEC_FILE="$SPEC_DIR/${FEATURE}.md"
|
|
23
|
+
APP_DIR="$(pwd)"
|
|
24
|
+
STATUS_FILE="/tmp/ralph-loop-${FEATURE}.status"
|
|
25
|
+
TOKENS_FILE="/tmp/ralph-loop-${FEATURE}.tokens"
|
|
26
|
+
|
|
27
|
+
# Colors
|
|
28
|
+
RED='\033[0;31m'
|
|
29
|
+
GREEN='\033[0;32m'
|
|
30
|
+
YELLOW='\033[0;33m'
|
|
31
|
+
BLUE='\033[0;34m'
|
|
32
|
+
MAGENTA='\033[0;35m'
|
|
33
|
+
CYAN='\033[0;36m'
|
|
34
|
+
BOLD='\033[1m'
|
|
35
|
+
DIM='\033[2m'
|
|
36
|
+
NC='\033[0m'
|
|
37
|
+
|
|
38
|
+
# Terminal width
|
|
39
|
+
TERM_WIDTH=$(tput cols 2>/dev/null || echo 80)
|
|
40
|
+
|
|
41
|
+
# Truncate text
|
|
42
|
+
truncate() {
|
|
43
|
+
local text="$1"
|
|
44
|
+
local max="$2"
|
|
45
|
+
if [ ${#text} -gt $max ]; then
|
|
46
|
+
echo "${text:0:$((max-3))}..."
|
|
47
|
+
else
|
|
48
|
+
echo "$text"
|
|
49
|
+
fi
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
# Clean task text
|
|
53
|
+
clean_task() {
|
|
54
|
+
echo "$1" | sed 's/- \[\[complexity:.*\]\]//g' | sed 's/\[complexity:.*\]//g' | sed 's/ */ /g'
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
# Progress bar
|
|
58
|
+
progress_bar() {
|
|
59
|
+
local percent=$1
|
|
60
|
+
local width=15
|
|
61
|
+
local filled=$((percent * width / 100))
|
|
62
|
+
local empty=$((width - filled))
|
|
63
|
+
printf "${GREEN}"
|
|
64
|
+
for ((i=0; i<filled; i++)); do printf "\xe2\x96\x88"; done
|
|
65
|
+
printf "${DIM}"
|
|
66
|
+
for ((i=0; i<empty; i++)); do printf "\xe2\x96\x91"; done
|
|
67
|
+
printf "${NC}"
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
# Detect current phase
|
|
71
|
+
detect_phase() {
|
|
72
|
+
if pgrep -f "PROMPT_feature.md" > /dev/null 2>&1; then
|
|
73
|
+
echo "Planning"
|
|
74
|
+
elif pgrep -f "PROMPT_e2e.md" > /dev/null 2>&1; then
|
|
75
|
+
echo "E2E Testing"
|
|
76
|
+
elif pgrep -f "PROMPT_verify.md" > /dev/null 2>&1; then
|
|
77
|
+
echo "Verification"
|
|
78
|
+
elif pgrep -f "PROMPT_review.md" > /dev/null 2>&1; then
|
|
79
|
+
echo "PR Review"
|
|
80
|
+
elif pgrep -f "PROMPT.md" > /dev/null 2>&1; then
|
|
81
|
+
echo "Implementation"
|
|
82
|
+
elif pgrep -f "feature-loop.sh.*$FEATURE" > /dev/null 2>&1; then
|
|
83
|
+
echo "Running"
|
|
84
|
+
else
|
|
85
|
+
echo "Idle"
|
|
86
|
+
fi
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
# Get iteration info
|
|
90
|
+
get_iteration_info() {
|
|
91
|
+
if [ -f "$STATUS_FILE" ]; then
|
|
92
|
+
cat "$STATUS_FILE"
|
|
93
|
+
return
|
|
94
|
+
fi
|
|
95
|
+
if pgrep -f "feature-loop.sh.*${FEATURE}" > /dev/null 2>&1; then
|
|
96
|
+
echo "-1|50|0"
|
|
97
|
+
else
|
|
98
|
+
echo "0|50|0"
|
|
99
|
+
fi
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
# Get token info
|
|
103
|
+
get_token_info() {
|
|
104
|
+
if [ -f "$TOKENS_FILE" ]; then
|
|
105
|
+
cat "$TOKENS_FILE"
|
|
106
|
+
else
|
|
107
|
+
echo "0|0"
|
|
108
|
+
fi
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
# Format number
|
|
112
|
+
format_number() {
|
|
113
|
+
local num=$1
|
|
114
|
+
if [ $num -ge 1000000 ]; then
|
|
115
|
+
printf "%.1fM" $(echo "scale=1; $num/1000000" | bc)
|
|
116
|
+
elif [ $num -ge 1000 ]; then
|
|
117
|
+
printf "%.1fK" $(echo "scale=1; $num/1000" | bc)
|
|
118
|
+
else
|
|
119
|
+
printf "%d" $num
|
|
120
|
+
fi
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
# Main loop
|
|
124
|
+
while true; do
|
|
125
|
+
clear
|
|
126
|
+
|
|
127
|
+
TIMESTAMP=$(date '+%H:%M:%S')
|
|
128
|
+
ITER_INFO=$(get_iteration_info)
|
|
129
|
+
ITER_CURRENT=$(echo "$ITER_INFO" | cut -d'|' -f1)
|
|
130
|
+
ITER_MAX=$(echo "$ITER_INFO" | cut -d'|' -f2)
|
|
131
|
+
[[ "$ITER_CURRENT" =~ ^-?[0-9]+$ ]] || ITER_CURRENT=0
|
|
132
|
+
[[ "$ITER_MAX" =~ ^[0-9]+$ ]] || ITER_MAX=50
|
|
133
|
+
|
|
134
|
+
echo -e "${BOLD}================================================================${NC}"
|
|
135
|
+
printf "${BOLD} ${CYAN}RALPH MONITOR${NC}: %-30s ${DIM}%s${NC}\n" "$FEATURE" "$TIMESTAMP"
|
|
136
|
+
echo -e "${BOLD}================================================================${NC}"
|
|
137
|
+
|
|
138
|
+
# Check if plan exists
|
|
139
|
+
if [ ! -f "$PLAN_FILE" ]; then
|
|
140
|
+
echo ""
|
|
141
|
+
echo -e " ${YELLOW}Waiting for implementation plan...${NC}"
|
|
142
|
+
echo -e " ${DIM}$PLAN_FILE${NC}"
|
|
143
|
+
echo ""
|
|
144
|
+
sleep 10
|
|
145
|
+
continue
|
|
146
|
+
fi
|
|
147
|
+
|
|
148
|
+
# Count tasks
|
|
149
|
+
DONE_IMPL=$(grep "^- \[x\]" "$PLAN_FILE" 2>/dev/null | grep -v "E2E:" | wc -l | tr -d '[:space:]')
|
|
150
|
+
TODO_IMPL=$(grep "^- \[ \]" "$PLAN_FILE" 2>/dev/null | grep -v "E2E:" | wc -l | tr -d '[:space:]')
|
|
151
|
+
DONE_E2E=$(grep "^- \[x\].*E2E:" "$PLAN_FILE" 2>/dev/null | wc -l | tr -d '[:space:]')
|
|
152
|
+
TODO_E2E=$(grep "^- \[ \].*E2E:" "$PLAN_FILE" 2>/dev/null | wc -l | tr -d '[:space:]')
|
|
153
|
+
[[ "$DONE_IMPL" =~ ^[0-9]+$ ]] || DONE_IMPL=0
|
|
154
|
+
[[ "$TODO_IMPL" =~ ^[0-9]+$ ]] || TODO_IMPL=0
|
|
155
|
+
[[ "$DONE_E2E" =~ ^[0-9]+$ ]] || DONE_E2E=0
|
|
156
|
+
[[ "$TODO_E2E" =~ ^[0-9]+$ ]] || TODO_E2E=0
|
|
157
|
+
|
|
158
|
+
TOTAL_IMPL=$((DONE_IMPL + TODO_IMPL))
|
|
159
|
+
TOTAL_E2E=$((DONE_E2E + TODO_E2E))
|
|
160
|
+
DONE_ALL=$((DONE_IMPL + DONE_E2E))
|
|
161
|
+
TOTAL_ALL=$((TOTAL_IMPL + TOTAL_E2E))
|
|
162
|
+
|
|
163
|
+
[ $TOTAL_IMPL -gt 0 ] && PERCENT_IMPL=$((DONE_IMPL * 100 / TOTAL_IMPL)) || PERCENT_IMPL=0
|
|
164
|
+
[ $TOTAL_ALL -gt 0 ] && PERCENT_ALL=$((DONE_ALL * 100 / TOTAL_ALL)) || PERCENT_ALL=0
|
|
165
|
+
|
|
166
|
+
PHASE=$(detect_phase)
|
|
167
|
+
BRANCH=$(git branch --show-current 2>/dev/null || echo "-")
|
|
168
|
+
|
|
169
|
+
case "$PHASE" in
|
|
170
|
+
"Planning") PHASE_COLOR="${BLUE}" ;;
|
|
171
|
+
"Implementation") PHASE_COLOR="${YELLOW}" ;;
|
|
172
|
+
"E2E Testing") PHASE_COLOR="${CYAN}" ;;
|
|
173
|
+
"Verification") PHASE_COLOR="${MAGENTA}" ;;
|
|
174
|
+
"PR Review") PHASE_COLOR="${GREEN}" ;;
|
|
175
|
+
"Idle") PHASE_COLOR="${DIM}" ;;
|
|
176
|
+
*) PHASE_COLOR="${NC}" ;;
|
|
177
|
+
esac
|
|
178
|
+
|
|
179
|
+
TOKEN_INFO=$(get_token_info)
|
|
180
|
+
TOKEN_INPUT=$(echo "$TOKEN_INFO" | cut -d'|' -f1)
|
|
181
|
+
TOKEN_OUTPUT=$(echo "$TOKEN_INFO" | cut -d'|' -f2)
|
|
182
|
+
[[ "$TOKEN_INPUT" =~ ^[0-9]+$ ]] || TOKEN_INPUT=0
|
|
183
|
+
[[ "$TOKEN_OUTPUT" =~ ^[0-9]+$ ]] || TOKEN_OUTPUT=0
|
|
184
|
+
TOKEN_TOTAL=$((TOKEN_INPUT + TOKEN_OUTPUT))
|
|
185
|
+
|
|
186
|
+
if [ "$ITER_CURRENT" = "-1" ]; then
|
|
187
|
+
ITER_DISPLAY="?"
|
|
188
|
+
else
|
|
189
|
+
ITER_DISPLAY="$ITER_CURRENT"
|
|
190
|
+
fi
|
|
191
|
+
|
|
192
|
+
# Status
|
|
193
|
+
echo ""
|
|
194
|
+
printf " Phase: ${PHASE_COLOR}${BOLD}%-14s${NC}" "$PHASE"
|
|
195
|
+
printf " Iter: ${BOLD}%s${NC}/${DIM}%d${NC}" "$ITER_DISPLAY" "$ITER_MAX"
|
|
196
|
+
printf " Branch: ${CYAN}%s${NC}\n" "$BRANCH"
|
|
197
|
+
printf " Tokens: ${MAGENTA}$(format_number $TOKEN_TOTAL)${NC} ${DIM}(in:$(format_number $TOKEN_INPUT) out:$(format_number $TOKEN_OUTPUT))${NC}\n"
|
|
198
|
+
|
|
199
|
+
echo -e "${DIM} ----------------------------------------------------------------${NC}"
|
|
200
|
+
|
|
201
|
+
# Progress
|
|
202
|
+
echo ""
|
|
203
|
+
printf " ${BOLD}Implementation:${NC} $(progress_bar $PERCENT_IMPL) ${BOLD}%3d%%${NC} " "$PERCENT_IMPL"
|
|
204
|
+
printf "${GREEN}Done: %d${NC} / ${YELLOW}Todo: %d${NC}\n" "$DONE_IMPL" "$TODO_IMPL"
|
|
205
|
+
|
|
206
|
+
if [ $TOTAL_E2E -gt 0 ]; then
|
|
207
|
+
[ $TOTAL_E2E -gt 0 ] && PERCENT_E2E=$((DONE_E2E * 100 / TOTAL_E2E)) || PERCENT_E2E=0
|
|
208
|
+
printf " ${BOLD}E2E Tests: ${NC} $(progress_bar $PERCENT_E2E) ${BOLD}%3d%%${NC} " "$PERCENT_E2E"
|
|
209
|
+
printf "${GREEN}Done: %d${NC} / ${YELLOW}Todo: %d${NC}\n" "$DONE_E2E" "$TODO_E2E"
|
|
210
|
+
fi
|
|
211
|
+
|
|
212
|
+
printf " ${DIM}--------------------------------------------${NC}\n"
|
|
213
|
+
printf " ${BOLD}Overall: ${NC} $(progress_bar $PERCENT_ALL) ${BOLD}%3d%%${NC} " "$PERCENT_ALL"
|
|
214
|
+
printf "${GREEN}Done: %d${NC} / Total: %d\n" "$DONE_ALL" "$TOTAL_ALL"
|
|
215
|
+
|
|
216
|
+
# Current task
|
|
217
|
+
CURRENT_TASK=$(grep "^- \[ \]" "$PLAN_FILE" 2>/dev/null | grep -v "E2E:" | head -1 | sed 's/^- \[ \] //')
|
|
218
|
+
CURRENT_TASK=$(clean_task "$CURRENT_TASK")
|
|
219
|
+
if [ -n "$CURRENT_TASK" ]; then
|
|
220
|
+
echo ""
|
|
221
|
+
echo -e " ${BOLD}NOW WORKING ON${NC}"
|
|
222
|
+
CURRENT_TASK=$(truncate "$CURRENT_TASK" $((TERM_WIDTH - 8)))
|
|
223
|
+
echo -e " ${YELLOW}>${NC} ${BOLD}$CURRENT_TASK${NC}"
|
|
224
|
+
fi
|
|
225
|
+
|
|
226
|
+
# Recent commits
|
|
227
|
+
echo ""
|
|
228
|
+
echo -e " ${BOLD}RECENT COMMITS${NC}"
|
|
229
|
+
COMMITS=$(git log --oneline -3 2>/dev/null)
|
|
230
|
+
if [ -n "$COMMITS" ]; then
|
|
231
|
+
while IFS= read -r commit; do
|
|
232
|
+
commit=$(truncate "$commit" $((TERM_WIDTH - 8)))
|
|
233
|
+
echo -e " ${DIM}$commit${NC}"
|
|
234
|
+
done <<< "$COMMITS"
|
|
235
|
+
else
|
|
236
|
+
echo -e " ${DIM}No commits yet${NC}"
|
|
237
|
+
fi
|
|
238
|
+
|
|
239
|
+
echo ""
|
|
240
|
+
echo -e "${DIM} ----------------------------------------------------------------${NC}"
|
|
241
|
+
echo -e " ${DIM}Refreshing every 10s - Press Ctrl+C to exit${NC}"
|
|
242
|
+
|
|
243
|
+
sleep 10
|
|
244
|
+
done
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# Specifications
|
|
2
|
+
|
|
3
|
+
This folder contains feature specifications and their implementation plans.
|
|
4
|
+
|
|
5
|
+
## Structure
|
|
6
|
+
|
|
7
|
+
Each feature has:
|
|
8
|
+
- `<feature>.md` - Specification document
|
|
9
|
+
- `<feature>-implementation-plan.md` - Implementation tasks
|
|
10
|
+
|
|
11
|
+
## Spec Template
|
|
12
|
+
|
|
13
|
+
```markdown
|
|
14
|
+
<!--
|
|
15
|
+
Copyright (c) 2025 {{projectName}}. All rights reserved.
|
|
16
|
+
SPDX-License-Identifier: Proprietary
|
|
17
|
+
-->
|
|
18
|
+
|
|
19
|
+
# Feature Name Specification
|
|
20
|
+
|
|
21
|
+
**Status:** Planned | In Progress | Completed
|
|
22
|
+
**Version:** 1.0
|
|
23
|
+
**Last Updated:** YYYY-MM-DD
|
|
24
|
+
|
|
25
|
+
## Purpose
|
|
26
|
+
[One paragraph explaining why this feature exists]
|
|
27
|
+
|
|
28
|
+
## User Stories
|
|
29
|
+
- As a [user], I want [action] so that [benefit]
|
|
30
|
+
|
|
31
|
+
## Requirements
|
|
32
|
+
- [ ] Requirement 1
|
|
33
|
+
- [ ] Requirement 2
|
|
34
|
+
|
|
35
|
+
## Technical Notes
|
|
36
|
+
- Uses: [existing patterns/components]
|
|
37
|
+
- Location: [where code should live]
|
|
38
|
+
|
|
39
|
+
## Visual Requirements
|
|
40
|
+
(For UI features - delete if backend-only)
|
|
41
|
+
- **Layout:** [Grid/Stack/Sidebar, responsive behavior]
|
|
42
|
+
- **Components:** [shadcn components to use]
|
|
43
|
+
- **Chart Types:** [If applicable]
|
|
44
|
+
- **States:** [Empty, loading, error handling]
|
|
45
|
+
- **Mobile:** [What changes on small screens]
|
|
46
|
+
- **Reference:** [Similar page in app or shadcn docs]
|
|
47
|
+
|
|
48
|
+
## Acceptance Criteria
|
|
49
|
+
- [ ] Criteria 1
|
|
50
|
+
- [ ] Criteria 2
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## Active Specs
|
|
54
|
+
|
|
55
|
+
| Spec | Status | Last Updated | Implementation Plan |
|
|
56
|
+
|------|--------|--------------|---------------------|
|
|
57
|
+
| (Your specs will appear here) | Planned | YYYY-MM-DD | - |
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# Example Feature Specification
|
|
2
|
+
|
|
3
|
+
**Status:** Planned
|
|
4
|
+
**Version:** 1.0
|
|
5
|
+
**Last Updated:** YYYY-MM-DD
|
|
6
|
+
|
|
7
|
+
## Purpose
|
|
8
|
+
|
|
9
|
+
This is an example specification to demonstrate the format. Replace this with your actual feature description explaining why this feature exists and what problem it solves.
|
|
10
|
+
|
|
11
|
+
## User Stories
|
|
12
|
+
|
|
13
|
+
- As a user, I want [action] so that [benefit]
|
|
14
|
+
- As an admin, I want [action] so that [benefit]
|
|
15
|
+
|
|
16
|
+
## Requirements
|
|
17
|
+
|
|
18
|
+
### Functional Requirements
|
|
19
|
+
- [ ] Requirement 1 - Description of what the system must do
|
|
20
|
+
- [ ] Requirement 2 - Another functional requirement
|
|
21
|
+
|
|
22
|
+
### Non-Functional Requirements
|
|
23
|
+
- [ ] Performance: [target metrics]
|
|
24
|
+
- [ ] Security: [security considerations]
|
|
25
|
+
- [ ] Accessibility: [WCAG level]
|
|
26
|
+
|
|
27
|
+
## Technical Notes
|
|
28
|
+
|
|
29
|
+
- **Uses:** Existing patterns or components to leverage
|
|
30
|
+
- **Location:** Where the code should live (e.g., `{{appDir}}/app/dashboard/`)
|
|
31
|
+
- **Dependencies:** External libraries or APIs needed
|
|
32
|
+
- **Database:** Schema changes required (if any)
|
|
33
|
+
|
|
34
|
+
## Visual Requirements
|
|
35
|
+
|
|
36
|
+
(For UI features - delete this section if backend-only)
|
|
37
|
+
|
|
38
|
+
- **Layout:** Describe the layout structure and responsive behavior
|
|
39
|
+
- **Components:** List the UI components needed (Button, Card, Table, etc.)
|
|
40
|
+
- **Chart Types:** If applicable, specify chart types needed
|
|
41
|
+
- **States:**
|
|
42
|
+
- Empty: What to show when there's no data
|
|
43
|
+
- Loading: Skeleton or spinner pattern
|
|
44
|
+
- Error: How to display errors
|
|
45
|
+
- **Mobile:** How the layout adapts on small screens
|
|
46
|
+
- **Reference:** Link to similar pages in the app or design references
|
|
47
|
+
|
|
48
|
+
## API Endpoints
|
|
49
|
+
|
|
50
|
+
(If applicable)
|
|
51
|
+
|
|
52
|
+
| Method | Endpoint | Description |
|
|
53
|
+
|--------|----------|-------------|
|
|
54
|
+
| GET | `/api/example` | Fetch example data |
|
|
55
|
+
| POST | `/api/example` | Create new example |
|
|
56
|
+
|
|
57
|
+
## Acceptance Criteria
|
|
58
|
+
|
|
59
|
+
- [ ] Criteria 1 - Specific, testable condition
|
|
60
|
+
- [ ] Criteria 2 - Another acceptance criterion
|
|
61
|
+
- [ ] Criteria 3 - E2E testable scenario
|
|
62
|
+
|
|
63
|
+
## Out of Scope
|
|
64
|
+
|
|
65
|
+
- Feature X (planned for future iteration)
|
|
66
|
+
- Integration Y (separate spec)
|
|
67
|
+
|
|
68
|
+
## Open Questions
|
|
69
|
+
|
|
70
|
+
- [ ] Question 1 - Decision needed
|
|
71
|
+
- [ ] Question 2 - Clarification required
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Configuration Utilities
|
|
3
|
+
* Load and parse ralph.config.js files
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { existsSync } from 'node:fs';
|
|
7
|
+
import { join } from 'node:path';
|
|
8
|
+
import { pathToFileURL } from 'node:url';
|
|
9
|
+
import { logger } from './logger.js';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Stack configuration in ralph.config.js
|
|
13
|
+
*/
|
|
14
|
+
export interface StackConfig {
|
|
15
|
+
framework: {
|
|
16
|
+
name: string;
|
|
17
|
+
version?: string;
|
|
18
|
+
variant?: string;
|
|
19
|
+
};
|
|
20
|
+
packageManager: string;
|
|
21
|
+
testing: {
|
|
22
|
+
unit: string;
|
|
23
|
+
e2e: string;
|
|
24
|
+
};
|
|
25
|
+
styling: string;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Commands configuration in ralph.config.js
|
|
30
|
+
*/
|
|
31
|
+
export interface CommandsConfig {
|
|
32
|
+
dev: string;
|
|
33
|
+
build: string;
|
|
34
|
+
test: string;
|
|
35
|
+
lint: string;
|
|
36
|
+
typecheck: string;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Paths configuration in ralph.config.js
|
|
41
|
+
*/
|
|
42
|
+
export interface PathsConfig {
|
|
43
|
+
root: string;
|
|
44
|
+
prompts: string;
|
|
45
|
+
guides: string;
|
|
46
|
+
specs: string;
|
|
47
|
+
scripts: string;
|
|
48
|
+
learnings: string;
|
|
49
|
+
agents: string;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Loop configuration in ralph.config.js
|
|
54
|
+
*/
|
|
55
|
+
export interface LoopConfig {
|
|
56
|
+
maxIterations: number;
|
|
57
|
+
maxE2eAttempts: number;
|
|
58
|
+
defaultModel: string;
|
|
59
|
+
planningModel: string;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Full ralph.config.js structure
|
|
64
|
+
*/
|
|
65
|
+
export interface RalphConfig {
|
|
66
|
+
name: string;
|
|
67
|
+
stack: StackConfig;
|
|
68
|
+
commands: CommandsConfig;
|
|
69
|
+
paths: PathsConfig;
|
|
70
|
+
loop: LoopConfig;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Default configuration values
|
|
75
|
+
*/
|
|
76
|
+
export const DEFAULT_CONFIG: RalphConfig = {
|
|
77
|
+
name: 'project',
|
|
78
|
+
stack: {
|
|
79
|
+
framework: {
|
|
80
|
+
name: 'unknown',
|
|
81
|
+
version: undefined,
|
|
82
|
+
variant: undefined,
|
|
83
|
+
},
|
|
84
|
+
packageManager: 'npm',
|
|
85
|
+
testing: {
|
|
86
|
+
unit: 'none',
|
|
87
|
+
e2e: 'none',
|
|
88
|
+
},
|
|
89
|
+
styling: 'css',
|
|
90
|
+
},
|
|
91
|
+
commands: {
|
|
92
|
+
dev: 'npm run dev',
|
|
93
|
+
build: 'npm run build',
|
|
94
|
+
test: 'npm test',
|
|
95
|
+
lint: 'npm run lint',
|
|
96
|
+
typecheck: 'npm run typecheck',
|
|
97
|
+
},
|
|
98
|
+
paths: {
|
|
99
|
+
root: '.ralph',
|
|
100
|
+
prompts: '.ralph/prompts',
|
|
101
|
+
guides: '.ralph/guides',
|
|
102
|
+
specs: '.ralph/specs',
|
|
103
|
+
scripts: '.ralph/scripts',
|
|
104
|
+
learnings: '.ralph/LEARNINGS.md',
|
|
105
|
+
agents: '.ralph/AGENTS.md',
|
|
106
|
+
},
|
|
107
|
+
loop: {
|
|
108
|
+
maxIterations: 10,
|
|
109
|
+
maxE2eAttempts: 5,
|
|
110
|
+
defaultModel: 'sonnet',
|
|
111
|
+
planningModel: 'opus',
|
|
112
|
+
},
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Load ralph.config.js from a project directory
|
|
117
|
+
* Returns null if config file doesn't exist
|
|
118
|
+
*/
|
|
119
|
+
export async function loadConfig(projectRoot: string): Promise<RalphConfig | null> {
|
|
120
|
+
const configPath = join(projectRoot, 'ralph.config.js');
|
|
121
|
+
|
|
122
|
+
if (!existsSync(configPath)) {
|
|
123
|
+
return null;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
try {
|
|
127
|
+
// Use dynamic import for ESM compatibility
|
|
128
|
+
// Add timestamp to bust module cache for fresh config
|
|
129
|
+
const configUrl = pathToFileURL(configPath).href + `?t=${Date.now()}`;
|
|
130
|
+
const configModule = await import(configUrl);
|
|
131
|
+
return (configModule.default || configModule) as RalphConfig;
|
|
132
|
+
} catch (error) {
|
|
133
|
+
logger.error(`Failed to load config from ${configPath}: ${error instanceof Error ? error.message : String(error)}`);
|
|
134
|
+
return null;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Load config with defaults merged in
|
|
140
|
+
*/
|
|
141
|
+
export async function loadConfigWithDefaults(projectRoot: string): Promise<RalphConfig> {
|
|
142
|
+
const config = await loadConfig(projectRoot);
|
|
143
|
+
|
|
144
|
+
if (!config) {
|
|
145
|
+
return DEFAULT_CONFIG;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// Deep merge with defaults
|
|
149
|
+
return {
|
|
150
|
+
name: config.name || DEFAULT_CONFIG.name,
|
|
151
|
+
stack: {
|
|
152
|
+
...DEFAULT_CONFIG.stack,
|
|
153
|
+
...config.stack,
|
|
154
|
+
framework: {
|
|
155
|
+
...DEFAULT_CONFIG.stack.framework,
|
|
156
|
+
...config.stack?.framework,
|
|
157
|
+
},
|
|
158
|
+
testing: {
|
|
159
|
+
...DEFAULT_CONFIG.stack.testing,
|
|
160
|
+
...config.stack?.testing,
|
|
161
|
+
},
|
|
162
|
+
},
|
|
163
|
+
commands: {
|
|
164
|
+
...DEFAULT_CONFIG.commands,
|
|
165
|
+
...config.commands,
|
|
166
|
+
},
|
|
167
|
+
paths: {
|
|
168
|
+
...DEFAULT_CONFIG.paths,
|
|
169
|
+
...config.paths,
|
|
170
|
+
},
|
|
171
|
+
loop: {
|
|
172
|
+
...DEFAULT_CONFIG.loop,
|
|
173
|
+
...config.loop,
|
|
174
|
+
},
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Check if a ralph config exists in the project
|
|
180
|
+
*/
|
|
181
|
+
export function hasConfig(projectRoot: string): boolean {
|
|
182
|
+
const configPath = join(projectRoot, 'ralph.config.js');
|
|
183
|
+
return existsSync(configPath);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Get the ralph root directory from config or default
|
|
188
|
+
*/
|
|
189
|
+
export async function getRalphRoot(projectRoot: string): Promise<string> {
|
|
190
|
+
const config = await loadConfig(projectRoot);
|
|
191
|
+
return config?.paths?.root || '.ralph';
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* Get the specs directory from config or default
|
|
196
|
+
*/
|
|
197
|
+
export async function getSpecsDir(projectRoot: string): Promise<string> {
|
|
198
|
+
const config = await loadConfig(projectRoot);
|
|
199
|
+
return config?.paths?.specs || '.ralph/specs';
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* Get the scripts directory from config or default
|
|
204
|
+
*/
|
|
205
|
+
export async function getScriptsDir(projectRoot: string): Promise<string> {
|
|
206
|
+
const config = await loadConfig(projectRoot);
|
|
207
|
+
return config?.paths?.scripts || '.ralph/scripts';
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* Get loop settings with defaults
|
|
212
|
+
*/
|
|
213
|
+
export async function getLoopSettings(projectRoot: string): Promise<LoopConfig> {
|
|
214
|
+
const config = await loadConfig(projectRoot);
|
|
215
|
+
return {
|
|
216
|
+
maxIterations: config?.loop?.maxIterations || DEFAULT_CONFIG.loop.maxIterations,
|
|
217
|
+
maxE2eAttempts: config?.loop?.maxE2eAttempts || DEFAULT_CONFIG.loop.maxE2eAttempts,
|
|
218
|
+
defaultModel: config?.loop?.defaultModel || DEFAULT_CONFIG.loop.defaultModel,
|
|
219
|
+
planningModel: config?.loop?.planningModel || DEFAULT_CONFIG.loop.planningModel,
|
|
220
|
+
};
|
|
221
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import cfonts from 'cfonts';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Display the RALPH ASCII header in Simpson yellow
|
|
5
|
+
*/
|
|
6
|
+
export function displayHeader(): void {
|
|
7
|
+
cfonts.say('RALPH', {
|
|
8
|
+
font: 'block',
|
|
9
|
+
colors: ['#FED90F'],
|
|
10
|
+
letterSpacing: 1,
|
|
11
|
+
lineHeight: 1,
|
|
12
|
+
space: true,
|
|
13
|
+
maxLength: 0,
|
|
14
|
+
});
|
|
15
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import pc from 'picocolors';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Logging utilities with colored output
|
|
5
|
+
*/
|
|
6
|
+
export const logger = {
|
|
7
|
+
info(message: string): void {
|
|
8
|
+
console.log(pc.blue('info'), message);
|
|
9
|
+
},
|
|
10
|
+
|
|
11
|
+
success(message: string): void {
|
|
12
|
+
console.log(pc.green('success'), message);
|
|
13
|
+
},
|
|
14
|
+
|
|
15
|
+
warn(message: string): void {
|
|
16
|
+
console.log(pc.yellow('warn'), message);
|
|
17
|
+
},
|
|
18
|
+
|
|
19
|
+
error(message: string): void {
|
|
20
|
+
console.log(pc.red('error'), message);
|
|
21
|
+
},
|
|
22
|
+
|
|
23
|
+
debug(message: string): void {
|
|
24
|
+
if (process.env.DEBUG) {
|
|
25
|
+
console.log(pc.gray('debug'), message);
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
};
|