ralphblaster-agent 0.1.1
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 +294 -0
- package/bin/agent-dashboard.sh +168 -0
- package/bin/monitor-agent.sh +264 -0
- package/bin/ralphblaster.js +247 -0
- package/package.json +64 -0
- package/postinstall-colored.js +66 -0
- package/src/api-client.js +764 -0
- package/src/claude-plugin/.claude-plugin/plugin.json +9 -0
- package/src/claude-plugin/README.md +42 -0
- package/src/claude-plugin/skills/ralph/SKILL.md +259 -0
- package/src/commands/add-project.js +257 -0
- package/src/commands/init.js +79 -0
- package/src/config-file-manager.js +84 -0
- package/src/config.js +66 -0
- package/src/error-window.js +86 -0
- package/src/executor/claude-runner.js +716 -0
- package/src/executor/error-handler.js +65 -0
- package/src/executor/git-helper.js +196 -0
- package/src/executor/index.js +296 -0
- package/src/executor/job-handlers/clarifying-questions.js +213 -0
- package/src/executor/job-handlers/code-execution.js +145 -0
- package/src/executor/job-handlers/prd-generation.js +259 -0
- package/src/executor/path-helper.js +74 -0
- package/src/executor/prompt-validator.js +51 -0
- package/src/executor.js +4 -0
- package/src/index.js +342 -0
- package/src/logger.js +193 -0
- package/src/logging/README.md +93 -0
- package/src/logging/config.js +179 -0
- package/src/logging/destinations/README.md +290 -0
- package/src/logging/destinations/api-destination-unbatched.js +118 -0
- package/src/logging/destinations/api-destination.js +40 -0
- package/src/logging/destinations/base-destination.js +85 -0
- package/src/logging/destinations/batched-destination.js +198 -0
- package/src/logging/destinations/console-destination.js +172 -0
- package/src/logging/destinations/file-destination.js +208 -0
- package/src/logging/destinations/index.js +29 -0
- package/src/logging/destinations/progress-batch-destination-unbatched.js +92 -0
- package/src/logging/destinations/progress-batch-destination.js +41 -0
- package/src/logging/formatter.js +288 -0
- package/src/logging/log-manager.js +426 -0
- package/src/progress-throttle.js +101 -0
- package/src/system-monitor.js +64 -0
- package/src/utils/format.js +16 -0
- package/src/utils/log-file-helper.js +265 -0
- package/src/utils/progress-parser.js +250 -0
- package/src/worktree-manager.js +255 -0
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Ralph Agent Monitoring Script
|
|
3
|
+
# Ensures only one agent runs and provides visibility into its activity
|
|
4
|
+
|
|
5
|
+
AGENT_DIR="$(cd "$(dirname "$0")/.." && pwd)"
|
|
6
|
+
AGENT_SCRIPT="$AGENT_DIR/bin/ralphblaster.js"
|
|
7
|
+
LOG_DIR="$HOME/.ralphblaster-logs"
|
|
8
|
+
CURRENT_LOG="$LOG_DIR/agent-$(date +%Y%m%d).log"
|
|
9
|
+
PID_FILE="$LOG_DIR/agent.pid"
|
|
10
|
+
STATUS_FILE="$LOG_DIR/agent-status.json"
|
|
11
|
+
|
|
12
|
+
# Create log directory
|
|
13
|
+
mkdir -p "$LOG_DIR"
|
|
14
|
+
|
|
15
|
+
# Function to check if agent is running
|
|
16
|
+
check_agent() {
|
|
17
|
+
if [ -f "$PID_FILE" ]; then
|
|
18
|
+
local pid=$(cat "$PID_FILE")
|
|
19
|
+
if ps -p "$pid" > /dev/null 2>&1; then
|
|
20
|
+
# Check if it's actually our agent process
|
|
21
|
+
if ps -p "$pid" -o command= | grep -q "ralphblaster"; then
|
|
22
|
+
return 0 # Running
|
|
23
|
+
fi
|
|
24
|
+
fi
|
|
25
|
+
# Stale PID file
|
|
26
|
+
rm -f "$PID_FILE"
|
|
27
|
+
fi
|
|
28
|
+
return 1 # Not running
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
# Function to kill all agent processes
|
|
32
|
+
kill_all_agents() {
|
|
33
|
+
echo "Searching for all Ralph agent processes..."
|
|
34
|
+
local pids=$(pgrep -f "ralphblaster.js")
|
|
35
|
+
|
|
36
|
+
if [ -z "$pids" ]; then
|
|
37
|
+
echo "No agent processes found"
|
|
38
|
+
return
|
|
39
|
+
fi
|
|
40
|
+
|
|
41
|
+
echo "Found agent processes: $pids"
|
|
42
|
+
for pid in $pids; do
|
|
43
|
+
echo "Killing process $pid..."
|
|
44
|
+
kill -TERM "$pid" 2>/dev/null
|
|
45
|
+
sleep 1
|
|
46
|
+
# Force kill if still running
|
|
47
|
+
if ps -p "$pid" > /dev/null 2>&1; then
|
|
48
|
+
echo "Force killing $pid..."
|
|
49
|
+
kill -KILL "$pid" 2>/dev/null
|
|
50
|
+
fi
|
|
51
|
+
done
|
|
52
|
+
|
|
53
|
+
rm -f "$PID_FILE"
|
|
54
|
+
echo "All agents stopped"
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
# Function to start agent
|
|
58
|
+
start_agent() {
|
|
59
|
+
if check_agent; then
|
|
60
|
+
echo "❌ Agent already running (PID: $(cat "$PID_FILE"))"
|
|
61
|
+
echo "Use 'monitor-agent.sh restart' to restart it"
|
|
62
|
+
return 1
|
|
63
|
+
fi
|
|
64
|
+
|
|
65
|
+
echo "Starting Ralph agent..."
|
|
66
|
+
echo "Logs: $CURRENT_LOG"
|
|
67
|
+
|
|
68
|
+
# Start agent with output to log file
|
|
69
|
+
cd "$AGENT_DIR"
|
|
70
|
+
RALPH_LOG_LEVEL="${RALPH_LOG_LEVEL:-info}" node "$AGENT_SCRIPT" >> "$CURRENT_LOG" 2>&1 &
|
|
71
|
+
local pid=$!
|
|
72
|
+
|
|
73
|
+
echo $pid > "$PID_FILE"
|
|
74
|
+
|
|
75
|
+
# Wait a moment to ensure it started
|
|
76
|
+
sleep 2
|
|
77
|
+
|
|
78
|
+
if check_agent; then
|
|
79
|
+
echo "✅ Agent started successfully (PID: $pid)"
|
|
80
|
+
echo ""
|
|
81
|
+
echo "Monitor logs with:"
|
|
82
|
+
echo " tail -f $CURRENT_LOG"
|
|
83
|
+
echo ""
|
|
84
|
+
echo "Check status with:"
|
|
85
|
+
echo " $0 status"
|
|
86
|
+
return 0
|
|
87
|
+
else
|
|
88
|
+
echo "❌ Agent failed to start"
|
|
89
|
+
echo "Check logs: $CURRENT_LOG"
|
|
90
|
+
return 1
|
|
91
|
+
fi
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
# Function to stop agent
|
|
95
|
+
stop_agent() {
|
|
96
|
+
if ! check_agent; then
|
|
97
|
+
echo "Agent not running"
|
|
98
|
+
# Clean up any zombie processes just in case
|
|
99
|
+
kill_all_agents
|
|
100
|
+
return 0
|
|
101
|
+
fi
|
|
102
|
+
|
|
103
|
+
local pid=$(cat "$PID_FILE")
|
|
104
|
+
echo "Stopping agent (PID: $pid)..."
|
|
105
|
+
kill -TERM "$pid" 2>/dev/null
|
|
106
|
+
|
|
107
|
+
# Wait for graceful shutdown
|
|
108
|
+
local timeout=10
|
|
109
|
+
while [ $timeout -gt 0 ]; do
|
|
110
|
+
if ! ps -p "$pid" > /dev/null 2>&1; then
|
|
111
|
+
rm -f "$PID_FILE"
|
|
112
|
+
echo "✅ Agent stopped"
|
|
113
|
+
return 0
|
|
114
|
+
fi
|
|
115
|
+
sleep 1
|
|
116
|
+
timeout=$((timeout - 1))
|
|
117
|
+
done
|
|
118
|
+
|
|
119
|
+
# Force kill if still running
|
|
120
|
+
echo "Force killing agent..."
|
|
121
|
+
kill -KILL "$pid" 2>/dev/null
|
|
122
|
+
rm -f "$PID_FILE"
|
|
123
|
+
echo "✅ Agent stopped (forced)"
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
# Function to show status
|
|
127
|
+
show_status() {
|
|
128
|
+
echo "=== Ralph Agent Status ==="
|
|
129
|
+
echo ""
|
|
130
|
+
|
|
131
|
+
# Check main agent
|
|
132
|
+
if check_agent; then
|
|
133
|
+
local pid=$(cat "$PID_FILE")
|
|
134
|
+
echo "✅ Main agent: RUNNING (PID: $pid)"
|
|
135
|
+
|
|
136
|
+
# Get process info
|
|
137
|
+
echo ""
|
|
138
|
+
echo "Process details:"
|
|
139
|
+
ps -p "$pid" -o pid,state,start,time,command | tail -n +2
|
|
140
|
+
|
|
141
|
+
# Get API token info
|
|
142
|
+
if [ -f "$HOME/.ralphblasterrc" ]; then
|
|
143
|
+
echo ""
|
|
144
|
+
echo "API Token: configured in ~/.ralphblasterrc"
|
|
145
|
+
fi
|
|
146
|
+
|
|
147
|
+
# Show recent activity from logs
|
|
148
|
+
echo ""
|
|
149
|
+
echo "Recent activity (last 5 lines):"
|
|
150
|
+
if [ -f "$CURRENT_LOG" ]; then
|
|
151
|
+
tail -5 "$CURRENT_LOG" | sed 's/^/ /'
|
|
152
|
+
else
|
|
153
|
+
echo " (no log file found)"
|
|
154
|
+
fi
|
|
155
|
+
else
|
|
156
|
+
echo "❌ Main agent: NOT RUNNING"
|
|
157
|
+
fi
|
|
158
|
+
|
|
159
|
+
echo ""
|
|
160
|
+
echo "=== All Ralph Agent Processes ==="
|
|
161
|
+
local all_pids=$(pgrep -f "ralphblaster.js")
|
|
162
|
+
|
|
163
|
+
if [ -z "$all_pids" ]; then
|
|
164
|
+
echo "No agent processes found"
|
|
165
|
+
else
|
|
166
|
+
echo "Found processes:"
|
|
167
|
+
for pid in $all_pids; do
|
|
168
|
+
echo ""
|
|
169
|
+
ps -p "$pid" -o pid,state,start,time,command | tail -n +2 | sed 's/^/ /'
|
|
170
|
+
done
|
|
171
|
+
|
|
172
|
+
# Warning if multiple agents
|
|
173
|
+
local count=$(echo "$all_pids" | wc -w)
|
|
174
|
+
if [ "$count" -gt 1 ]; then
|
|
175
|
+
echo ""
|
|
176
|
+
echo "⚠️ WARNING: Multiple agent processes detected!"
|
|
177
|
+
echo "This may cause jobs to be processed by different agents."
|
|
178
|
+
echo "Run '$0 restart' to ensure only one agent is running."
|
|
179
|
+
fi
|
|
180
|
+
fi
|
|
181
|
+
|
|
182
|
+
echo ""
|
|
183
|
+
echo "Logs directory: $LOG_DIR"
|
|
184
|
+
echo "Current log: $CURRENT_LOG"
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
# Function to tail logs
|
|
188
|
+
tail_logs() {
|
|
189
|
+
if [ ! -f "$CURRENT_LOG" ]; then
|
|
190
|
+
echo "No log file found at: $CURRENT_LOG"
|
|
191
|
+
return 1
|
|
192
|
+
fi
|
|
193
|
+
|
|
194
|
+
echo "Tailing agent logs (Ctrl+C to stop)..."
|
|
195
|
+
echo "File: $CURRENT_LOG"
|
|
196
|
+
echo ""
|
|
197
|
+
tail -f "$CURRENT_LOG"
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
# Function to show recent logs
|
|
201
|
+
show_logs() {
|
|
202
|
+
local lines="${1:-50}"
|
|
203
|
+
|
|
204
|
+
if [ ! -f "$CURRENT_LOG" ]; then
|
|
205
|
+
echo "No log file found at: $CURRENT_LOG"
|
|
206
|
+
return 1
|
|
207
|
+
fi
|
|
208
|
+
|
|
209
|
+
echo "Last $lines lines from agent log:"
|
|
210
|
+
echo "File: $CURRENT_LOG"
|
|
211
|
+
echo ""
|
|
212
|
+
tail -n "$lines" "$CURRENT_LOG"
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
# Main command handling
|
|
216
|
+
case "${1:-status}" in
|
|
217
|
+
start)
|
|
218
|
+
start_agent
|
|
219
|
+
;;
|
|
220
|
+
stop)
|
|
221
|
+
stop_agent
|
|
222
|
+
;;
|
|
223
|
+
restart)
|
|
224
|
+
echo "Restarting agent..."
|
|
225
|
+
kill_all_agents # Kill ALL agents, not just the tracked one
|
|
226
|
+
sleep 2
|
|
227
|
+
start_agent
|
|
228
|
+
;;
|
|
229
|
+
status)
|
|
230
|
+
show_status
|
|
231
|
+
;;
|
|
232
|
+
logs)
|
|
233
|
+
tail_logs
|
|
234
|
+
;;
|
|
235
|
+
show-logs)
|
|
236
|
+
show_logs "${2:-50}"
|
|
237
|
+
;;
|
|
238
|
+
kill-all)
|
|
239
|
+
kill_all_agents
|
|
240
|
+
;;
|
|
241
|
+
*)
|
|
242
|
+
echo "Ralph Agent Monitor"
|
|
243
|
+
echo ""
|
|
244
|
+
echo "Usage: $0 [command]"
|
|
245
|
+
echo ""
|
|
246
|
+
echo "Commands:"
|
|
247
|
+
echo " start Start the agent (fails if already running)"
|
|
248
|
+
echo " stop Stop the agent gracefully"
|
|
249
|
+
echo " restart Kill all agents and start fresh"
|
|
250
|
+
echo " status Show agent status and recent activity"
|
|
251
|
+
echo " logs Tail agent logs in real-time"
|
|
252
|
+
echo " show-logs Show recent logs (default: 50 lines)"
|
|
253
|
+
echo " kill-all Kill all agent processes (use when stuck)"
|
|
254
|
+
echo ""
|
|
255
|
+
echo "Examples:"
|
|
256
|
+
echo " $0 start # Start the agent"
|
|
257
|
+
echo " $0 status # Check if agent is running"
|
|
258
|
+
echo " $0 logs # Watch live logs"
|
|
259
|
+
echo " $0 show-logs 100 # Show last 100 log lines"
|
|
260
|
+
echo " $0 restart # Fresh start (kills any zombies)"
|
|
261
|
+
echo ""
|
|
262
|
+
exit 1
|
|
263
|
+
;;
|
|
264
|
+
esac
|
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// Parse command line arguments BEFORE loading modules that use config
|
|
4
|
+
const args = process.argv.slice(2);
|
|
5
|
+
|
|
6
|
+
// Check for --agents flag (multi-agent mode)
|
|
7
|
+
const agentsIndex = args.findIndex(arg => arg.startsWith('--agents='));
|
|
8
|
+
let agentCount = null;
|
|
9
|
+
if (agentsIndex !== -1) {
|
|
10
|
+
agentCount = parseInt(args[agentsIndex].split('=')[1], 10);
|
|
11
|
+
// Get max agents from environment variable (default: 10)
|
|
12
|
+
const maxAgents = parseInt(process.env.RALPHBLASTER_MAX_AGENTS_PER_USER || process.env.RALPH_MAX_AGENTS_PER_USER || '10', 10);
|
|
13
|
+
if (isNaN(agentCount) || agentCount < 1 || agentCount > maxAgents) {
|
|
14
|
+
console.error(`Error: --agents flag requires a number between 1 and ${maxAgents}`);
|
|
15
|
+
process.exit(1);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// Check for --token flag
|
|
20
|
+
const tokenIndex = args.findIndex(arg => arg.startsWith('--token='));
|
|
21
|
+
if (tokenIndex !== -1) {
|
|
22
|
+
const token = args[tokenIndex].split('=')[1];
|
|
23
|
+
if (!token || token.trim() === '') {
|
|
24
|
+
console.error('Error: --token flag requires a value');
|
|
25
|
+
process.exit(1);
|
|
26
|
+
}
|
|
27
|
+
// Set both old and new variable names for backward compatibility
|
|
28
|
+
process.env.RALPHBLASTER_API_TOKEN = token;
|
|
29
|
+
process.env.RALPH_API_TOKEN = token;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// Check for --api-url flag
|
|
33
|
+
const apiUrlIndex = args.findIndex(arg => arg.startsWith('--api-url='));
|
|
34
|
+
if (apiUrlIndex !== -1) {
|
|
35
|
+
const apiUrl = args[apiUrlIndex].split('=')[1];
|
|
36
|
+
if (!apiUrl || apiUrl.trim() === '') {
|
|
37
|
+
console.error('Error: --api-url flag requires a value');
|
|
38
|
+
process.exit(1);
|
|
39
|
+
}
|
|
40
|
+
// Set both old and new variable names for backward compatibility
|
|
41
|
+
process.env.RALPHBLASTER_API_URL = apiUrl;
|
|
42
|
+
process.env.RALPH_API_URL = apiUrl;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Show help
|
|
46
|
+
if (args.includes('--help') || args.includes('-h')) {
|
|
47
|
+
console.log(`
|
|
48
|
+
RalphBlaster Agent - Autonomous coding agent for RalphBlaster
|
|
49
|
+
|
|
50
|
+
Usage:
|
|
51
|
+
ralphblaster [options]
|
|
52
|
+
ralphblaster init [options]
|
|
53
|
+
ralphblaster add-project
|
|
54
|
+
|
|
55
|
+
Commands:
|
|
56
|
+
(default) Start the agent in polling mode
|
|
57
|
+
init Save credentials to ~/.ralphblasterrc
|
|
58
|
+
add-project Register current directory as a RalphBlaster project
|
|
59
|
+
|
|
60
|
+
Options:
|
|
61
|
+
--agents=<count> Run multiple agents concurrently (1-10, default: 1)
|
|
62
|
+
--token=<token> API token for authentication
|
|
63
|
+
--api-url=<url> API base URL (default: https://hq.ralphblaster.com)
|
|
64
|
+
--help, -h Show this help message
|
|
65
|
+
|
|
66
|
+
Getting Started:
|
|
67
|
+
1. Save your credentials:
|
|
68
|
+
ralphblaster init --token=fm6ibAG6vamdjtbG5snuD3F4
|
|
69
|
+
|
|
70
|
+
2. Register your project (run in project directory):
|
|
71
|
+
ralphblaster add-project
|
|
72
|
+
|
|
73
|
+
3. Start the agent:
|
|
74
|
+
ralphblaster
|
|
75
|
+
|
|
76
|
+
Configuration:
|
|
77
|
+
Token is loaded from (in order of priority):
|
|
78
|
+
1. --token flag
|
|
79
|
+
2. RALPHBLASTER_API_TOKEN (or RALPH_API_TOKEN) environment variable
|
|
80
|
+
3. ~/.ralphblasterrc config file
|
|
81
|
+
|
|
82
|
+
Environment Variables:
|
|
83
|
+
RALPHBLASTER_API_TOKEN API token (RALPH_API_TOKEN also supported)
|
|
84
|
+
RALPHBLASTER_API_URL API base URL (RALPH_API_URL also supported)
|
|
85
|
+
RALPHBLASTER_LOG_LEVEL Log level: error, warn, info, debug (default: info)
|
|
86
|
+
RALPHBLASTER_MAX_AGENTS_PER_USER Max concurrent agents (default: 10)
|
|
87
|
+
RALPHBLASTER_ALLOWED_PATHS Colon-separated list of allowed base paths
|
|
88
|
+
(optional security whitelist)
|
|
89
|
+
RALPHBLASTER_AGENT_ID Agent identifier for multi-agent setups
|
|
90
|
+
|
|
91
|
+
Note: RALPH_* variables are supported for backward compatibility but deprecated.
|
|
92
|
+
|
|
93
|
+
Examples:
|
|
94
|
+
# First time setup - save credentials
|
|
95
|
+
ralphblaster init --token=your_token_here --api-url=https://hq.ralphblaster.com
|
|
96
|
+
|
|
97
|
+
# Register project with API
|
|
98
|
+
cd /path/to/your/project
|
|
99
|
+
ralphblaster add-project
|
|
100
|
+
|
|
101
|
+
# Start single agent (uses token from ~/.ralphblasterrc)
|
|
102
|
+
ralphblaster
|
|
103
|
+
|
|
104
|
+
# Run 3 agents concurrently for parallel job processing
|
|
105
|
+
ralphblaster --agents=3
|
|
106
|
+
|
|
107
|
+
# Run with environment variable (if not using ~/.ralphblasterrc)
|
|
108
|
+
RALPHBLASTER_API_TOKEN=your_token_here ralphblaster
|
|
109
|
+
|
|
110
|
+
# Run with custom API URL
|
|
111
|
+
ralphblaster --api-url=http://localhost:3000
|
|
112
|
+
|
|
113
|
+
# Use with npm
|
|
114
|
+
npm start -- --agents=3
|
|
115
|
+
`);
|
|
116
|
+
process.exit(0);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// Check for version
|
|
120
|
+
if (args.includes('--version') || args.includes('-v')) {
|
|
121
|
+
const packageJson = require('../package.json');
|
|
122
|
+
console.log(`ralphblaster v${packageJson.version}`);
|
|
123
|
+
process.exit(0);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// Check for init command
|
|
127
|
+
if (args.includes('init')) {
|
|
128
|
+
const InitCommand = require('../src/commands/init');
|
|
129
|
+
const initCmd = new InitCommand();
|
|
130
|
+
initCmd.run().catch(error => {
|
|
131
|
+
// Error handling is done in InitCommand.handleError
|
|
132
|
+
// Just exit with error code
|
|
133
|
+
});
|
|
134
|
+
return; // Don't start agent polling loop
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// Check for add-project command (alias for init)
|
|
138
|
+
if (args.includes('add-project')) {
|
|
139
|
+
const AddProjectCommand = require('../src/commands/add-project');
|
|
140
|
+
const addProjectCmd = new AddProjectCommand();
|
|
141
|
+
addProjectCmd.run().catch(error => {
|
|
142
|
+
// Error handling is done in AddProjectCommand.handleError
|
|
143
|
+
// Just exit with error code
|
|
144
|
+
});
|
|
145
|
+
return; // Don't start agent polling loop
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// Multi-agent mode: Launch multiple agent processes
|
|
149
|
+
if (agentCount && agentCount > 1) {
|
|
150
|
+
const { spawn } = require('child_process');
|
|
151
|
+
const path = require('path');
|
|
152
|
+
|
|
153
|
+
console.log('');
|
|
154
|
+
console.log('╔════════════════════════════════════════════════════════════╗');
|
|
155
|
+
console.log(`║ RalphBlaster Multi-Agent Manager - Starting ${agentCount} agents ║`);
|
|
156
|
+
console.log('╚════════════════════════════════════════════════════════════╝');
|
|
157
|
+
console.log('');
|
|
158
|
+
|
|
159
|
+
const agents = [];
|
|
160
|
+
const agentProcesses = [];
|
|
161
|
+
|
|
162
|
+
// Cleanup function for graceful shutdown
|
|
163
|
+
const cleanup = () => {
|
|
164
|
+
console.log('\n\nShutting down all agents...');
|
|
165
|
+
agentProcesses.forEach((proc, index) => {
|
|
166
|
+
if (proc && !proc.killed) {
|
|
167
|
+
console.log(` Stopping agent-${index + 1} (PID: ${proc.pid})`);
|
|
168
|
+
proc.kill('SIGTERM');
|
|
169
|
+
}
|
|
170
|
+
});
|
|
171
|
+
setTimeout(() => {
|
|
172
|
+
console.log('All agents stopped');
|
|
173
|
+
process.exit(0);
|
|
174
|
+
}, 500);
|
|
175
|
+
};
|
|
176
|
+
|
|
177
|
+
// Setup signal handlers
|
|
178
|
+
process.on('SIGINT', cleanup);
|
|
179
|
+
process.on('SIGTERM', cleanup);
|
|
180
|
+
|
|
181
|
+
// Launch each agent
|
|
182
|
+
for (let i = 1; i <= agentCount; i++) {
|
|
183
|
+
const agentId = `agent-${i}`;
|
|
184
|
+
|
|
185
|
+
// Spawn agent process with unique ID
|
|
186
|
+
const agentProcess = spawn('node', [path.join(__dirname, 'ralphblaster.js')], {
|
|
187
|
+
env: {
|
|
188
|
+
...process.env,
|
|
189
|
+
RALPHBLASTER_AGENT_ID: agentId,
|
|
190
|
+
RALPH_AGENT_ID: agentId // Set both for backward compatibility
|
|
191
|
+
},
|
|
192
|
+
stdio: 'inherit' // Share stdio with parent for unified logging
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
agentProcesses.push(agentProcess);
|
|
196
|
+
|
|
197
|
+
// Handle agent exit
|
|
198
|
+
agentProcess.on('exit', (code, signal) => {
|
|
199
|
+
if (code !== 0 && code !== null) {
|
|
200
|
+
console.error(`\nAgent ${agentId} exited with code ${code}`);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// If any agent dies unexpectedly, shut down all
|
|
204
|
+
if (signal || (code && code !== 0)) {
|
|
205
|
+
console.error(`\nAgent ${agentId} failed, shutting down all agents...`);
|
|
206
|
+
cleanup();
|
|
207
|
+
}
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
console.log(`✓ Started ${agentId} (PID: ${agentProcess.pid})`);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
console.log('');
|
|
214
|
+
console.log(`All ${agentCount} agents launched. Press Ctrl+C to stop all agents`);
|
|
215
|
+
console.log('');
|
|
216
|
+
|
|
217
|
+
// Keep process alive
|
|
218
|
+
return;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
// Single agent mode (default)
|
|
222
|
+
// Load modules AFTER environment variables are set
|
|
223
|
+
// Wrap in try-catch to handle config errors gracefully
|
|
224
|
+
let RalphAgent, logger;
|
|
225
|
+
try {
|
|
226
|
+
RalphAgent = require('../src/index');
|
|
227
|
+
logger = require('../src/logger');
|
|
228
|
+
} catch (error) {
|
|
229
|
+
// Handle config errors (e.g., missing API token)
|
|
230
|
+
console.error('Error: ' + error.message);
|
|
231
|
+
process.exit(1);
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
// Start the agent
|
|
235
|
+
const agent = new RalphAgent();
|
|
236
|
+
|
|
237
|
+
logger.info('');
|
|
238
|
+
logger.info('╔═══════════════════════════════════════════╗');
|
|
239
|
+
logger.info('║ RalphBlaster Agent Starting... ║');
|
|
240
|
+
logger.info('╚═══════════════════════════════════════════╝');
|
|
241
|
+
logger.info('');
|
|
242
|
+
|
|
243
|
+
agent.start().catch(error => {
|
|
244
|
+
logger.error('Fatal error starting agent: ' + (error?.message || error));
|
|
245
|
+
console.error(error); // Also log full error with stack trace
|
|
246
|
+
process.exit(1);
|
|
247
|
+
});
|
package/package.json
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "ralphblaster-agent",
|
|
3
|
+
"version": "0.1.1",
|
|
4
|
+
"description": "RalphBlaster agent that polls for and executes coding jobs via Claude CLI",
|
|
5
|
+
"main": "src/index.js",
|
|
6
|
+
"bin": {
|
|
7
|
+
"ralphblaster": "bin/ralphblaster.js"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"bin/",
|
|
11
|
+
"src/",
|
|
12
|
+
"postinstall-colored.js",
|
|
13
|
+
"LICENSE",
|
|
14
|
+
"README.md"
|
|
15
|
+
],
|
|
16
|
+
"scripts": {
|
|
17
|
+
"start": "node bin/ralphblaster.js",
|
|
18
|
+
"start:multi": "node bin/ralphblaster.js --agents=3",
|
|
19
|
+
"start:multi:5": "node bin/ralphblaster.js --agents=5",
|
|
20
|
+
"test": "jest",
|
|
21
|
+
"test:watch": "jest --watch",
|
|
22
|
+
"test:coverage": "jest --coverage",
|
|
23
|
+
"postinstall": "node postinstall-colored.js"
|
|
24
|
+
},
|
|
25
|
+
"keywords": [
|
|
26
|
+
"ralph",
|
|
27
|
+
"agent",
|
|
28
|
+
"claude",
|
|
29
|
+
"automation"
|
|
30
|
+
],
|
|
31
|
+
"author": "Wildfront LLC",
|
|
32
|
+
"license": "MIT",
|
|
33
|
+
"repository": {
|
|
34
|
+
"type": "git",
|
|
35
|
+
"url": "git+https://github.com/Wildfront/ralphblaster-agent.git"
|
|
36
|
+
},
|
|
37
|
+
"homepage": "https://github.com/Wildfront/ralphblaster-agent#readme",
|
|
38
|
+
"bugs": {
|
|
39
|
+
"url": "https://github.com/Wildfront/ralphblaster-agent/issues"
|
|
40
|
+
},
|
|
41
|
+
"dependencies": {
|
|
42
|
+
"axios": "^1.6.0",
|
|
43
|
+
"dotenv": "^16.3.1",
|
|
44
|
+
"secure-json-parse": "^4.1.0"
|
|
45
|
+
},
|
|
46
|
+
"devDependencies": {
|
|
47
|
+
"@types/jest": "^29.5.14",
|
|
48
|
+
"jest": "^29.7.0"
|
|
49
|
+
},
|
|
50
|
+
"jest": {
|
|
51
|
+
"testEnvironment": "node",
|
|
52
|
+
"coverageDirectory": "coverage",
|
|
53
|
+
"collectCoverageFrom": [
|
|
54
|
+
"src/**/*.js",
|
|
55
|
+
"!src/logger.js"
|
|
56
|
+
],
|
|
57
|
+
"testMatch": [
|
|
58
|
+
"**/test/**/*.test.js"
|
|
59
|
+
]
|
|
60
|
+
},
|
|
61
|
+
"engines": {
|
|
62
|
+
"node": ">=18.0.0"
|
|
63
|
+
}
|
|
64
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
const os = require('os');
|
|
6
|
+
|
|
7
|
+
// ANSI color codes
|
|
8
|
+
const colors = {
|
|
9
|
+
reset: '\x1b[0m',
|
|
10
|
+
bright: '\x1b[1m',
|
|
11
|
+
dim: '\x1b[2m',
|
|
12
|
+
gray: '\x1b[90m',
|
|
13
|
+
cyan: '\x1b[36m',
|
|
14
|
+
green: '\x1b[32m',
|
|
15
|
+
yellow: '\x1b[33m',
|
|
16
|
+
orange: '\x1b[38;5;208m',
|
|
17
|
+
red: '\x1b[31m',
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
const ralph = `
|
|
21
|
+
${colors.gray} /\\
|
|
22
|
+
/ \\
|
|
23
|
+
/ \\
|
|
24
|
+
| |
|
|
25
|
+
| ${colors.bright}${colors.yellow}${colors.reset}${colors.gray}${colors.bright}${colors.yellow}.${colors.reset}${colors.gray} |
|
|
26
|
+
| ${colors.yellow}(${colors.bright}${colors.yellow}o${colors.reset}${colors.yellow})${colors.reset}${colors.gray} | ${colors.bright}${colors.yellow}Ralph Agent${colors.reset}
|
|
27
|
+
| ${colors.yellow}(${colors.bright}${colors.yellow}o${colors.reset}${colors.yellow})${colors.reset}${colors.gray} | ${colors.dim}v1.3.4${colors.reset}
|
|
28
|
+
| ${colors.yellow}~${colors.reset}${colors.gray} |
|
|
29
|
+
| ${colors.red}\\___/${colors.reset}${colors.gray} |
|
|
30
|
+
| |
|
|
31
|
+
| |
|
|
32
|
+
| |
|
|
33
|
+
/| |\\
|
|
34
|
+
/ | | \\
|
|
35
|
+
/ | | \\
|
|
36
|
+
/__/| |\\__\\
|
|
37
|
+
${colors.orange}/|${colors.reset}${colors.gray} ${colors.orange}|\\${colors.reset}
|
|
38
|
+
${colors.orange}/ |${colors.reset}${colors.gray} ${colors.orange}| \\${colors.reset}
|
|
39
|
+
${colors.bright}${colors.yellow}/ ${colors.reset}${colors.orange}|${colors.reset}${colors.gray} ${colors.orange}| ${colors.bright}${colors.yellow}\\${colors.reset}
|
|
40
|
+
${colors.bright}${colors.yellow}' ${colors.reset}${colors.orange}|${colors.reset}${colors.gray} ${colors.orange}| ${colors.bright}${colors.yellow}'${colors.reset}
|
|
41
|
+
${colors.orange}|${colors.reset}${colors.gray} ${colors.orange}|${colors.reset}
|
|
42
|
+
`;
|
|
43
|
+
|
|
44
|
+
// No plugin installation needed - skill is bundled with the agent
|
|
45
|
+
|
|
46
|
+
const message = `
|
|
47
|
+
${ralph}
|
|
48
|
+
|
|
49
|
+
${colors.bright}${colors.green}Installed successfully!${colors.reset}
|
|
50
|
+
|
|
51
|
+
${colors.green}Getting Started:${colors.reset}
|
|
52
|
+
|
|
53
|
+
${colors.dim}1.${colors.reset} Make sure Claude CLI is installed:
|
|
54
|
+
${colors.yellow}claude --version${colors.reset}
|
|
55
|
+
|
|
56
|
+
${colors.dim}2.${colors.reset} Get your API token from Ralph (requires 'ralph_agent' permission)
|
|
57
|
+
|
|
58
|
+
${colors.dim}3.${colors.reset} Start the agent:
|
|
59
|
+
${colors.yellow}ralphblaster --token=your_api_token_here${colors.reset}
|
|
60
|
+
|
|
61
|
+
${colors.green}Documentation:${colors.reset}
|
|
62
|
+
${colors.cyan}https://github.com/Wildfront/ralphblaster-agent#readme${colors.reset}
|
|
63
|
+
|
|
64
|
+
`;
|
|
65
|
+
|
|
66
|
+
console.log(message);
|